设计模式简介(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 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)的最佳实践。它们的价值在于:
- 减少重复代码:通过标准化解决方案降低冗余
- 提升可维护性:统一的模式使团队协作更顺畅
- 增强扩展性:提供清晰的扩展接口与扩展点
- 降低复杂度:将复杂问题分解为可理解的模式
学习设计模式的误区
许多开发者在接触设计模式时容易陷入两个极端:
- 过度设计:试图将所有问题都套用模式,反而增加系统复杂度
- 完全忽视:认为模式只是理论,实际开发中毫无用处
正确的态度应该是:将设计模式视为工具箱中的工具。在合适场景下选择最合适的模式,就像木匠选择锤子或电钻一样自然。
核心模式详解:三类模式的典型应用
创建型模式:优雅的实例管理
单例模式(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 元
实战案例:电商系统的模式应用
场景描述
某电商平台需要实现以下功能:
- 支持多种支付方式(支付宝、微信、信用卡)
- 订单状态变更时通知相关方(用户、客服、仓储)
- 灵活配置不同促销策略(满减、折扣、赠品)
模式应用方案
工厂模式+策略模式组合
// 支付工厂类
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}")
通过组合使用多种模式,系统实现了:
- 扩展性:新增支付方式只需修改工厂类
- 解耦性:订单状态变更与通知机制完全分离
- 灵活性:促销策略可动态切换
学习路径与常见问题解答
进阶学习建议
- 实践优先:通过重构现有代码应用模式
- 模式对比:理解相似模式(如工厂 vs 抽象工厂)
- 反模式认知:学习常见设计错误(如过度抽象)
- 领域模式扩展:学习领域驱动设计中的模式
常见误区澄清
Q:使用设计模式会让代码变得复杂吗?
A:设计模式本身是简化问题的工具。关键在于合理应用,过度设计反而会增加复杂度。建议遵循"YAGNI原则"(除非必要,否则不预先设计)
Q:函数式编程需要学习设计模式吗?
A:设计模式本质是面向对象的解决方案。函数式编程有其对应的函数式设计原则(如柯里化、高阶函数),但设计模式的概念仍可作为设计思维的参考。
Q:如何判断是否该使用某个模式?
A:当遇到以下情况时考虑:
- 频繁出现相似的代码结构
- 对象间通信存在强耦合
- 需要应对多种可能的扩展需求
结论:站在巨人肩膀上编程
设计模式不仅是代码的优化工具,更是面向对象思维的训练体系。它们帮助开发者:
- 降低学习曲线:通过模式名称快速理解复杂系统
- 提升团队协作:统一的模式语言减少沟通成本
- 增强代码健壮性:经过验证的解决方案减少潜在错误
建议读者从简单模式(如工厂、观察者)开始实践,逐步深入复杂模式。记住:模式不是银弹,但恰到好处的使用能让代码如行云流水般优雅。当您下次遇到"如何组织对象协作"的困惑时,不妨打开设计模式的"工具箱",总能找到合适的解决方案。
本文通过系统性讲解设计模式的核心概念、分类及实战应用,帮助开发者建立结构化的设计思维。掌握这些模式如同获得了编程世界的"通关秘籍",让您在面对复杂需求时更加从容不迫。