这是我自己整理的一份设计模式速记。23 个模式按创建型、结构型、行为型分开,每个模式保留一句核心、一个能跑的小例子,最后把学习过程中卡住的问题汇成 Q&A。
代码是 Java,示例尽量短,能省的行都省了;个别片段补了 import,其余按需自行补。
| 类型 |
数量 |
关心什么 |
| 创建型 |
5 |
对象怎么来 |
| 结构型 |
7 |
对象怎么拼 |
| 行为型 |
11 |
对象怎么交互 |
口诀:创建型「抽工建单原」,结构型「桥适组装享外代」,其余是行为型。
- 抽工建单原 = 抽象工厂、工厂方法、建造者、单例、原型
- 桥适组装享外代 = 桥接、适配器、组合、装饰、享元、外观、代理
创建型模式
Factory 管“造哪个”,Abstract Factory 管“造一族”,Builder 管“怎么一步步造”,Prototype 管“照着造”,Singleton 管“只造一个”。
| 模式 |
核心 |
关键结构 |
| Factory Method |
子类决定 new 哪个 |
抽象工厂类 + 子类实现创建 |
| Abstract Factory |
创建一族相关对象 |
抽象工厂接口 + 多个产品接口 |
| Builder |
分步构造复杂对象 |
Builder + 链式调用 + build |
| Prototype |
克隆现成对象 |
clone / copy |
| Singleton |
全局唯一实例 |
私有构造 + 静态实例 |
1. Factory Method 工厂方法
父类定创建接口,子类决定 new 哪个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| interface Pay { void pay(); }
class WechatPay implements Pay { public void pay() { System.out.println("微信支付"); } }
class AliPay implements Pay { public void pay() { System.out.println("支付宝支付"); } }
abstract class PayFactory { abstract Pay createPay();
public void doPay() { Pay pay = createPay(); pay.pay(); } }
class WechatPayFactory extends PayFactory { Pay createPay() { return new WechatPay(); } }
class AliPayFactory extends PayFactory { Pay createPay() { return new AliPay(); } }
public class Main { public static void main(String[] args) { PayFactory factory = new WechatPayFactory(); factory.doPay(); } }
|
核心:创建延迟到子类。
2. Abstract Factory 抽象工厂
创建一族相关对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| interface Button { void render(); }
interface TextBox { void render(); }
class WinButton implements Button { public void render() { System.out.println("Windows 按钮"); } }
class WinTextBox implements TextBox { public void render() { System.out.println("Windows 文本框"); } }
class MacButton implements Button { public void render() { System.out.println("Mac 按钮"); } }
class MacTextBox implements TextBox { public void render() { System.out.println("Mac 文本框"); } }
interface UIFactory { Button createButton(); TextBox createTextBox(); }
class WinFactory implements UIFactory { public Button createButton() { return new WinButton(); } public TextBox createTextBox() { return new WinTextBox(); } }
class MacFactory implements UIFactory { public Button createButton() { return new MacButton(); } public TextBox createTextBox() { return new MacTextBox(); } }
public class Main { public static void main(String[] args) { UIFactory factory = new MacFactory(); factory.createButton().render(); factory.createTextBox().render(); } }
|
核心:一族产品一起换,不混搭。
工厂方法是一个方法创建一个产品;抽象工厂是一组方法创建一族产品。
3. Builder 建造者
分步构造复杂对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| class Computer { private String cpu; private String gpu; private int ram;
public void setCpu(String cpu) { this.cpu = cpu; }
public void setGpu(String gpu) { this.gpu = gpu; }
public void setRam(int ram) { this.ram = ram; }
public String toString() { return "CPU=" + cpu + ", GPU=" + gpu + ", RAM=" + ram + "G"; } }
class ComputerBuilder { private Computer computer = new Computer();
public ComputerBuilder cpu(String cpu) { computer.setCpu(cpu); return this; }
public ComputerBuilder gpu(String gpu) { computer.setGpu(gpu); return this; }
public ComputerBuilder ram(int ram) { computer.setRam(ram); return this; }
public Computer build() { return computer; } }
public class Main { public static void main(String[] args) { Computer pc = new ComputerBuilder() .cpu("i9") .gpu("RTX 4090") .ram(64) .build();
System.out.println(pc); } }
|
核心:构造过程分步,最后 build。
和工厂的区别:工厂关心“创建哪个”,Builder 关心“怎么一步步建”。
4. Prototype 原型
克隆一个现成对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| class Order implements Cloneable { private String product; private int count;
public Order(String product, int count) { this.product = product; this.count = count; }
public void setCount(int count) { this.count = count; }
@Override public Order clone() { try { return (Order) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } }
public String toString() { return "Order{product=" + product + ", count=" + count + "}"; } }
public class Main { public static void main(String[] args) { Order template = new Order("iPhone", 1);
Order order1 = template.clone(); order1.setCount(10);
Order order2 = template.clone(); order2.setCount(20);
System.out.println(template); System.out.println(order1); System.out.println(order2); } }
|
核心:以现有对象为模子复制新对象。
适合创建成本高、或需要保留母版再改副本的场景。
注意:Java 的 clone() 是浅拷贝,对象里有引用类型时要小心深拷贝。
5. Singleton 单例
全局只有一个实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class ConfigManager { private static volatile ConfigManager instance;
private ConfigManager() { }
public static ConfigManager getInstance() { if (instance == null) { synchronized (ConfigManager.class) { if (instance == null) { instance = new ConfigManager(); } } } return instance; }
public void load() { System.out.println("加载配置"); } }
public class Main { public static void main(String[] args) { ConfigManager c1 = ConfigManager.getInstance(); ConfigManager c2 = ConfigManager.getInstance();
c1.load(); System.out.println(c1 == c2); } }
|
核心:私有构造 + 静态实例 + 全局访问点。
更简单的写法:
1 2 3 4 5 6 7
| enum ConfigManager { INSTANCE;
public void load() { System.out.println("加载配置"); } }
|
枚举单例天然防反射、防序列化破坏,工程里更推荐。
结构型模式
结构型模式都在解决“对象怎么组合、怎么复用、怎么控制访问”。
| 模式 |
核心 |
| Adapter |
转接口 |
| Bridge |
拆维度 |
| Composite |
树形统一 |
| Decorator |
包一层加功能 |
| Facade |
统一入口 |
| Flyweight |
共享对象省内存 |
| Proxy |
控制访问 |
1. Adapter 适配器
接口不兼容,加个转接头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| interface OldPrinter { void printOld(String text); }
class OldPrinterImpl implements OldPrinter { public void printOld(String text) { System.out.println("老打印机:" + text); } }
interface NewPrinter { void print(String text); }
class PrinterAdapter implements NewPrinter { private OldPrinter oldPrinter;
public PrinterAdapter(OldPrinter oldPrinter) { this.oldPrinter = oldPrinter; }
public void print(String text) { oldPrinter.printOld(text); } }
public class Main { public static void main(String[] args) { NewPrinter printer = new PrinterAdapter(new OldPrinterImpl()); printer.print("Hello"); } }
|
核心:不改老代码,包一层转接口。
2. Bridge 桥接
抽象和实现分离,两个维度独立扩展。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| interface Color { String fill(); }
class Red implements Color { public String fill() { return "红色"; } }
class Blue implements Color { public String fill() { return "蓝色"; } }
abstract class Shape { protected Color color;
public Shape(Color color) { this.color = color; }
abstract void draw(); }
class Circle extends Shape { public Circle(Color color) { super(color); }
public void draw() { System.out.println("画一个 " + color.fill() + " 的圆"); } }
class Square extends Shape { public Square(Color color) { super(color); }
public void draw() { System.out.println("画一个 " + color.fill() + " 的方形"); } }
public class Main { public static void main(String[] args) { Shape redCircle = new Circle(new Red()); Shape blueSquare = new Square(new Blue());
redCircle.draw(); blueSquare.draw(); } }
|
核心:形状和颜色各自扩展,不搞类爆炸。
3. Composite 组合
树形结构,叶子/容器统一处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import java.util.ArrayList; import java.util.List;
interface FileSystemNode { void show(int depth); }
class FileNode implements FileSystemNode { private String name;
public FileNode(String name) { this.name = name; }
public void show(int depth) { System.out.println(" ".repeat(depth) + "文件:" + name); } }
class FolderNode implements FileSystemNode { private String name; private List<FileSystemNode> children = new ArrayList<>();
public FolderNode(String name) { this.name = name; }
public void add(FileSystemNode node) { children.add(node); }
public void show(int depth) { System.out.println(" ".repeat(depth) + "文件夹:" + name); for (FileSystemNode child : children) { child.show(depth + 1); } } }
public class Main { public static void main(String[] args) { FolderNode root = new FolderNode("root"); FolderNode docs = new FolderNode("docs"); docs.add(new FileNode("a.txt")); docs.add(new FileNode("b.txt")); root.add(docs); root.add(new FileNode("readme.md"));
root.show(0); } }
|
核心:文件和文件夹统一当节点处理,递归调用。
4. Decorator 装饰
不改进原类,包一层加功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| interface Coffee { String desc(); double cost(); }
class SimpleCoffee implements Coffee { public String desc() { return "普通咖啡"; }
public double cost() { return 10; } }
abstract class CoffeeDecorator implements Coffee { protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; } }
class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); }
public String desc() { return coffee.desc() + " + 奶"; }
public double cost() { return coffee.cost() + 2; } }
class SugarDecorator extends CoffeeDecorator { public SugarDecorator(Coffee coffee) { super(coffee); }
public String desc() { return coffee.desc() + " + 糖"; }
public double cost() { return coffee.cost() + 1; } }
public class Main { public static void main(String[] args) { Coffee coffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee())); System.out.println(coffee.desc() + ",价格:" + coffee.cost()); } }
|
核心:一层层包装,动态加功能,不改原类。
5. Facade 外观
给子系统一个统一入口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class CPU { void start() { System.out.println("CPU 启动"); } }
class Memory { void load() { System.out.println("内存加载"); } }
class Disk { void read() { System.out.println("磁盘读取"); } }
class ComputerFacade { private CPU cpu = new CPU(); private Memory memory = new Memory(); private Disk disk = new Disk();
public void start() { cpu.start(); memory.load(); disk.read(); System.out.println("电脑启动完成"); } }
public class Main { public static void main(String[] args) { new ComputerFacade().start(); } }
|
核心:封装复杂调用,对外只给一个简单接口。
6. Flyweight 享元
共享细粒度对象,省内存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import java.util.HashMap; import java.util.Map;
class ChessPiece { private String color;
public ChessPiece(String color) { this.color = color; }
public void put(int x, int y) { System.out.println(color + " 棋子放在 (" + x + "," + y + ")"); } }
class ChessPieceFactory { private static Map<String, ChessPiece> pool = new HashMap<>();
public static ChessPiece get(String color) { if (!pool.containsKey(color)) { pool.put(color, new ChessPiece(color)); } return pool.get(color); } }
public class Main { public static void main(String[] args) { ChessPiece black1 = ChessPieceFactory.get("黑"); ChessPiece black2 = ChessPieceFactory.get("黑"); ChessPiece white = ChessPieceFactory.get("白");
black1.put(1, 1); black2.put(2, 2); white.put(3, 3);
System.out.println(black1 == black2); } }
|
核心:内部状态共享,外部状态由调用方传入。
7. Proxy 代理
替原对象控制访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| 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); }
public void display() { System.out.println("显示图片:" + filename); } }
class ImageProxy implements Image { private String filename; private RealImage realImage;
public ImageProxy(String filename) { this.filename = filename; }
public void display() { if (realImage == null) { realImage = new RealImage(filename); } realImage.display(); } }
public class Main { public static void main(String[] args) { Image image = new ImageProxy("big.jpg"); System.out.println("第一次调用"); image.display(); System.out.println("第二次调用"); image.display(); } }
|
核心:代理控制对真实对象的访问,可加懒加载、权限、日志。
行为型模式
行为型模式都在解决“对象之间怎么交互、职责怎么分配、变化怎么隔离”。
| 模式 |
核心 |
| Interpreter |
语法变对象树,递归解释 |
| Template Method |
父类定流程,子类填步骤 |
| Chain of Responsibility |
请求沿链传,能处理就停 |
| Command |
请求封装成对象,可撤销可排队 |
| Iterator |
统一遍历,不暴露内部结构 |
| Mediator |
多对多走中介,变一对多 |
| Memento |
状态快照,随时恢复 |
| Observer |
一变多通知,发布订阅 |
| State |
状态决定行为,自动迁移 |
| Strategy |
算法族可互换,运行时切换 |
| Visitor |
数据与操作分离,加操作不改原类 |
1. Interpreter 解释器
解释自定义语法/表达式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| interface Expression { int interpret(); }
class Number implements Expression { private int value;
public Number(int value) { this.value = value; }
public int interpret() { return value; } }
class Add implements Expression { private Expression left; private Expression right;
public Add(Expression left, Expression right) { this.left = left; this.right = right; }
public int interpret() { return left.interpret() + right.interpret(); } }
class Sub implements Expression { private Expression left; private Expression right;
public Sub(Expression left, Expression right) { this.left = left; this.right = right; }
public int interpret() { return left.interpret() - right.interpret(); } }
public class Main { public static void main(String[] args) { Expression expr = new Sub( new Add(new Number(10), new Number(5)), new Number(3) ); System.out.println(expr.interpret()); } }
|
核心:把语法规则抽象成对象树,递归解释。
2. Template Method 模板方法
父类定骨架,子类填步骤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| abstract class Game { public final void play() { init(); start(); end(); }
protected abstract void init(); protected abstract void start(); protected abstract void end(); }
class Football extends Game { protected void init() { System.out.println("足球:热身"); } protected void start() { System.out.println("足球:开球"); } protected void end() { System.out.println("足球:终场"); } }
class Basketball extends Game { protected void init() { System.out.println("篮球:热身"); } protected void start() { System.out.println("篮球:跳球"); } protected void end() { System.out.println("篮球:终场"); } }
public class Main { public static void main(String[] args) { Game game = new Football(); game.play(); } }
|
核心:流程父类定,步骤子类填。
框架里的钩子方法就是这个套路。
3. Chain of Responsibility 责任链
请求沿链传,能处理就处理,否则下一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| abstract class Handler { protected Handler next;
public Handler setNext(Handler next) { this.next = next; return next; }
public abstract void handle(int level); }
class TeamLeader extends Handler { public void handle(int level) { if (level <= 1) { System.out.println("组长审批通过"); } else if (next != null) { next.handle(level); } } }
class Manager extends Handler { public void handle(int level) { if (level <= 2) { System.out.println("经理审批通过"); } else if (next != null) { next.handle(level); } } }
class Director extends Handler { public void handle(int level) { if (level <= 3) { System.out.println("总监审批通过"); } else { System.out.println("无人能审批"); } } }
public class Main { public static void main(String[] args) { Handler chain = new TeamLeader(); chain.setNext(new Manager()).setNext(new Director());
chain.handle(1); chain.handle(2); chain.handle(3); chain.handle(4); } }
|
核心:链式传递,谁合适谁处理,可中断可传递。
4. Command 命令
把请求封装成对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| interface Command { void execute(); void undo(); }
class Light { public void on() { System.out.println("灯打开"); }
public void off() { System.out.println("灯关闭"); } }
class LightOnCommand implements Command { private Light light;
public LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
public void undo() { light.off(); } }
class RemoteControl { private Command command;
public void setCommand(Command command) { this.command = command; }
public void press() { command.execute(); }
public void pressUndo() { command.undo(); } }
public class Main { public static void main(String[] args) { Light light = new Light(); RemoteControl remote = new RemoteControl();
remote.setCommand(new LightOnCommand(light)); remote.press(); remote.pressUndo(); } }
|
核心:请求变成对象,可存、可排队、可撤销、可记录日志。
5. Iterator 迭代器
统一遍历集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import java.util.Iterator; import java.util.NoSuchElementException;
class MyList<T> implements Iterable<T> { private Object[] data = new Object[10]; private int size = 0;
public void add(T item) { data[size++] = item; }
public Iterator<T> iterator() { return new Iterator<T>() { private int index = 0;
public boolean hasNext() { return index < size; }
@SuppressWarnings("unchecked") public T next() { if (!hasNext()) { throw new NoSuchElementException(); } return (T) data[index++]; } }; } }
public class Main { public static void main(String[] args) { MyList<String> list = new MyList<>(); list.add("A"); list.add("B"); list.add("C");
for (String s : list) { System.out.println(s); } } }
|
核心:遍历逻辑从集合里抽出来,调用方不关心内部结构。
对象不直接通信,走中介。
中介者模式是迪米特法则(Law of Demeter, LoD)(最少知识原则(Least Knowledge Principle, LKP))典型应用 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import java.util.ArrayList; import java.util.List;
class ChatRoom { private List<User> users = new ArrayList<>();
public void join(User user) { users.add(user); }
public void send(String message, User from) { for (User user : users) { if (user != from) { user.receive(message, from.getName()); } } } }
class User { private String name; private ChatRoom room;
public User(String name, ChatRoom room) { this.name = name; this.room = room; room.join(this); }
public String getName() { return name; }
public void send(String message) { System.out.println(name + " 发送:" + message); room.send(message, this); }
public void receive(String message, String from) { System.out.println(name + " 收到来自 " + from + " 的消息:" + message); } }
public class Main { public static void main(String[] args) { ChatRoom room = new ChatRoom(); User a = new User("Alice", room); User b = new User("Bob", room); User c = new User("Carol", room);
a.send("大家好"); } }
|
核心:多对多通信变一对多,同事类之间不直接引用。
7. Memento 备忘录
保存状态,之后恢复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| class Memento { private String state;
public Memento(String state) { this.state = state; }
public String getState() { return state; } }
class Editor { private String content = "";
public void type(String words) { content += words; }
public String getContent() { return content; }
public Memento save() { return new Memento(content); }
public void restore(Memento memento) { content = memento.getState(); } }
class History { private java.util.Stack<Memento> stack = new java.util.Stack<>();
public void push(Memento memento) { stack.push(memento); }
public Memento pop() { return stack.pop(); } }
public class Main { public static void main(String[] args) { Editor editor = new Editor(); History history = new History();
editor.type("Hello"); history.push(editor.save());
editor.type(" World"); history.push(editor.save());
editor.type("!!!"); System.out.println("当前:" + editor.getContent());
editor.restore(history.pop()); System.out.println("撤销一次:" + editor.getContent());
editor.restore(history.pop()); System.out.println("撤销两次:" + editor.getContent()); } }
|
核心:状态快照存到外部,需要时恢复,不破坏封装。
8. Observer 观察者
一变多通知,发布订阅。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import java.util.ArrayList; import java.util.List;
interface Observer { void update(String message); }
class NewsAgency { private List<Observer> observers = new ArrayList<>();
public void subscribe(Observer observer) { observers.add(observer); }
public void unsubscribe(Observer observer) { observers.remove(observer); }
public void publish(String news) { for (Observer observer : observers) { observer.update(news); } } }
class User implements Observer { private String name;
public User(String name) { this.name = name; }
public void update(String message) { System.out.println(name + " 收到新闻:" + message); } }
public class Main { public static void main(String[] args) { NewsAgency agency = new NewsAgency();
User a = new User("Alice"); User b = new User("Bob");
agency.subscribe(a); agency.subscribe(b);
agency.publish("今天有大事"); } }
|
核心:发布者不关心谁订阅,订阅者自动收到通知。
9. State 状态
状态决定行为,状态可迁移。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| interface State { void handle(Order order); }
class PendingState implements State { public void handle(Order order) { System.out.println("待支付:去支付"); order.setState(new PaidState()); } }
class PaidState implements State { public void handle(Order order) { System.out.println("已支付:去发货"); order.setState(new ShippedState()); } }
class ShippedState implements State { public void handle(Order order) { System.out.println("已发货:已完成"); order.setState(new DoneState()); } }
class DoneState implements State { public void handle(Order order) { System.out.println("已完成:不能再操作"); } }
class Order { private State state = new PendingState();
public void setState(State state) { this.state = state; }
public void next() { state.handle(this); } }
public class Main { public static void main(String[] args) { Order order = new Order(); order.next(); order.next(); order.next(); order.next(); } }
|
核心:状态自己决定下一步,避免一堆 if-else。
10. Strategy 策略
算法族可互换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| interface SortStrategy { void sort(int[] arr); }
class BubbleSort implements SortStrategy { public void sort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } } } } }
class QuickSort implements SortStrategy { public void sort(int[] arr) { java.util.Arrays.sort(arr); } }
class Sorter { private SortStrategy strategy;
public Sorter(SortStrategy strategy) { this.strategy = strategy; }
public void setStrategy(SortStrategy strategy) { this.strategy = strategy; }
public void sort(int[] arr) { strategy.sort(arr); } }
public class Main { public static void main(String[] args) { int[] arr = {5, 2, 8, 1};
Sorter sorter = new Sorter(new BubbleSort()); sorter.sort(arr); System.out.println(java.util.Arrays.toString(arr));
sorter.setStrategy(new QuickSort()); sorter.sort(arr); } }
|
核心:算法独立成类,运行时可换。
和 State 的区别:Strategy 是外部主动换算法;State 是状态自己决定行为。
11. Visitor 访问者
外部给对象加操作,不改原类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| import java.util.ArrayList; import java.util.List;
interface Visitor { void visit(FileNode file); void visit(FolderNode folder); }
interface Node { void accept(Visitor visitor); }
class FileNode implements Node { private String name; private int size;
public FileNode(String name, int size) { this.name = name; this.size = size; }
public String getName() { return name; }
public int getSize() { return size; }
public void accept(Visitor visitor) { visitor.visit(this); } }
class FolderNode implements Node { private String name; private List<Node> children = new ArrayList<>();
public FolderNode(String name) { this.name = name; }
public void add(Node node) { children.add(node); }
public String getName() { return name; }
public List<Node> getChildren() { return children; }
public void accept(Visitor visitor) { visitor.visit(this); } }
class SizeVisitor implements Visitor { private int total = 0;
public void visit(FileNode file) { total += file.getSize(); }
public void visit(FolderNode folder) { for (Node child : folder.getChildren()) { child.accept(this); } }
public int getTotal() { return total; } }
public class Main { public static void main(String[] args) { FolderNode root = new FolderNode("root"); FolderNode docs = new FolderNode("docs"); docs.add(new FileNode("a.txt", 10)); docs.add(new FileNode("b.txt", 20)); root.add(docs); root.add(new FileNode("readme.md", 5));
SizeVisitor visitor = new SizeVisitor(); root.accept(visitor); System.out.println("总大小:" + visitor.getTotal()); } }
|
核心:数据结构和操作分离,加新操作不改元素类。
常见问题
Q1:23 种设计模式怎么分类?
A:
- 创建型:管“对象怎么来”。
- 结构型:管“对象怎么拼”。
- 行为型:管“对象怎么交互”。
Q2:创建型五个怎么区分?
A:
- Factory Method:父类定创建接口,子类决定 new 哪个。
- Abstract Factory:创建一族相关对象。
- Builder:分步构造复杂对象。
- Prototype:克隆现成对象。
- Singleton:全局唯一实例。
一句话:工厂管“造哪个”,抽象工厂管“造一族”,Builder 管“怎么一步步造”,Prototype 管“照着造”,Singleton 管“只造一个”。
Q3:抽象工厂和工厂方法差不多?
A:像,但不一样。
- 工厂方法:创建一个产品。
- 抽象工厂:创建一族配套产品。
- 抽象工厂里每个
createX() 可以看作一个工厂方法。
- 但抽象工厂多了“产品族必须配套”的约束。
Q4:结构型七个怎么区分?
A:
- Adapter:转接口。
- Bridge:拆维度,用组合代替继承。
- Composite:树形结构,叶子/容器统一处理。
- Decorator:包一层加功能。
- Facade:统一入口,简化调用。
- Flyweight:共享对象,省内存。
- Proxy:控制对真实对象的访问。
Q5:Bridge 就是关联关系吗?
A:结构上常用关联/组合实现,但有关联不等于 Bridge。
Bridge 的关键是:两个独立变化的维度,各自扩展,避免继承爆炸。
Q6:Composite 为什么好用?
A:它把文件和文件夹统一成同一种节点。
调用方不用区分叶子和容器,递归处理即可。菜单树、组织架构、UI 容器都是这个套路。
Q7:Facade 和 Abstract Factory 能坐一桌吗?
A:都封装,但不是一类。
- Facade:结构型,简化调用,给子系统统一入口。
- Abstract Factory:创建型,封装创建一族对象。
Q8:Proxy 懒加载怎么理解?
A:代理层先暂存参数或条件,不急着创建真实对象。
第一次真正需要时才创建。核心就是:先记账,后干活。
Q9:Flyweight 工厂静态方法为什么能 new 非静态类?像单例吗?
A:static 方法属于类,可以 new 任意对象、访问静态成员。
Flyweight 按 key 共享多个对象;Singleton 全局只允许一个实例。像,但不一样。
Q10:行为型怎么记?
A:
- Interpreter:语法变对象树,递归解释。
- Template Method:父类定流程,子类填步骤。
- Chain of Responsibility:请求沿链传。
- Command:请求封装成对象。
- Iterator:统一遍历。
- Mediator:多对多走中介。
- Memento:状态快照。
- Observer:发布订阅。
- State:状态决定行为。
- Strategy:算法族可互换。
- Visitor:数据与操作分离。
Q11:解释器一定要用栈吗?像编译原理、状态机吗?
A:不一定用栈,递归或对象树也可以。
它像编译原理里“语法树 + 求值”那一小部分,不是完整编译器。
本质不是状态机,核心是语法树递归求值。
Q12:责任链里 next 没定义为什么能用?
A:next 定义在父类 Handler 里,通常是 protected 字段。
子类继承后可以直接访问。责任链本质就是手动拼了一个单向链表。
Q13:Command 不就是函数吗?
A:很多 Command 可以用函数、Runnable、Consumer 替代。
Command 多出来的是“对象化”:可排队、可撤销、可记录日志、可组合成宏命令。
Q14:增强 for 循环编译后会生成迭代器吗?
A:实现 Iterable 的集合会生成 Iterator。
数组的增强 for 编译后是普通下标循环。
Q15:群聊是不是 Mediator 实现的?
A:核心模型就是中介者。用户不直接互发,统一发给聊天室,聊天室转发。
真实群聊还涉及持久化、离线消息、多设备同步、消息顺序等,工程更复杂。
Q16:Memento 不就是栈吗?哈希表也可以?
A:Memento 是“状态快照对象”。
栈、HashMap 是存放快照的容器。
撤销常用 Stack<Memento>,存档可用 Map<String, Memento>。
Q17:Observer 名字绕,能叫分发节点吗?
A:可以。
Subject 就是发布者、事件源、分发节点。
Observer 就是订阅者、接收者、监听器。
Q18:Visitor 为什么绕?什么叫双重分派?
A:Java 是单分派,直接 visitor.visit(node) 不能按运行时类型走。
所以绕两次:
node.accept(visitor) 确定元素类型。
visitor.visit(this) 确定访问者类型。
好处:加新操作不改节点。
坏处:加新节点类型要改所有 Visitor。
Q19:Visitor 不适合 Java?工具类更好?
A:业务代码里,工具类静态方法通常更直白。
Visitor 适合:操作多、节点稳定、不想写 instanceof 的场景,比如编译器、解析器、代码分析。
Java 单分派导致 Visitor 绕;其他语言用动态分派、多分派、密封类 + 模式匹配替代。
Q20:一段代码能同时是多个模式吗?
A:能。模式是视角,不是互斥标签。
一个类可以同时是 Singleton、Facade,内部又用 Factory 和 Strategy。
Q21:Visitor 是不是语言补丁?
A:是。
它本质是在单分派语言里模拟多分派。
语言进步后,很多补丁被固化进语法,比如 Kotlin 的 sealed + when、Rust 的 enum + match。
Q22:Facade 门面模式是什么?
A:门面模式就是外观模式,同一个东西。
核心:对外给统一、稳定的高层接口,把内部复杂调用包起来。
平台对多产品接口耦合时,平台侧加 Facade 收口,产品只依赖 Facade。
Q23:产品要利用门面模式重构,谁重构?平台还是产品?
A:被依赖的公共底座重构,通常是平台侧。
思路:平台加 Facade,对外稳定,对内吸收变化。
产品只依赖 Facade,不再因平台内部接口变化而联动修改。
再进一步,可演进为插件化。