架构原则与设计模式实战

说实话,做了十几年软件架构,我越来越觉得——设计模式和架构原则这东西,不是背出来的,是踩坑踩出来的。今天咱们聊三个实战场景:SOLID在微服务里怎么落地、DDD里的模式怎么用、以及Spring框架里那些你天天用却没意识到的设计模式。

一、SOLID原则在微服务架构中的应用

先说说SOLID。很多人觉得这是面向对象那套,微服务用不上。我一开始也这么想,直到有一次重构一个订单系统……嗯,那叫一个痛苦。

1. 单一职责原则(SRP)

微服务本身就是SRP的体现。每个服务只做一件事。但实际项目中,我见过太多「订单服务」既管订单又管支付还管物流。你想想看,这跟没拆分有啥区别?

我的经验:一个微服务如果超过3个不相关的职责,就该拆了。别犹豫。

2. 开闭原则(OCP)

微服务里怎么实现开闭?用事件驱动。我习惯的做法是:核心服务发布事件,扩展服务订阅事件。这样加新功能不用改老代码。

// 订单服务只发布事件
public class OrderService {
    private final EventPublisher publisher;
    
    public void createOrder(Order order) {
        // 核心逻辑
        publisher.publish(new OrderCreatedEvent(order));
    }
}

// 新加的积分服务,只订阅事件
@Component
public class PointsService {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        // 加积分,完全不影响订单服务
    }
}

3. 里氏替换原则(LSP)

微服务间的接口契约要严格。我曾经遇到过一个坑:支付服务返回的「成功」状态,有的版本是字符串"success",有的版本是布尔值true。下游服务全得跟着改。这就是违反LSP的典型。

避坑指南:服务间的DTO和API契约,一定要用版本管理。我吃过亏,现在每个接口都带版本号。

4. 接口隔离原则(ISP)

别搞大而全的「万能服务接口」。我见过一个用户服务,一个接口返回用户所有信息——订单、积分、地址、偏好……调用方其实只需要用户名。这既浪费带宽,又增加耦合。

5. 依赖反转原则(DIP)

微服务里,高层模块(业务逻辑)不应该依赖低层模块(数据库、消息队列)。用依赖注入解决。Spring Cloud里,我习惯把Feign客户端定义在独立的API模块中。

二、DDD中的模式应用

DDD(领域驱动设计)我真正用起来是在一个电商项目里。说实话,刚开始觉得太复杂,后来发现——不是DDD复杂,是我没理解它的精髓。

1. 实体与值对象

实体有唯一标识,值对象没有。举个例子:订单是实体(有订单号),地址是值对象(两个地址如果内容一样就相等)。

// 实体
public class Order {
    private OrderId id;  // 唯一标识
    private OrderStatus status;
    // 状态可以变,但id不变
}

// 值对象
public class Address {
    private final String province;
    private final String city;
    private final String detail;
    // 不可变,比较的是内容
}

2. 聚合与聚合根

聚合是一组相关对象的集合。聚合根是外部访问的唯一入口。我习惯把订单作为聚合根,订单项、支付记录都在聚合内部。

我的习惯:聚合内的数据一致性由聚合根保证。外部只能通过聚合根操作内部对象。

3. 领域事件

领域事件是DDD里我最喜欢的模式。它让领域逻辑保持纯净,同时又能解耦。比如订单完成时发布OrderCompletedEvent,物流服务、通知服务各自处理。

4. 仓库模式

仓库封装了数据访问逻辑。领域层只依赖仓库接口,不关心具体实现。我在项目中用Spring Data JPA实现仓库,切换数据库时只需要改实现类。

三、设计模式在Spring框架中的体现

Spring框架本身就是设计模式的集大成者。我经常跟团队说:你学Spring,其实就是在学设计模式。

设计模式 Spring中的体现 我的使用场景
工厂模式 BeanFactory、ApplicationContext 所有对象的创建都交给Spring管理
单例模式 默认的Bean作用域 无状态的服务类,比如Service、Repository
代理模式 AOP、@Transactional 日志、事务、权限控制
模板方法模式 JdbcTemplate、RestTemplate 数据库操作、HTTP调用
观察者模式 ApplicationListener、@EventListener 事件驱动、异步通知
策略模式 Resource接口、各种Converter 多种支付方式、多种数据源

1. 工厂模式——BeanFactory

说白了,Spring就是个超级工厂。你告诉它要什么类型的对象,它给你创建好,还帮你注入依赖。我刚开始用Spring时觉得这很神奇,后来理解了工厂模式,就明白了——这不就是工厂模式的高级版嘛。

2. 代理模式——AOP

AOP是Spring最强大的功能之一。我经常用它做日志记录和性能监控。比如给所有Service方法加个切面,记录执行时间。

@Aspect
@Component
public class PerformanceAspect {
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object measureTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long elapsed = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " 耗时: " + elapsed + "ms");
        return result;
    }
}

3. 模板方法模式——JdbcTemplate

JdbcTemplate把「获取连接-执行SQL-处理结果-关闭连接」这个固定流程封装好了。你只需要写SQL和结果处理逻辑。这就是模板方法模式的典型应用。

4. 观察者模式——事件机制

Spring的事件机制我用的很多。比如用户注册后,发送欢迎邮件、初始化积分、记录日志。这些都可以通过事件异步处理,主流程不受影响。

我的建议:把Spring框架当成设计模式的活教材。每学一个Spring特性,就去想想它用了什么设计模式。这样学得深,记得牢。

知识体系总览

下面这张图是我梳理的本章知识结构。你可以看到,SOLID、DDD、Spring设计模式这三块,其实都指向同一个目标——写出高内聚、低耦合的代码。

架构原则与设计模式实战知识体系 SOLID原则 DDD模式 Spring设计模式 SRP · OCP · LSP · ISP · DIP 微服务中的单一职责 事件驱动实现开闭原则 接口契约与版本管理 实体 · 值对象 · 聚合 聚合根与一致性边界 领域事件驱动 仓库模式封装数据访问 工厂模式 · 单例模式 代理模式 · AOP实现 模板方法 · JdbcTemplate 观察者模式 · 事件机制 目标:高内聚 · 低耦合 · 可维护 · 可扩展

最后说一句:设计模式和架构原则不是银弹。我见过太多人为了用模式而用模式,把简单问题搞复杂了。记住一句话——合适的才是最好的。你在项目中遇到的具体问题,往往比任何理论都更能教会你该用哪种模式。


公众号:蓝海资料掘金营,微信deep3321