设计模式简介(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言:为什么我们需要设计模式?

在软件开发领域,设计模式就像是程序员的“经验结晶”。它们是经过验证的解决方案,能够帮助开发者高效解决重复出现的问题。想象一下,当你在建筑工地工作时,如果每次都要从零开始设计房屋结构,不仅耗时,还容易犯错。而设计模式就像是一套经过实践验证的“建筑图纸”,让开发者能够快速构建稳定、可维护的系统。

对于编程初学者而言,设计模式可能显得抽象难懂。但通过本文的循序渐进讲解,你将发现:这些模式不过是将日常开发经验提炼成的通用策略。它们如同乐高积木,通过组合不同模块,能快速搭建出复杂而优雅的系统架构。

什么是设计模式?

定义与核心价值

设计模式(Design Patterns)是针对特定问题的解决方案模板,由 Erich Gamma 等人于 1994 年在经典著作《设计模式:可复用面向对象软件的基础》中首次系统总结。这 23 种设计模式(实际应用中已扩展至数十种)分为三大类:

类型目标问题典型模式示例
创建型对象创建与初始化单例模式、工厂模式
结构型类与对象组合适配器模式、装饰器模式
行为型对象间职责分配与通信观察者模式、策略模式

这些模式并非编程语言的特性,而是面向对象编程(OOP)的最佳实践。它们的价值在于:

  • 减少重复代码:通过标准化解决方案降低冗余
  • 提升可维护性:统一的模式使团队协作更顺畅
  • 增强扩展性:提供清晰的扩展接口与扩展点
  • 降低复杂度:将复杂问题分解为可理解的模式

学习设计模式的误区

许多开发者在接触设计模式时容易陷入两个极端:

  1. 过度设计:试图将所有问题都套用模式,反而增加系统复杂度
  2. 完全忽视:认为模式只是理论,实际开发中毫无用处

正确的态度应该是:将设计模式视为工具箱中的工具。在合适场景下选择最合适的模式,就像木匠选择锤子或电钻一样自然。

核心模式详解:三类模式的典型应用

创建型模式:优雅的实例管理

单例模式(Singleton Pattern)

意图:确保一个类只有一个实例,并提供全局访问点
比喻:如同公司的唯一 CEO,无论从哪个部门访问都指向同一个人

class Singleton:
    _instance = None

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

s1 = Singleton()
s2 = Singleton()
print(s1 == s2)  # 输出:True

适用场景:日志记录器、数据库连接池等需要全局唯一实例的场景

工厂模式(Factory Pattern)

意图:封装对象创建逻辑,隐藏具体实现
比喻:如同汽车工厂,根据订单生产不同车型

// 抽象产品接口
interface Payment {
    void process();
}

// 具体产品
class CreditCardPayment implements Payment {
    public void process() { /* ... */ }
}

// 工厂类
class PaymentFactory {
    public static Payment createPayment(String type) {
        if ("credit".equals(type)) return new CreditCardPayment();
        // 其他类型处理...
        return null;
    }
}

扩展性优势:添加新支付方式只需修改工厂类,无需改动调用端代码

结构型模式:灵活的类组合艺术

适配器模式(Adapter Pattern)

意图:将一个接口转换为客户端期望的另一个接口
比喻:如同转接头,让不同接口的电器可以协同工作

// 目标接口
class Target {
    constructor() {}
    request() { console.log("目标方法"); }
}

// 待适配类
class Adaptee {
    specificRequest() { console.log("被适配方法"); }
}

// 适配器类
class Adapter extends Target {
    constructor(adaptee) {
        super();
        this.adaptee = adaptee;
    }
    request() {
        this.adaptee.specificRequest();
    }
}

const adaptee = new Adaptee();
const adapter = new Adapter(adaptee);
adapter.request(); // 输出:被适配方法

装饰器模式(Decorator Pattern)

意图:动态添加对象功能,避免类爆炸
比喻:如同给蛋糕添加装饰层,每层装饰可独立选择

class Component:
    def operation(self):
        pass

class ConcreteComponent(Component):
    def operation(self):
        return "基础功能"

class Decorator(Component):
    def __init__(self, component):
        self.component = component

class DecoratorA(Decorator):
    def operation(self):
        return f"装饰A: {self.component.operation()}"

base = ConcreteComponent()
decorated = DecoratorA(base)
print(decorated.operation())  # 输出:装饰A: 基础功能

行为型模式:对象间的优雅通信

观察者模式(Observer Pattern)

意图:定义一对多依赖关系,状态变化自动通知
比喻:如同公众号订阅,当内容更新时所有订阅者自动收到通知

// 目标接口
interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

// 具体目标
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;

    @Override
    public void registerObserver(Observer o) { observers.add(o); }
    // 其他接口实现...

    public void setMeasurements(float temp) {
        this.temperature = temp;
        notifyObservers();
    }
}

