第1章:设计原则与架构风格——分层架构、六边形架构、整洁架构中的设计原则

说实话,很多工程师干了三五年,代码写得挺溜,但一谈到架构就懵了。

我当年也是这样。直到有一次接手一个遗留系统,改一个功能要动七八个模块,改完还总出bug。那时候我才意识到——架构不是花架子,它决定了你的代码能活多久

这一章,我们来聊聊架构风格和设计原则的关系。说白了,就是看看那些经典的架构模式里,到底藏着哪些设计原则。

1. 分层架构:最朴素的隔离之道

分层架构,大家都不陌生。三层架构、四层架构,本质都是关注点分离

我个人习惯把分层架构理解为「各司其职」。表现层只管展示,业务层只管逻辑,数据层只管存取。谁也别越界。

核心设计原则:

  • 单一职责原则:每一层只做一件事
  • 依赖倒置原则:上层依赖抽象,不依赖下层具体实现
  • 接口隔离原则:层与层之间通过窄接口通信

我在项目中遇到过一个问题:业务层直接调用了数据库层的具体类。后来数据库换了,业务层代码改得面目全非。嗯,这就是典型的违反依赖倒置。

我的建议:层与层之间只依赖接口。哪怕只有一种实现,也要先定义接口。这不是过度设计,这是给自己留后路。

// 好的做法:依赖抽象
class IUserRepository {
public:
    virtual User findById(int id) = 0;
    virtual ~IUserRepository() = default;
};

class UserService {
private:
    IUserRepository& repo;  // 依赖接口
public:
    UserService(IUserRepository& r) : repo(r) {}
    User getUser(int id) { return repo.findById(id); }
};

2. 六边形架构:把核心逻辑保护起来

六边形架构,也叫端口适配器架构。我第一次看到这个图的时候,觉得挺玄乎。后来用上了,才发现它解决了一个大问题——业务逻辑不被外部污染

你想想看,传统的分层架构里,业务层直接依赖数据库、消息队列、外部API。一旦这些外部组件变了,业务逻辑也得跟着改。这合理吗?不合理。

六边形架构的核心思想是:业务逻辑在最内层,对外只暴露端口(接口)。外部的一切都是适配器

核心设计原则:

  • 依赖倒置原则:外部依赖内部,内部不依赖外部
  • 开闭原则:增加新的外部适配器,不需要改内部逻辑
  • 接口隔离原则:每个端口只定义调用方需要的方法

我曾经在一个支付系统里用过六边形架构。核心逻辑处理订单状态机,外部对接微信支付、支付宝、银联。后来新增了一个跨境支付渠道,只需要写一个新的适配器,核心代码一行没动。这种感觉,很爽。

// 端口定义
class IPaymentPort {
public:
    virtual bool pay(Order& order) = 0;
    virtual bool refund(Order& order) = 0;
};

// 核心业务逻辑
class OrderService {
private:
    IPaymentPort& payment;
public:
    OrderService(IPaymentPort& p) : payment(p) {}
    void processOrder(Order& o) {
        // 业务逻辑...
        payment.pay(o);
    }
};

// 适配器:微信支付
class WechatPayAdapter : public IPaymentPort {
    bool pay(Order& o) override { /* 微信支付实现 */ }
    bool refund(Order& o) override { /* 微信退款实现 */ }
};

注意:六边形架构不是银弹。如果你的业务逻辑本身就很简单,强行套用反而增加复杂度。我见过有人为了用六边形架构,写了五层抽象,最后自己都绕晕了。

3. 整洁架构:原则的集大成者

整洁架构是Robert C. Martin提出的。说白了,它把六边形架构的思想又往前推了一步——不仅外部要隔离,内部也要分层

整洁架构把系统分成四层:

层级 内容 依赖方向
企业业务规则 实体、核心业务对象 最内层,无依赖
应用业务规则 用例、应用服务 依赖内层
接口适配器 控制器、网关、展示器 依赖内层
框架与驱动 数据库、Web框架、UI 最外层,依赖内层

依赖规则只有一条:外层可以依赖内层,内层绝不依赖外层

核心设计原则:

  • 依赖倒置原则:所有依赖指向抽象
  • 开闭原则:新增功能通过扩展实现,不修改已有代码
  • 里氏替换原则:内层的接口可以被任意外层实现替换
  • 接口隔离原则:每层只暴露必要的接口

我记得有一次重构一个电商系统,原来的代码把SQL查询写在控制器里。按照整洁架构的思路,我们把查询逻辑下沉到用例层,控制器只做参数解析和结果返回。后来换了ORM框架,只改了最外层的适配器,核心逻辑完全不受影响。

// 内层:实体
class Order {
public:
    double totalAmount() const;
    void addItem(Product p, int qty);
};

// 内层:用例
class CheckoutUseCase {
public:
    void execute(Order& order, IPaymentPort& payment) {
        double total = order.totalAmount();
        payment.charge(total);
    }
};

// 外层:控制器
class CheckoutController {
public:
    void handleRequest(Request& req) {
        Order order = buildOrder(req);
        CheckoutUseCase useCase;
        useCase.execute(order, paymentAdapter);
    }
};

4. 三种架构的对比与选择

这三种架构不是互斥的,而是层层递进的关系。

架构风格 核心思想 适用场景 复杂度
分层架构 关注点分离 中小型项目,团队熟悉
六边形架构 核心与外部隔离 需要对接多种外部系统
整洁架构 严格依赖规则 大型复杂系统,长期维护

我个人建议:不要为了用架构而用架构。项目初期,分层架构就够了。随着系统变复杂,再逐步引入六边形或整洁架构。我见过太多人一开始就上整洁架构,结果项目还没上线,架构先把自己累死了。

避坑指南:我曾经在一个小工具项目里强行套用整洁架构,写了十几个接口和适配器。最后发现,核心逻辑只有200行代码,接口定义却写了500行。嗯,这就是过度设计。记住:架构是为业务服务的,不是反过来。

5. 知识体系总览

下面这张图,我把三种架构风格和它们对应的设计原则梳理了一下。你可以把它当作一个快速参考。

架构风格与设计原则关系图 分层架构 核心:关注点分离 原则: • 单一职责原则 • 依赖倒置原则 • 接口隔离原则 适用:中小型项目 复杂度:低 六边形架构 核心:核心与外部隔离 原则: • 依赖倒置原则 • 开闭原则 • 接口隔离原则 适用:多外部系统对接 复杂度:中 整洁架构 核心:严格依赖规则 原则: • 依赖倒置原则 • 开闭原则 • 里氏替换原则 • 接口隔离原则 适用:大型复杂系统 复杂度:高 共同核心:依赖倒置 + 接口隔离 + 关注点分离

看到这张图,你应该能感受到:三种架构风格虽然形式不同,但背后的设计原则是相通的。依赖倒置、接口隔离、关注点分离,这些原则就像建筑的钢筋,不管外面怎么装修,骨架始终不变。

好了,这一章就聊到这里。记住:架构不是目的,是手段。选对架构,你的代码能活十年;选错了,半年就想重写。


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