23种设计模式
23种设计模式总结(大白话,适合小白),完整例子讲解,明白怎么用,什么时候用,对比优缺点,不同之处
23种设计模式大白话总结(适合小白)
设计模式是解决代码问题的“经典套路”,就像烹饪的固定配方。以下是最通俗的解释+生活例子+代码片段,帮你快速理解每种模式的核心思想、适用场景和优缺点,并对比不同模式的区别!
一、创建型模式(5种)
核心目标:解决对象创建的问题,让代码灵活生成实例。
1. 单例模式(Singleton)
是什么:确保一个类只有一个实例,全局可访问。
例子:数据库连接池、全局配置对象。
代码:
java
public class Singleton {private static Singleton instance;private Singleton() {} // 私有构造public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }
何时用:需要严格控制实例数量时(如共享资源)。
优点:节省内存,避免重复创建。
缺点:多线程需加锁(可用双重检查锁
优化)。
2. 工厂方法模式(Factory Method)
是什么:定义一个创建对象的接口,让子类决定实例化哪个类。
例子:物流系统,不同运输方式(卡车、轮船)由不同子工厂创建。
代码:
java
interface Transport {void deliver(); } class Truck implements Transport {public void deliver() { System.out.println("陆运"); } } class Ship implements Transport {public void deliver() { System.out.println("海运"); } }// 工厂接口 interface Logistics {Transport createTransport(); } class RoadLogistics implements Logistics {public Transport createTransport() { return new Truck(); } } class SeaLogistics implements Logistics {public Transport createTransport() { return new Ship(); } }
何时用:需要解耦对象创建和使用时。
优点:扩展性强(新增运输方式只需加子类)。
缺点:每新增一个产品就要新增一个工厂类。
3. 抽象工厂模式(Abstract Factory)
是什么:创建成套相关对象(如GUI组件:按钮+文本框)。
例子:Windows风格工厂生产Windows按钮和文本框,Mac工厂生产Mac风格组件。
代码:
java
interface Button { void render(); } interface TextBox { void input(); }// Windows 系列组件 class WinButton implements Button {public void render() { System.out.println("Windows 按钮"); } } class WinTextBox implements TextBox {public void input() { System.out.println("Windows 输入框"); } }// Mac 系列组件 class MacButton implements Button {public void render() { System.out.println("Mac 按钮"); } } class MacTextBox implements TextBox {public void input() { System.out.println("Mac 输入框"); } }// 抽象工厂 interface GUIFactory {Button createButton();TextBox createTextBox(); } class WinFactory implements GUIFactory {public Button createButton() { return new WinButton(); }public TextBox createTextBox() { return new WinTextBox(); } } class MacFactory implements GUIFactory {public Button createButton() { return new MacButton(); }public TextBox createTextBox() { return new MacTextBox(); } }
何时用:需要保证产品兼容性时。
优点:产品族一致性高。
缺点:新增产品族需修改所有工厂。
4. 建造者模式(Builder)
是什么:分步骤构造复杂对象,支持灵活组合参数。
例子:组装电脑(CPU、内存、硬盘可自定义)。
代码:
java
class Computer {private String CPU;private String RAM;// 私有构造,只能通过Builder创建private Computer(Builder builder) {this.CPU = builder.CPU;this.RAM = builder.RAM;}// 建造者public static class Builder {private String CPU;private String RAM;public Builder setCPU(String cpu) { this.CPU = cpu; return this; }public Builder setRAM(String ram) { this.RAM = ram; return this; }public Computer build() { return new Computer(this); }} }// 使用 Computer myPC = new Computer.Builder().setCPU("Intel i9").setRAM("32GB").build();
何时用:对象构造参数多且可选时。
优点:避免构造方法过长。
缺点:代码量增加。
5. 原型模式(Prototype)
是什么:通过克隆现有对象创建新对象(而非new
)。
例子:游戏中的怪物快速复制。
代码:
java
class Monster implements Cloneable {private String type;public Monster(String type) { this.type = type; }@Overridepublic Monster clone() throws CloneNotSupportedException {return (Monster) super.clone();} }// 使用 Monster dragon = new Monster("Dragon"); Monster dragon2 = dragon.clone(); // 克隆而不是新建
何时用:对象创建成本高时(如数据库初始化)。
优点:性能高(比new
快)。
缺点:深拷贝需额外处理。
二、结构型模式(7种)
结构型设计模式主要解决如何组合类和对象来形成更大的结构,同时保持灵活性和可复用性。
核心目标:解决类和对象的组合问题,优化代码结构。
6. 适配器模式(Adapter)
是什么:让不兼容的接口协同工作。
例子:Type-C转3.5mm耳机转接头。
代码:
java
// 旧接口(3.5mm耳机) interface OldHeadphone {void playSound(); } // 新接口(Type-C) interface TypeC {void transmitDigital(); } // 适配器 class Adapter implements OldHeadphone {private TypeC typeC;public Adapter(TypeC typeC) { this.typeC = typeC; }public void playSound() {typeC.transmitDigital(); // 调用新接口的方法} }
何时用:旧系统兼容新接口时,整合老代码或第三方库时接口不兼容。
优点:无需修改原有代码,让不兼容的类一起工作。
缺点:增加调用层级,代码复杂度增加。
7. 装饰器模式(Decorator)
是什么:动态给对象添加功能(替代继承)。
例子:给人穿不同衣服(装饰),给咖啡加糖、加牛奶。
代码:
java
// 基础接口 interface Coffee {int cost(); }// 基础实现 class BasicCoffee implements Coffee {@Overridepublic int cost() {return 10;} }// 装饰器基类 abstract class CoffeeDecorator implements Coffee {protected Coffee coffee;public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;} }// 具体装饰器(加糖) class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic int cost() {return coffee.cost() + 2;} }// 使用 public class Main {public static void main(String[] args) {Coffee coffee = new BasicCoffee();coffee = new SugarDecorator(coffee);System.out.println(coffee.cost()); // 输出12} }
何时用:不想用继承,但需要动态扩展功能,需要灵活扩展对象功能时。
优点:灵活,避免继承导致的类爆炸。
缺点:多层装饰复杂,可能难调试。
8. 代理模式(Proxy)
是什么:通过代理控制对象访问(如权限验证)。
例子:延迟加载图片。
代码:
java
interface Image {void display(); }// 真实图片 class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("加载图片: " + filename);}@Overridepublic void display() {System.out.println("显示图片: " + filename);} }// 代理类 class ProxyImage implements Image {private String filename;private RealImage realImage;public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}realImage.display();} }// 使用 public class Main {public static void main(String[] args) {Image image = new ProxyImage("photo.jpg");image.display(); // 第一次真正加载image.display(); // 直接使用缓存} }
何时用:需要延迟加载或权限控制时。
优点:解耦客户端和实际对象,保护目标对象。
缺点:增加请求处理时间。
9. 组合模式(Composite)
是什么:统一处理单个对象和组合对象,用树形结构表示“部分-整体”关系。
例子:文件系统(文件夹包含文件/子文件夹)。
代码:
java
interface Component {void operation(); }// 叶子节点(文件) class Leaf implements Component {@Overridepublic void operation() {System.out.println("执行叶子节点操作");} }// 组合节点(文件夹) class Composite implements Component {private List<Component> children = new ArrayList<>();public void add(Component component) {children.add(component);}@Overridepublic void operation() {for (Component child : children) {child.operation();}} }// 使用 public class Main {public static void main(String[] args) {Composite root = new Composite();root.add(new Leaf());root.add(new Leaf());root.operation(); // 输出两次叶子操作} }
何时用:处理树形结构(菜单、文件系统)。
优点:统一处理单个对象和组合对象。
缺点:设计抽象,业务复杂时难实现,叶子节点可能被迫实现不相关的方法。
10. 桥接模式(Bridge)
是什么:将抽象与实现分离,各自独立变化。
例子:不同颜色和形状的图形(如红色圆形、蓝色方形)。
代码:
java
abstract class Shape {protected Color color;public Shape(Color color) { this.color = color; } } class Circle extends Shape { /* 具体实现 */ }
java
// 实现部分(渲染器) interface Renderer {void renderCircle(int radius); }class VectorRenderer implements Renderer {@Overridepublic void renderCircle(int radius) {System.out.println("矢量圆,半径" + radius);} }// 抽象部分(形状) abstract class Shape {protected Renderer renderer;public Shape(Renderer renderer) {this.renderer = renderer;}abstract void draw(); }class Circle extends Shape {private int radius;public Circle(Renderer renderer, int radius) {super(renderer);this.radius = radius;}@Overridevoid draw() {renderer.renderCircle(radius);} }// 使用 public class Main {public static void main(String[] args) {Renderer vectorRenderer = new VectorRenderer();Circle circle = new Circle(vectorRenderer, 5);circle.draw(); // 输出矢量圆,半径5} }
何时用:避免多层继承,独立扩展不同维度,多维度变化的场景。
优点:减少类数量,灵活扩展,解耦抽象和实现。
缺点:设计复杂度高。
11. 享元模式(Flyweight)
是什么:共享大量细粒度对象(如文字处理中的字符库),共享对象以减少内存占用。
例子:游戏中的重复小兵模型共享。
代码:
java
class Bullet {private final String type; // 内部状态(可共享)public Bullet(String type) {this.type = type;}public void fire(int x, int y) { // 外部状态由参数传递System.out.println(type + "子弹发射到(" + x + "," + y + ")");} }class BulletFactory {private static final Map<String, Bullet> bullets = new HashMap<>();public static Bullet getBullet(String type) {if (!bullets.containsKey(type)) {bullets.put(type, new Bullet(type));}return bullets.get(type);} }// 使用 public class Main {public static void main(String[] args) {Bullet bullet1 = BulletFactory.getBullet("9mm");Bullet bullet2 = BulletFactory.getBullet("9mm");System.out.println(bullet1 == bullet2); // 输出truebullet1.fire(100, 200);} }
何时用:系统有大量相似对象时,需要减少内存开销时。
优点:节省内存,大幅降低内存占用。
缺点:需要区分内部/外部状态。
12. 外观模式(Facade)
是什么:提供一个简化接口,隐藏系统复杂性,为复杂子系统提供统一入口。
例子:一键启动电脑(封装开机自检、加载系统等步骤)。
代码:
java
class CPU {void start() { System.out.println("CPU启动"); } }class Memory {void start() { System.out.println("内存启动"); } }// 外观类(一键开机) class ComputerFacade {private CPU cpu;private Memory memory;public ComputerFacade() {cpu = new CPU();memory = new Memory();}public void start() {cpu.start();memory.start();} }// 使用 public class Main {public static void main(String[] args) {ComputerFacade computer = new ComputerFacade();computer.start(); // 隐藏复杂步骤} }
何时用:简化客户端调用复杂系统时。
优点:降低使用复杂度。
缺点:不符合开闭原则(修改需改外观类),外观类可能变成“上帝类”。
三、行为型模式(11种)
行为型设计模式主要解决 对象之间的交互和职责分配,让代码更灵活、可维护。
核心目标:解决对象间的交互与职责分配问题。
13. 观察者模式(Observer)
是什么:一对多依赖,对象状态变化时通知所有依赖者。
例子:微信公众号(发布文章时通知所有订阅用户)。
代码:
java
// 观察者接口 interface Subscriber {void update(String message); }// 被观察者(主题) class WeChatPublicAccount {private List<Subscriber> subscribers = new ArrayList<>();public void addSubscriber(Subscriber sub) {subscribers.add(sub);}public void notifySubscribers(String message) {for (Subscriber sub : subscribers) {sub.update(message);}} }// 具体观察者 class User implements Subscriber {private String name;public User(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " 收到消息:" + message);} }// 使用 public class Main {public static void main(String[] args) {WeChatPublicAccount account = new WeChatPublicAccount();account.addSubscriber(new User("张三"));account.addSubscriber(new User("李四"));account.notifySubscribers("新文章发布了!");} }
何时用:需要动态联动多个对象时。
优点:解耦观察者和被观察者。
缺点:通知顺序可能影响效率。
14. 策略模式(Strategy)
是什么:封装算法族,可动态切换。
例子:支付方式(支付宝、微信、银行卡)。
代码:
java
// 策略接口 interface PaymentStrategy {void pay(int amount); }// 具体策略 class Alipay implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("支付宝支付:" + amount + "元");} }class WechatPay implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("微信支付:" + amount + "元");} }// 上下文(使用策略的类) class ShoppingCart {private PaymentStrategy strategy;public void setStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void checkout(int amount) {strategy.pay(amount);} }// 使用 public class Main {public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();cart.setStrategy(new Alipay());cart.checkout(100); // 支付宝支付:100元} }
何时用:需要灵活替换算法时。
优点:避免多重条件判断。
缺点:策略类数量多。
15. 模板方法模式(Template Method)
是什么:定义算法骨架,子类实现细节。
例子:咖啡和茶的制作流程(烧水、冲泡、加料)。
代码:
java
abstract class Beverage {// 模板方法(固定流程)public final void prepare() {boilWater();brew();pourInCup();addCondiments();}void boilWater() {System.out.println("烧水");}abstract void brew(); // 子类实现abstract void addCondiments();void pourInCup() {System.out.println("倒入杯子");} }class Coffee extends Beverage {@Overridevoid brew() {System.out.println("冲泡咖啡粉");}@Overridevoid addCondiments() {System.out.println("加糖和牛奶");} }// 使用 public class Main {public static void main(String[] args) {Beverage coffee = new Coffee();coffee.prepare(); // 执行模板方法} }
何时用:多个子类有公共流程时。
优点:代码复用性强。
缺点:子类可能影响父类逻辑。
16. 责任链模式(Chain of Responsibility)
是什么:将请求沿处理链传递,直到被处理。
例子:审批流程(员工→经理→CEO)。
代码:
java
// 处理者接口 interface Handler {void setNext(Handler next);void handleRequest(int amount); }// 具体处理者 class GroupLeader implements Handler {private Handler next;@Overridepublic void setNext(Handler next) {this.next = next;}@Overridepublic void handleRequest(int amount) {if (amount <= 1000) {System.out.println("组长审批通过");} else if (next != null) {next.handleRequest(amount);}} }class Manager implements Handler {private Handler next;@Overridepublic void setNext(Handler next) {this.next = next;}@Overridepublic void handleRequest(int amount) {if (amount <= 5000) {System.out.println("经理审批通过");} else if (next != null) {next.handleRequest(amount);}} }// 使用 public class Main {public static void main(String[] args) {Handler groupLeader = new GroupLeader();Handler manager = new Manager();groupLeader.setNext(manager);groupLeader.handleRequest(3000); // 经理审批通过} }
何时用:请求需多级处理时。
优点:解耦请求和处理者。
缺点:链长时性能低。
17. 状态模式(State)
是什么:对象行为随内部状态改变而改变。
例子:订单状态(待支付→已发货→已完成)。
代码:
java
// 状态接口 interface State {void handle(); }// 具体状态 class OnState implements State {@Overridepublic void handle() {System.out.println("灯已开");} }class OffState implements State {@Overridepublic void handle() {System.out.println("灯已关");} }// 上下文(状态持有者) class LightSwitch {private State state;public void setState(State state) {this.state = state;}public void press() {state.handle();} }// 使用 public class Main {public static void main(String[] args) {LightSwitch light = new LightSwitch();light.setState(new OffState());light.press(); // 灯已关light.setState(new OnState());light.press(); // 灯已开} }
何时用:对象有多个状态且行为不同时。
优点:取代大量if-else
判断。
缺点:状态类数量多。
18. 命令模式(Command)
是什么:将请求封装为对象,支持撤销、排队。
例子:遥控器按键(每个按键对应一个命令)。
代码:
java
// 命令接口 interface Command {void execute(); }// 具体命令(开灯) class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();} }// 接收者(实际执行操作的对象) class Light {public void turnOn() {System.out.println("灯亮了");} }// 调用者(遥控器按钮) class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();} }// 使用 public class Main {public static void main(String[] args) {Light light = new Light();Command lightOn = new LightOnCommand(light);RemoteControl remote = new RemoteControl();remote.setCommand(lightOn);remote.pressButton(); // 灯亮了} }
何时用:需要记录操作历史或支持撤销时。
优点:解耦请求发起者和执行者。
缺点:命令类膨胀36。
19. 中介者模式(Mediator)
是什么:通过中介对象管理多个对象交互。
例子:聊天室(用户不直接对话,通过服务器中转)。
代码:
java
class ChatRoom {public static void send(User user, String msg) { /* 转发消息 */ } }
何时用:多对象交互复杂时。
优点:减少类间依赖。
缺点:中介类可能过于复杂。
20. 访问者模式(Visitor)
是什么:在不修改类的前提下,为类添加新操作。
例子:超市商品计价(不同商品类型用不同计价策略)。
代码:
java
// 元素接口(商品) interface Product {void accept(Visitor visitor); }// 具体元素 class Book implements Product {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public double getPrice() {return 50.0;} }// 访问者接口 interface Visitor {void visit(Book book); }// 具体访问者(价格计算) class PriceVisitor implements Visitor {@Overridepublic void visit(Book book) {System.out.println("书的价格:" + book.getPrice());} }// 使用 public class Main {public static void main(String[] args) {Product book = new Book();Visitor visitor = new PriceVisitor();book.accept(visitor); // 书的价格:50.0} }
何时用:需为复杂对象结构添加新功能时。
优点:符合开闭原则。
缺点:增加新元素类困难。
21. 备忘录模式(Memento)
是什么:保存对象状态,支持回滚。
例子:游戏存档。
代码:
java
复制
class Game {private String state;public Memento save() { return new Memento(state); }public void load(Memento m) { state = m.getState(); } }
何时用:需要撤销/恢复功能时。
优点:状态保存与业务逻辑分离。
缺点:消耗内存。
22. 迭代器模式(Iterator)
是什么:提供统一方式遍历集合元素。
例子:遍历书架的书籍(隐藏底层存储结构)。
代码:
java
复制
interface Iterator { boolean hasNext(); Object next(); }
何时用:需要统一遍历不同数据结构时。
优点:隐藏集合内部实现。
缺点:增加额外类。
23. 解释器模式(Interpreter)
是什么:定义语法规则,解释特定语言。
例子:SQL解析、数学表达式计算。
代码:
java
复制
interface Expression { int interpret(Context context); } class Add implements Expression {private Expression left, right;public int interpret(Context c) { return left.interpret(c) + right.interpret(c); } }
何时用:需要解析特定语法时。
优点:易于扩展语法规则。
缺点:复杂语法难维护。
四、模式对比与总结
1. 创建型模式对比
模式 | 核心思想 | 典型应用场景 |
---|---|---|
单例模式 | 全局唯一实例 | 配置管理、线程池 |
工厂方法 | 子类决定创建对象 | 物流运输、支付方式 |
抽象工厂 | 创建成套对象 | 跨平台UI组件库 |
建造者 | 分步骤构造复杂对象 | 自定义电脑配置 |
原型模式 | 克隆代替新建 | 游戏怪物生成 |
2. 行为型模式对比
对比总结
模式 | 核心区别 | 适用场景 |
---|---|---|
适配器 | 转换接口,让旧代码兼容新系统 | 接口不兼容 |
装饰器 | 动态添加功能,不修改原类 | 灵活扩展功能 |
代理 | 控制访问(权限、延迟加载) | 保护或优化访问 |
组合 | 统一处理树形结构的节点 | 菜单、文件系统 |
外观 | 简化复杂系统的调用入口 | 提供简洁接口 |
桥接 | 分离抽象和实现,避免类爆炸 | 多维度独立变化 |
享元 | 共享对象,减少内存占用 | 大量重复对象 |
如何选择:
-
要兼容接口?→ 适配器
-
动态加功能?→ 装饰器
-
控制访问?→ 代理
-
处理树形结构?→ 组合
-
简化复杂调用?→ 外观
-
避免多维继承?→ 桥接
-
节省内存?→ 享元
实际应用场景:
-
适配器:Java 的
InputStreamReader
将字节流转换为字符流。 -
装饰器:Java IO 中的
BufferedReader
包装FileReader
。 -
代理:Spring AOP 中的动态代理。
-
享元:Java 的
String
常量池。
3. 结构型模式对比
对比总结
模式 | 核心区别 | 适用场景 |
---|---|---|
策略模式 | 动态切换算法(如支付方式) | 多种算法需要灵活替换 |
观察者模式 | 一对多依赖通知(如消息订阅) | 对象状态变化通知其他对象 |
责任链模式 | 链式处理请求(如审批流程) | 请求需要多个对象处理 |
命令模式 | 封装请求为对象(如遥控器按钮) | 请求参数化、队列化 |
模板方法模式 | 固定流程,子类实现细节(如冲泡饮料) | 多个类有相同流程但不同步骤 |
状态模式 | 对象行为随状态改变(如电灯开关) | 对象状态影响行为 |
访问者模式 | 分离算法与对象结构(如统计商品价格) | 对复杂结构执行多种操作 |
如何选择:
-
需要动态切换算法 → 策略模式
-
状态变化通知其他对象 → 观察者模式
-
请求需要多级处理 → 责任链模式
-
封装请求为对象 → 命令模式
-
固定流程但有不同步骤 → 模板方法模式
-
行为随状态改变 → 状态模式
-
对复杂结构执行多种操作 → 访问者模式
实际应用场景:
-
策略模式:Java 的
Comparator
接口排序不同对象。 -
观察者模式:Java 的
Swing
事件监听。 -
责任链模式:Servlet 中的过滤器链。
-
命令模式:Java 的
Runnable
接口。
五、如何选择设计模式?
-
先明确问题类型:创建对象?组合结构?行为交互?
-
查看模式适用场景:如需要全局唯一实例→单例;需要灵活扩展算法→策略。
-
权衡优缺点:如单例节省内存但难扩展,工厂模式灵活但增加类数量。