第16讲:设计原则与设计模式的关系——原则是道,模式是术

这一讲,我想跟你聊聊一个很多人问过我的问题:设计原则和设计模式,到底什么关系?

我刚开始学设计模式那会儿,也犯过傻。背了二十多个模式,觉得挺牛。结果一到项目里,发现根本不知道用哪个。后来我才明白——光背模式没用,你得先懂原则

打个比方吧。
原则是「道」,模式是「术」。
道是根本规律,术是具体招式。
你光练招式,不懂心法,那就是花架子。

核心观点:设计原则是设计模式的底层逻辑。每一个设计模式,都可以从某条或多条设计原则推导出来。反过来,如果你真正理解了原则,你甚至可以自己「发明」模式。

16.1 原则与模式:一个是根,一个是果

我们先看一张图,把关系理清楚。

设计原则与设计模式的关系 道:设计原则(底层规律) 单一职责 · 开闭原则 · 里氏替换 · 接口隔离 · 依赖倒置 · 最少知识 推导 · 指导 术:设计模式(具体招式) 工厂模式 · 策略模式 · 观察者模式 · 装饰器模式 · 适配器模式 · 模板方法 实现 · 落地 实际项目:可维护、可扩展、可复用的代码

你看,从上到下,是「道 → 术 → 用」的递进关系。
原则是抽象的,模式是具体的。模式是原则在特定场景下的「标准答案」。

16.2 从原则推导模式:一个例子就够了

我拿一个最常见的例子来说——策略模式

假设你有一个订单系统。不同会员等级,折扣算法不一样。

新手可能会这么写:

class Order {
    double calculateDiscount(string level) {
        if (level == "普通") return price * 0.0;
        else if (level == "银卡") return price * 0.1;
        else if (level == "金卡") return price * 0.2;
        // 再加一个等级?又得改这里
    }
};

这代码有什么问题?
违反了开闭原则——对修改不关闭。每次加新等级,都得改这个函数。

好,那我们用原则来推导一下。

推导过程:

  1. 开闭原则告诉我们:对扩展开放,对修改关闭。所以不能改现有代码。
  2. 单一职责原则告诉我们:每个类只做一件事。折扣计算不应该和订单耦合在一起。
  3. 依赖倒置原则告诉我们:要依赖抽象,不要依赖具体实现。

三条原则一叠加,你自然就会想到:把折扣算法抽出来,做成一个接口,每个算法一个类。这不就是策略模式吗?

你看,我没背模式,我是从原则推导出来的。

// 策略接口
class DiscountStrategy {
public:
    virtual double apply(double price) = 0;
};

// 具体策略
class NormalDiscount : public DiscountStrategy {
    double apply(double price) override { return price; }
};

class SilverDiscount : public DiscountStrategy {
    double apply(double price) override { return price * 0.9; }
};

// 订单类不再关心具体算法
class Order {
    DiscountStrategy* strategy;
public:
    void setStrategy(DiscountStrategy* s) { strategy = s; }
    double calculate() { return strategy->apply(price); }
};

嗯,这才是面向对象该有的样子。

16.3 常见模式与原则的对应关系

我整理了一张表,方便你对照着看。

设计模式 核心遵循的原则 一句话解释
策略模式 开闭原则、依赖倒置 把算法抽出来,各自独立
工厂模式 依赖倒置、单一职责 把创建对象的责任单独拎出来
观察者模式 最少知识原则、开闭原则 发布者和订阅者互不依赖
装饰器模式 开闭原则、单一职责 不修改类,动态加功能
适配器模式 接口隔离原则、开闭原则 让不兼容的接口能一起工作
模板方法模式 里氏替换原则、开闭原则 固定骨架,子类填充细节

注意:一个模式往往对应多条原则。反过来,一条原则也可以推导出多个模式。这不是一一对应的关系,而是多对多的网状关系。

16.4 我踩过的坑:模式滥用

说实话,我早期也犯过「模式崇拜」的毛病。

有一次,一个简单的日志模块,我硬是套了工厂模式+单例模式+观察者模式。代码写了三百行,团队里没人看得懂。后来被架构师叫去谈话,他说了一句话我记到现在:「你是在写模式,不是在写代码。」

从那以后,我养成了一个习惯:
先问自己——这里违反了哪条原则?
如果没违反,就别硬上模式。

我的建议:

  • 遇到设计问题,先想原则,再想模式
  • 能用简单组合解决的,别用模式
  • 模式是工具,不是目标

16.5 从原则推导模式的三步法

最后,我分享一个自己总结的方法。遇到设计问题时,按这三步走:

  1. 识别变化点——哪部分代码未来可能会变?
  2. 套用原则——哪条原则能解决这个变化?比如「开闭原则」要求封装变化。
  3. 匹配模式——这个封装方式,是不是正好对应某个模式?

举个例子:
变化点是「折扣算法经常新增」→ 开闭原则要求「对扩展开放」→ 策略模式正好封装算法族。

你看,三步走完,模式自然就出来了。

说白了,原则是心法,模式是招式。
心法通了,招式可以自己创。
心法不通,背再多招式也是花架子。

我个人更建议你把精力花在理解原则上。模式可以查,原则必须内化。


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