设计模式如何应用?

访客 全栈框架 1

本文目录导读:

  1. 第一步:识别症状(判断是否需要用模式)
  2. 第二步:匹配场景(常用模式的应用案例)
  3. 第三步:落地原则(避免滥用)
  4. 一个决策流程

这是一个很核心的问题,设计模式不是“银弹”,也不是一开始就要生搬硬套的。

简单说:设计模式是特定场景下,解决重复性设计问题的成熟模板。 应用的核心不是“我要用哪个模式”,而是“我遇到了什么问题,哪个模式最能优雅地解决它”。

下面我从识别问题->选择模式->实践落地 三个步骤,结合具体代码案例来说明。

第一步:识别症状(判断是否需要用模式)

不要为了用模式而用模式,当你写代码时出现以下 “坏味道” ,就是考虑模式的时候:

  1. 代码臃肿,难以扩展:一个 if-elseswitch 有十几层,新增一个类型就要改所有地方。
  2. 对象创建复杂:需要创建一组相关或依赖的对象,且创建逻辑经常变。
  3. 对象间耦合过紧:一个对象的改动,导致N个对象跟着一起改(牵一发动全身)。
  4. 需要兼容多个接口或旧系统:接口不匹配,又不能改对方代码。

第二步:匹配场景(常用模式的应用案例)

这里选几个最高频、最实用的模式,结合真实场景说明。

策略模式(Strategy Pattern)—— 消灭大量 if-else

  • 场景:电商系统计算订单价格,普通会员打9折,VIP打8折,钻石打7折,且后期会不断增加会员等级。
  • 坏味道if (user.isVip) {...} else if (user.isDiamond)...
  • 模式应用
// 1. 定义策略接口
public interface DiscountStrategy {
    BigDecimal apply(BigDecimal price);
}
// 2. 实现具体策略
public class NormalDiscount implements DiscountStrategy {
    public BigDecimal apply(BigDecimal price) { return price.multiply(new BigDecimal("0.9")); }
}
public class VipDiscount implements DiscountStrategy {
    public BigDecimal apply(BigDecimal price) { return price.multiply(new BigDecimal("0.8")); }
}
// 3. 上下文类(使用策略)
public class OrderService {
    private DiscountStrategy strategy;
    public OrderService(DiscountStrategy strategy) { // 构造器或setter注入
        this.strategy = strategy;
    }
    public BigDecimal checkout(BigDecimal price) {
        return strategy.apply(price); // 不用if-else,直接委托
    }
}
// 4. 客户端调用
// 用户登录后,根据等级创建策略
DiscountStrategy ds = new VipDiscount();
OrderService order = new OrderService(ds);
order.checkout(price);

工厂方法模式(Factory Method)—— 解耦对象创建

  • 场景:日志系统,需要记录到文件、数据库、或远程服务器。
  • 坏味道LogLogger logger = new FileLogger() 在多个地方硬编码创建。
  • 模式应用
// 1. 产品接口
public interface Logger { void log(String msg); }
public class FileLogger implements Logger { ... }
public class DbLogger implements Logger { ... }
// 2. 工厂接口(工厂方法)
public abstract class LoggerFactory {
    public abstract Logger createLogger(); // 延迟到子类实现
    public void logSomething(String msg) {
        Logger logger = createLogger(); // 调用工厂方法
        logger.log(msg);
    }
}
// 3. 具体工厂
public class FileLoggerFactory extends LoggerFactory {
    public Logger createLogger() { return new FileLogger(); }
}
public class DbLoggerFactory extends LoggerFactory {
    public Logger createLogger() { return new DbLogger(); }
}
// 4. 使用
LoggerFactory factory = new FileLoggerFactory();
factory.logSomething("..."); // 客户端只依赖抽象工厂,不依赖具体Logger类

观察者模式(Observer)—— 解耦发布-订阅

  • 场景:微信支付成功后,需要:1. 发送短信,2. 发放积分,3. 推送通知,可能后续还要加“打印小票”。
  • 坏味道:支付成功后,在一个方法里依次调用 sendSms(), addPoints(), pushNotify(),新增功能就要改这个方法。
  • 模式应用
// 1. 观察者接口
public interface PaymentObserver {
    void afterPaid(Order order);
}
// 2. 具体观察者
public class SmsObserver implements PaymentObserver { ... }
public class PointsObserver implements PaymentObserver { ... }
// 3. 被观察者(事件源)
public class PaymentService {
    private List<PaymentObserver> observers = new ArrayList<>();
    public void addObserver(PaymentObserver observer) { observers.add(observer); }
    public void pay(Order order) {
        // ... 核心支付逻辑
        for (PaymentObserver observer : observers) {
            observer.afterPaid(order); // 通知所有观察者
        }
    }
}
// 4. 使用
PaymentService service = new PaymentService();
service.addObserver(new SmsObserver());
service.addObserver(new PointsObserver());
service.pay(order); // 支付成功后自动执行所有订阅者

适配器模式(Adapter)—— 兼容旧接口

  • 场景:系统之前用MySQL数据库,现在要换成Oracle,但旧代码里到处都是 MySQLUtil.query()
  • 坏味道:改所有调用处,风险高。
  • 模式应用
// 1. 目标接口(我们想要的)
public interface Database {
    void query(String sql);
}
// 2. 被适配者(旧系统或第三方库)
public class OracleDB {
    public void executeQuery(String sql) { ... }
}
// 3. 适配器
public class OracleAdapter implements Database {
    private OracleDB oracleDB;
    public OracleAdapter(OracleDB oracleDB) { this.oracleDB = oracleDB; }
    @Override
    public void query(String sql) {
        // 做必要的转换,然后调用被适配者的方法
        oracleDB.executeQuery(sql);
    }
}
// 4. 使用(客户端只依赖Database接口)
Database db = new OracleAdapter(new OracleDB());
db.query("SELECT * FROM users"); // 代码不用改

第三步:落地原则(避免滥用)

  1. KISS(Keep It Simple, Stupid):如果2个类就能解决问题,不要为了用模式而引入5个类,模式解决的是变化问题,如果未来不可能变化,直接用if-else更简单。
  2. 组合优于继承:优先用接口+组合(如策略模式),而不是大而全的类继承,继承容易造成类爆炸。
  3. 先有重构,后有模式:不要一开始就设计满屏模式,先写能跑的代码,当发现第二次需要修改类似逻辑时,再重构引入模式,这就是重构 -> 模式
  4. 熟读《设计模式》GoF:23种模式不是都要背,但创建型(单例、工厂、建造者)、结构型(适配器、装饰器、代理)、行为型(策略、观察者、模板方法) 这9个是最常用的,要能画出类图和讲出场景。

一个决策流程

当你写代码卡住时,问自己:

  1. 这段代码为什么难改? —— 因为有大量if-else?(考虑策略模式),因为对象创建太散乱?(考虑工厂模式)。
  2. 可能的变化在哪里? —— 算法经常变?把算法封装成策略,对象种类经常变?把创建过程封装成工厂。
  3. 引入模式后,代码是更清晰了还是更复杂了? —— 如果团队其他成员看不懂,或者导致Debug困难,说明过度设计了。

一句话应用心法:没有最好的模式,只有最合适的模式。 把模式当作工具箱里的工具,而不是蓝图,当你写出了一段自己都觉得“这以后肯定要改死”的代码时,就是打开工具箱的时候了。

标签: 设计模式 软件开发

抱歉,评论功能暂时关闭!