// 观察者接口
interface Observer {
    void update(float temp);
}

// 具体观察者
class PhoneApp implements Observer {
    @Override
    public void update(float temp) {
        System.out.println("手机APP收到温度:" + temp);
    }
}

// 使用示例
WeatherStation station = new WeatherStation();
PhoneApp app = new PhoneApp();
station.registerObserver(app);
station.setMeasurements(25.5f);

策略模式(Strategy Pattern)

意图:将算法封装为可互换组件
比喻:如同不同刀法的厨师,可根据需求切换烹饪策略

// 策略接口
class PaymentStrategy {
    pay(amount) {}
}

// 具体策略
class CreditCardStrategy extends PaymentStrategy {
    constructor(cardNumber) {
        this.cardNumber = cardNumber;
    }
    pay(amount) {
        console.log(`信用卡支付 ${amount} 元`);
    }
}

// 上下文类
class Order {
    constructor(strategy) {
        this.paymentStrategy = strategy;
    }
    placeOrder(amount) {
        this.paymentStrategy.pay(amount);
    }
}

// 使用示例
const order = new Order(new CreditCardStrategy("1234-5678"));
order.placeOrder(100); // 输出:信用卡支付 100 元

实战案例:电商系统的模式应用

场景描述

某电商平台需要实现以下功能:

  1. 支持多种支付方式(支付宝、微信、信用卡)
  2. 订单状态变更时通知相关方(用户、客服、仓储)
  3. 灵活配置不同促销策略(满减、折扣、赠品)

模式应用方案

工厂模式+策略模式组合

// 支付工厂类
class PaymentFactory {
    public static PaymentStrategy createStrategy(String type) {
        switch (type) {
            case "alipay": return new AlipayStrategy();
            case "wechat": return new WeChatStrategy();
            default: return new CreditCardStrategy();
        }
    }
}

// 促销策略上下文
class PromotionContext {
    private PromotionStrategy strategy;

    public void setStrategy(PromotionStrategy strategy) {
        this.strategy = strategy;
    }

    public void applyDiscount(Order order) {
        strategy.apply(order);
    }
}

观察者模式实现通知系统

class Order:
    def __init__(self):
        self.observers = []
    
    def attach(self, observer):
        self.observers.append(observer)
    
    def notify_observers(self):
        for observer in self.observers:
            observer.update(self)

class UserNotifier:
    def update(self, order):
        print(f"用户通知:订单{order.id}状态变更为{order.status}")

class WarehouseNotifier:
    def update(self, order):
        print(f"仓储系统:准备发货订单{order.id}")

通过组合使用多种模式,系统实现了:

  • 扩展性:新增支付方式只需修改工厂类
  • 解耦性:订单状态变更与通知机制完全分离
  • 灵活性:促销策略可动态切换

学习路径与常见问题解答

进阶学习建议

  1. 实践优先:通过重构现有代码应用模式
  2. 模式对比:理解相似模式(如工厂 vs 抽象工厂)
  3. 反模式认知:学习常见设计错误(如过度抽象)
  4. 领域模式扩展:学习领域驱动设计中的模式

常见误区澄清

Q:使用设计模式会让代码变得复杂吗?
A:设计模式本身是简化问题的工具。关键在于合理应用,过度设计反而会增加复杂度。建议遵循"YAGNI原则"(除非必要,否则不预先设计)

Q:函数式编程需要学习设计模式吗?
A:设计模式本质是面向对象的解决方案。函数式编程有其对应的函数式设计原则(如柯里化、高阶函数),但设计模式的概念仍可作为设计思维的参考。

Q:如何判断是否该使用某个模式?
A:当遇到以下情况时考虑:

  • 频繁出现相似的代码结构
  • 对象间通信存在强耦合
  • 需要应对多种可能的扩展需求

结论:站在巨人肩膀上编程

设计模式不仅是代码的优化工具,更是面向对象思维的训练体系。它们帮助开发者:

  • 降低学习曲线:通过模式名称快速理解复杂系统
  • 提升团队协作:统一的模式语言减少沟通成本
  • 增强代码健壮性:经过验证的解决方案减少潜在错误

建议读者从简单模式(如工厂、观察者)开始实践,逐步深入复杂模式。记住:模式不是银弹,但恰到好处的使用能让代码如行云流水般优雅。当您下次遇到"如何组织对象协作"的困惑时,不妨打开设计模式的"工具箱",总能找到合适的解决方案。

本文通过系统性讲解设计模式的核心概念、分类及实战应用,帮助开发者建立结构化的设计思维。掌握这些模式如同获得了编程世界的"通关秘籍",让您在面对复杂需求时更加从容不迫。

最新发布