浅谈常用的架构模式

开发 架构
架构模式有很多种,本文只讨论工作中使用较多的几种:分层架构,Pipeline架构,事件驱动架构。

架构模式是软件架构中在给定环境下常遇到问题的通用的、可重用的解决方案。类似于软件设计模式但覆盖范围更广,致力于软件工程中不同问题,如计算机硬件性能限制、高可用性、业务风险极小化。一些架构模式在软件框架被实现。- 维基百科

说明

架构模式有很多种,本文只讨论工作中使用较多的几种:

  • 分层架构
  • Pipeline架构
  • 事件驱动架构

分层架构

 

浅谈常用的架构模式
分层架构模式

分层架构模式工作中用的比较多,常见的有MVC等,通过分层将职责划分到某一层上,层次清晰,架构明了。

我们以MVC来举例说明:controller -> service -> dao

 

@RestController 
@RequestMapping("/order"
public class OrderController { 
    @Autowired 
    private OrderService orderService; 
 
    /** 
     * 新增订单 
     * @param order 
     * @return 
     */ 
    @PostMapping("/add"
    public Response addOrder(Order order) { 
        orderService.add(order); 
        return Response.success(); 
    } 

 
public interface OrderService { 
    /** 
     *  添加订单 
     * @param order 
     * @return 
     */ 
    boolean add(Order order); 

 
public interface OrderRepository { 
 
    int save(Order order); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

按照依赖方向,上层依次依赖下层,每一层处理不同到逻辑。

之前到文章有讨论过通过依赖反转来改变依赖关系,从而更少到减少耦合。

Pipeline架构

 

浅谈常用的架构模式
Pipeline架构模式

Pipeline架构也称为管道或流水线架构,处理流程成线性,各个环节有相应到组件处理,从前到后顺序执行。

概念说明:

  • source: 数据源,通常使用流数据为源,比如:KafkaSource;
  • channel:信道或管道,用于处理或转换数据,比如:JsonChannel;
  • Sink:数据落地,通常用于数据存储或转发,比如:DbSink, KafkaSink;
  • Component: 组件,用于执行逻辑的最小单元,source,channel,sink都是一个Component;
  • Pipeline: 管道或流水线,一个Pipeline由上面的组件组成,不同的业务可以组装成不同的Pipeline;
  • 代码实现:数字数据源 -> 累加 -> 转成字符串 -> 落地

 

/** 
 *  组件 
 */ 
public interface Component<T> { 
    /** 
     *  组件名称 
     * @return 
     */ 
    String getName(); 
 
    /** 
     *  获取下游组件 
     * @return 
     */ 
    Collection<Component> getDownStrems(); 
 
    /** 
     *  组件执行 
     */ 
    void execute(T o); 

 
public abstract class AbstractComponent<T, R> implements Component<T>{ 
 
    @Override 
    public void execute(T o) { 
        // 当前组件执行 
        R r = doExecute(o); 
        System.out.println(getName() + " receive " + o + " return " + r); 
        // 获取下游组件,并执行 
        Collection<Component> downStreams = getDownStrems(); 
        if (!CollectionUtils.isEmpty(downStreams)) { 
            downStreams.forEach(c -> c.execute(r)); 
        } 
    } 
 
    protected abstract R doExecute(T o); 

 
/** 
 *  数据来源 
 */ 
public abstract class Source<T, R> extends AbstractComponent<T, R>{ 
 

 
/** 
 *  管道/信道 
 * @param <T> 
 */ 
public abstract class Channel<T, R> extends AbstractComponent<T, R> { 
 

 
/** 
 *  数据落地 
 * @param <T> 
 */ 
public abstract class Sink<T, R> extends AbstractComponent<T, R> { 
 

 
public class IntegerSource extends Source<Integer,  Integer>{ 
 
    @Override 
    protected Integer doExecute(Integer o) { 
        return o; 
    } 
 
    @Override 
    public String getName() { 
        return "Integer-Source"
    } 
 
    @Override 
    public Collection<Component> getDownStrems() { 
        return Collections.singletonList(new IncrChannel()); 
    } 
 

 
public class IncrChannel extends Channel<IntegerInteger> { 
 
    @Override 
    protected Integer doExecute(Integer o) { 
        return o + 1; 
    } 
 
    @Override 
    public String getName() { 
        return "Incr-Channel"
    } 
 
    @Override 
    public Collection<Component> getDownStrems() { 
        return Collections.singletonList(new StringChannel()); 
    } 
 

 
public class StringChannel extends Channel<Integer, String> { 
 
    @Override 
    protected String doExecute(Integer o) { 
        return "str" + o; 
    } 
 
    @Override 
    public String getName() { 
        return "String-Channel"
    } 
 
    @Override 
    public Collection<Component> getDownStrems() { 
        return Collections.singletonList(new StringSink()); 
    } 
 

 
public class StringSink extends Sink<String, Void>{ 
 
    @Override 
    protected Void doExecute(String o) { 
        return null
    } 
 
    @Override 
    public String getName() { 
        return "String-Sink"
    } 
 
    @Override 
    public Collection<Component> getDownStrems() { 
        return null
    } 
 

 
/** 
 *  流水线 
 */ 
public class Pipeline { 
    /** 
     *  数据源 
     */ 
    private Source source; 
 
    public Pipeline(Source source) { 
        this.source = source; 
    } 
 
    /** 
     *  启动 
     */ 
    public void start() { 
        source.execute(1); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.

测试:

 

public class PipelineTest { 
 
    @Test 
    public void test() { 
        Pipeline pipeline = new Pipeline(new IntegerSource()); 
        pipeline.start(); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

执行结果:

 

Integer-Source receive 1 return 1  
Incr-Channel receive 1 return 2  
String-Channel receive 2 return str2  
String-Sink receive str2 return null 
  • 1.
  • 2.
  • 3.
  • 4.

事件驱动架构

 

浅谈常用的架构模式
事件驱动模式

事件驱动是以某个具体事件为触发条件,从而贯穿这个处理流程。通常事件驱动属于发布订阅模式或观察者模式, 用于异步处理,解耦业务逻辑。具体实现有进程内的和分布式的方式,比如:EventBus, MQ等等。

代码举例:

 

public class OrderEventListener implements Listener<OrderEvent> { 
 
    @Override 
    public void onEvent(OrderEvent event) { 
        System.out.println("receive event: " + event); 
    } 

 
public class EventBus { 
 
    private final static List<Listener> listeners = new ArrayList<>(); 
 
    /** 
     *  注册监听器 
     * @param listener 
     */ 
    public static void registerListener(Listener listener) { 
        listeners.add(listener); 
    } 
 
    /** 
     *  发布事件 
     * @param event 
     */ 
    public void publishEvent(Event event) { 
        // 收到并处理事件 
        listeners.forEach(l -> { 
            l.onEvent(event); 
        }); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

测试:

 

public class EventBusTest { 
 
    @Test 
    public void publish() { 
        OrderEvent event = new OrderEvent("order_2", OrderState.PENDING_PAYMENT); 
        EventBus.registerListener(new OrderEventListener()); 
        EventBus eventBus = new EventBus(); 
        eventBus.publishEvent(event); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

Spring中也有事件发布和监听(深入浅出Spring/SpringBoot 事件监听机制):

 

@Component 
public class OrderEventListener  { 
 
    @Async 
    @EventListener(OrderEvent.class) 
    public void onEvent(OrderEvent event) { 
        System.out.println("receive event: " + event); 
    } 

 
public class EventTest { 
    @Autowired 
    private ApplicationContext context; 
 
    @Test 
    public void publishEvent() { 
        OrderEvent event = new OrderEvent("order_1", OrderState.PENDING_PAYMENT); 
        context.publishEvent(event); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

总结

以上通过代码实例简单说明了工作中常用到的架构模式,但是模式不是固定的,工作中需结合实际情况按需使用即可。

责任编辑:未丽燕 来源: 今日头条
相关推荐

2021-07-23 11:35:49

架构运维技术

2023-06-16 13:34:00

软件架构模式

2012-01-13 10:45:56

企业应用架构

2024-02-05 08:11:30

架构模式单体

2020-02-26 09:00:00

Chatbot架构模型聊天机器人

2018-05-24 11:38:17

2023-07-27 06:51:46

Android架构模式

2022-06-14 11:01:37

架构模式开发

2022-09-21 10:05:09

架构模式

2020-06-28 10:15:39

架构模式软件

2017-09-14 09:30:38

软件架构模式

2020-10-08 18:20:54

前端后端架构

2019-12-31 10:08:35

架构模式软件

2021-12-15 10:05:25

软件开发 技术

2021-07-02 06:54:45

软件架构模式

2022-04-02 23:32:42

数据网格架构

2024-11-08 09:41:02

2020-02-24 21:23:41

跨平台想法尝试

2024-01-05 13:25:00

架构架构模式开发

2024-09-18 09:04:33

架构模式查询
点赞
收藏

51CTO技术栈公众号