044_设计模式入门(创建型 / 结构型 / 行为型)
设计模式(Design Pattern)是面向对象编程中对重复出现的问题的标准化解决方案,由 GoF(Gang of Four)总结为 23 种经典模式。这些模式基于封装、继承、多态三大特性,旨在提高代码的可复用性、可维护性和灵活性。根据解决问题的类型,设计模式可分为三大类:创建型模式(对象创建)、结构型模式(类 / 对象组合)、行为型模式(对象交互)。
一、设计模式概述
1.1 设计模式的核心价值
设计模式不是现成代码,而是通用设计思路,主要解决:
- 代码复用:避免重复编写相似逻辑。
- 解耦:降低类与类之间的依赖(高内聚、低耦合)。
- 扩展性:新增功能时无需修改原有代码(符合开闭原则)。
- 可读性:使用公认的模式使代码更易理解(如 “单例” 一看就知道是唯一实例)。
1.2 三大类模式的划分标准
- 创建型模式:聚焦 “对象如何创建”,隐藏创建细节(如实例化逻辑)。
- 结构型模式:聚焦 “类或对象如何组合”,实现更灵活的结构(如适配接口、动态扩展功能)。
- 行为型模式:聚焦 “对象如何交互”,规范职责分配与通信方式(如通知机制、算法切换)。
二、创建型模式(Creational Patterns)
创建型模式专注于对象的创建过程,通过封装创建逻辑,使代码不依赖具体类,从而应对需求变化(如更换产品类型)。常见的 5 种创建型模式如下:
2.1 单例模式(Singleton Pattern)
核心意图:
确保一个类只有一个实例,并提供全局唯一访问点。
解决的问题:
避免重复创建资源密集型对象(如数据库连接池、配置管理器),节省资源。
关键实现:
- 私有构造器(禁止外部new实例)。
- 静态私有实例(存储唯一实例)。
- 静态公有方法(返回实例,控制创建逻辑)。
简单示例(懒汉式):
public class ConfigManager {// 静态私有实例(懒加载:使用时才创建)private static ConfigManager instance;// 私有构造器:禁止外部创建private ConfigManager() {}// 全局访问点public static ConfigManager getInstance() {if (instance == null) {instance = new ConfigManager(); // 首次调用时初始化}return instance;}
}
适用场景:
- 全局配置、线程池、日志工厂等 “单一资源” 场景。
2.2 工厂方法模式(Factory Method Pattern)
核心意图:
定义创建对象的接口,但由子类决定实例化哪个类(将创建逻辑延迟到子类)。
解决的问题:
避免代码中直接new具体类(如new MySQLDao()),减少对具体实现的依赖(如更换数据库时无需修改调用代码)。
关键实现:
- 抽象工厂接口(定义创建方法)。
- 具体工厂类(实现创建方法,返回具体产品)。
- 产品接口(约束产品功能)。
简单示例:
// 产品接口
public interface Logger {void log(String message);
}// 具体产品:文件日志
public class FileLogger implements Logger {@Overridepublic void log(String message) {System.out.println("文件日志:" + message);}
}// 工厂接口
public interface LoggerFactory {Logger createLogger();
}// 具体工厂:创建文件日志
public class FileLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new FileLogger(); // 实例化具体产品}
}// 使用:依赖工厂接口,不依赖具体产品
public class Client {public static void main(String[] args) {LoggerFactory factory = new FileLoggerFactory();Logger logger = factory.createLogger(); // 无需直接new FileLoggerlogger.log("系统启动");}
}
适用场景:
产品种类较多且可能扩展(如日志系统支持文件日志、数据库日志)。
2.3 建造者模式(Builder Pattern)
核心意图:
将复杂对象的构建过程与表示分离,使同一构建过程可创建不同产品(如 “电脑” 可由不同 CPU、内存组合而成)。
解决的问题:
复杂对象的创建步骤繁琐(如 “用户” 对象需设置姓名、年龄、地址等多个属性,参数多且可选)。
关键实现:
- 产品类(复杂对象,如Computer)。
- 建造者类(封装构建步骤,提供链式设置方法)。
- director(可选,负责控制构建流程)。
简单示例:
// 产品:电脑(复杂对象)
public class Computer {private String cpu;private String memory;private String disk;// 私有构造器:仅允许Builder创建private Computer(Builder builder) {this.cpu = builder.cpu;this.memory = builder.memory;this.disk = builder.disk;}// 建造者类:负责构建Computerpublic static class Builder {private String cpu;private String memory;private String disk;// 链式设置属性(返回Builder自身)public Builder cpu(String cpu) {this.cpu = cpu;return this;}public Builder memory(String memory) {this.memory = memory;return this;}public Builder disk(String disk) {this.disk = disk;return this;}// 构建产品public Computer build() {return new Computer(this);}}
}// 使用:链式调用,清晰可控
Computer pc = new Computer.Builder().cpu("Intel i9").memory("32GB").disk("1TB SSD").build();
适用场景:
- 复杂对象创建(如订单、用户信息、配置对象等包含多个可选属性)。
2.4 其他创建型模式简介
- 抽象工厂模式:创建 “产品族”(如 Windows 系统的按钮 + 文本框,Mac 系统的按钮 + 文本框),支持多套产品组合。
- 原型模式:通过复制现有对象创建新对象(如大对象复制比重新初始化更高效),实现Cloneable接口。
三、结构型模式(Structural Patterns)
结构型模式专注于类或对象的组合方式,通过灵活组合实现功能扩展或接口适配,使系统结构更稳定。常见的 7 种结构型模式如下:
3.1 适配器模式(Adapter Pattern)
核心意图:
将一个类的接口转换为客户端期望的另一个接口,使接口不兼容的类可协同工作(类似 “转接头”)。
解决的问题:
旧系统接口与新系统不匹配(如旧接口有getOldData(),新系统需要getData())。
关键实现:
- 目标接口(客户端需要的接口)。
- 适配器类(实现目标接口,内部调用被适配者的方法)。
简单示例(类适配器):
// 目标接口(新系统需要的接口)
public interface NewInterface {void newMethod();
}// 被适配者(旧系统接口)
public class OldClass {public void oldMethod() {System.out.println("调用旧系统方法");}
}// 适配器:连接新接口与旧类
public class Adapter extends OldClass implements NewInterface {@Overridepublic void newMethod() {super.oldMethod(); // 适配:调用旧方法实现新接口}
}// 使用:客户端调用新接口,适配旧实现
NewInterface adapter = new Adapter();
adapter.newMethod(); // 输出“调用旧系统方法”
适用场景:
- 系统升级时兼容旧模块、集成第三方组件(接口不符)。
3.2 装饰器模式(Decorator Pattern)
核心意图:
动态地给对象添加额外功能,且不改变其原有结构(如给咖啡加奶、加糖)。
解决的问题:
避免通过继承扩展功能导致的类爆炸(如咖啡 + 奶、咖啡 + 糖、咖啡 + 奶 + 糖,继承需 3 个子类,装饰器只需 2 个装饰类)。
关键实现:
- 抽象组件(如Coffee)。
- 具体组件(如BlackCoffee)。
- 装饰器类(实现组件接口,持有组件实例,添加新功能)。
简单示例:
// 抽象组件:咖啡
public interface Coffee {String getDesc(); // 描述double cost(); // 价格
}// 具体组件:黑咖啡
public class BlackCoffee implements Coffee {@Overridepublic String getDesc() { return "黑咖啡"; }@Overridepublic double cost() { return 15; }
}// 装饰器抽象类
public abstract class CoffeeDecorator implements Coffee {protected Coffee coffee; // 持有被装饰的咖啡public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; }
}// 具体装饰器:加奶
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) { super(coffee); }@Overridepublic String getDesc() { return coffee.getDesc() + "+牛奶"; }@Overridepublic double cost() { return coffee.cost() + 5; } // 加价5元
}// 使用:动态叠加功能
Coffee drink = new BlackCoffee();
drink = new MilkDecorator(drink); // 加奶
drink = new SugarDecorator(drink); // 加糖
System.out.println(drink.getDesc()); // 黑咖啡+牛奶+糖
System.out.println(drink.cost()); // 15+5+3=23
适用场景:
动态扩展功能(如 IO 流中的BufferedInputStream给FileInputStream添加缓冲功能)。
3.3 代理模式(Proxy Pattern)
核心意图:
为对象提供代理对象,控制对原对象的访问(如权限校验、日志记录、延迟加载)。
解决的问题:
需在访问对象前后添加额外操作(如调用方法前检查权限,调用后记录日志)。
关键实现:
- 目标接口(代理与原对象实现同一接口)。
- 代理类(持有目标对象,在调用目标方法前后添加逻辑)。
简单示例(静态代理):
// 目标接口
public interface Image {void display();
}// 真实对象(高清图片,加载耗时)
public class RealImage implements Image {private String path;public RealImage(String path) {this.path = path;loadFromDisk(); // 初始化耗时}private void loadFromDisk() {System.out.println("加载图片:" + path);}@Overridepublic void display() {System.out.println("显示图片:" + path);}
}// 代理对象(控制访问,实现延迟加载)
public class ImageProxy implements Image {private RealImage realImage;private String path;public ImageProxy(String path) { this.path = path; }@Overridepublic void display() {// 延迟加载:仅在需要时创建真实对象if (realImage == null) {realImage = new RealImage(path);}realImage.display(); // 调用真实对象方法}
}// 使用:通过代理访问,优化性能
Image img = new ImageProxy("photo.png");
// 此时未加载图片,直到调用display()才触发加载
img.display();
适用场景:
- 延迟加载(大对象)、权限控制、日志记录、远程服务代理(如 RPC 框架)。
3.4 其他结构型模式简介
- 装饰器模式:动态给对象添加功能(功能叠加,如咖啡加奶加糖)。
- 外观模式:为复杂子系统提供统一入口(如电脑启动:简化 CPU、内存、硬盘的启动步骤)。
- 桥接模式:分离抽象与实现(如形状与颜色:圆形 + 红色、方形 + 蓝色,两者可独立扩展)。
四、行为型模式(Behavioral Patterns)
行为型模式专注于对象间的交互与职责分配,使对象协作更清晰、可扩展。常见的 11 种行为型模式如下:
4.1 策略模式(Strategy Pattern)
核心意图:
定义一系列算法,封装每个算法,并使它们可互换(如不同支付方式、排序算法)。
解决的问题:
避免用if-else硬编码多种算法(如支付系统:微信 / 支付宝 / 银行卡支付,新增支付方式需改原有代码)。
关键实现:
- 策略接口(定义算法统一方法)。
- 具体策略类(实现接口,封装不同算法)。
- 上下文类(持有策略对象,调用策略方法)。
简单示例:
// 策略接口(支付算法)
public interface PaymentStrategy {void pay(double amount);
}// 具体策略1:微信支付
public class WechatPay implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("微信支付:" + amount + "元");}
}// 具体策略2:支付宝支付
public class Alipay implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("支付宝支付:" + amount + "元");}
}// 上下文类(使用策略)
public class Order {private PaymentStrategy payment;// 设置策略(动态切换)public void setPayment(PaymentStrategy payment) {this.payment = payment;}public void checkout(double amount) {payment.pay(amount); // 调用策略方法}
}// 使用:动态切换算法,无需修改Order类
Order order = new Order();
order.setPayment(new WechatPay()); // 微信支付
order.checkout(200);order.setPayment(new Alipay()); // 切换为支付宝
order.checkout(300);
适用场景:
- 多种算法可选且需动态切换(如排序算法、支付方式、折扣策略)。
4.2 观察者模式(Observer Pattern)
核心意图:
定义对象间的一对多依赖,当一个对象状态变化时,所有依赖它的对象自动收到通知(如公众号与订阅者)。
解决的问题:
对象间联动通信(如订单状态更新后,需通知库存系统、日志系统、消息推送系统)。
关键实现:
- 主题接口(被观察者,提供注册、移除、通知观察者的方法)。
- 观察者接口(定义接收通知的方法)。
- 具体主题(维护观察者列表,状态变化时通知所有观察者)。
简单示例:
// 观察者接口
public interface Observer {void update(String message); // 接收通知
}// 主题接口(被观察者)
public interface Subject {void register(Observer observer); // 注册观察者void remove(Observer observer); // 移除观察者void notifyObservers(String msg); // 通知所有观察者
}// 具体主题:公众号
public class WechatSubject implements Subject {private List<Observer> observers = new ArrayList<>();@Overridepublic void register(Observer observer) {observers.add(observer);}@Overridepublic void remove(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String msg) {// 通知所有订阅者for (Observer o : observers) {o.update(msg);}}// 发布文章(状态变化)public void publish(String article) {notifyObservers("新文章:" + article);}
}// 具体观察者:用户
public class User implements Observer {private String name;public User(String name) { this.name = name; }@Overridepublic void update(String message) {System.out.println(name + "收到:" + message);}
}// 使用:订阅与通知
WechatSubject subject = new WechatSubject();
Observer user1 = new User("张三");
Observer user2 = new User("李四");subject.register(user1);
subject.register(user2);
subject.publish("《设计模式入门》"); // 所有用户收到通知
适用场景:
- 事件监听(如 GUI 按钮点击)、消息通知(订单状态、库存变更)、实时数据更新(股票行情)。
4.3 其他行为型模式简介
- 模板方法模式:定义算法骨架(如做菜步骤:备菜→烹饪→装盘),子类实现具体步骤。
- 责任链模式:请求沿处理者链条传递(如请假审批:组长→经理→总监),直到被处理。
- 迭代器模式:统一遍历聚合对象(如List的iterator()),隐藏内部结构。
五、设计模式的选择与实践建议
- 不盲目套用:模式是工具,需根据场景选择(如简单对象无需用建造者模式)。
- 优先掌握核心模式:创建型(单例、工厂方法)、结构型(适配器、代理)、行为型(策略、观察者)是高频使用模式。
- 理解而非记代码:掌握模式的 “意图” 和 “解决的问题”,而非死记代码实现(同一模式可有多种写法)。
- 从小处实践:在日常开发中尝试用模式重构代码(如用单例管理配置,用策略模式处理多规则逻辑)。
六、总结
设计模式是面向对象编程的 “成熟经验”,三大类模式各有侧重:
- 创建型:控制对象创建,解耦创建与使用。
- 结构型:优化类 / 对象组合,实现灵活扩展。
- 行为型:规范对象交互,使协作更清晰。
入门阶段无需掌握所有 23 种模式,重点理解核心模式的意图和适用场景,逐步在实践中体会其价值。记住:好的模式是 “自然而然” 解决问题的,而非刻意套用。