设计原则 1.SOLID 1.S-单一职责原则 类的设计要高内聚低耦合 ,一个类只有一个引发其变化的原因。
2.O-开闭原则 系统要扩展功能,而不是修改原有代码
3.L-里氏替换原则
子类必须能够代替父类,并保持其正确性
4.I-接口隔离原则 客户端不应该被迫依赖其不使用的方法
5.D-依赖倒置原则 高层模块不应该依赖低层模块,两者都应该依赖抽象。
2.其他设计原则 1.迪米特法则 一个对象应该对其他对象有尽可能少的了解。
降低耦合,避免过长调用链
2.合成复用原则 优先使用组合,而不是继承。
意义:继承是“强耦合”,组合更灵活。
设计模式 创建型模式 1.单例模式 核心思想 :某个类只有一个实例,并且提供一个全局访问点来获取这个实例。 结构 :构造器私有化 + 静态实例 + 全局访问方法。 适用场景 :配置对象、线程池、日志系统。 优点 :控制全局唯一对象,节省资源。 缺点 :全局状态可能导致代码难以测试。 应用 :Runtime.getRuntime(),Spring 默认 bean 单例。
1.饿汉式(Eager Initialization) 1 2 3 4 5 6 7 public class Singleton { private static final Singleton instance = new Singleton (); private Singleton () {} public static Singleton getInstance () { return instance; } }
特点:饿汉式在类加载时就创建对象,即在类的Initialization(加载)阶段创建。
优点:线程安全简单。
缺点:一开始就加载可能会导致内存浪费。
2.懒汉式(Lazy Initialization,线程不安全) 1 2 3 4 5 6 7 8 9 10 11 public class Singleton { private static Singleton instance; private Singleton () {} public static Singleton getInstance () { if (instance == null ) { instance = new Singleton (); } return instance; } }
特点:只有在需要用到这个实例时才进行第一次创建。
缺点:多线程环境下,可能有多个线程同时进入if(instance==null)中,导致创建多个实例。
3.懒汉式(线程安全版) 1 2 3 4 5 6 7 8 9 10 11 public class Singleton { private static Singleton instance; private Singleton () {} public static synchronized Singleton getInstance () { if (instance == null ) { instance = new Singleton (); } return instance; } }
在实例方法加锁
1 2 3 4 public synchronized void foo () { }
等价于
1 2 3 4 5 6 public void foo ( ) { synchronized (this ) { } }
在静态方法加锁
1 2 3 4 public static synchronized void bar () { }
等价于
1 2 3 4 5 6 public static void bar () { synchronized (Singleton.class ) { } }
特点:因此懒汉式的线程安全版加的是静态方法锁,即对整个类的对象加锁。
优点:线程安全
缺点:每次调用都需要加锁,效率低。
4.双重检查锁(DCL) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Singleton { private static volatile Singleton instance; private Singleton () {} public static Singleton getInstance () { if (instance == null ) { synchronized (Singleton.class) { if (instance == null ) { instance = new Singleton (); } } } return instance; } }
其中volatile关键字防止指令重排,在Java中创建一个对象可以大概分为三步:
1 2 3 4 memory = allocate(); // 1. 分配内存 ctorInstance(memory); // 2. 初始化对象instance = memory; // 3. 将 instance 指向内存
而JIT和CPU的指令重排会导致
1 2 3 memory = allocate(); // 1. 分配内存instance = memory; // 2. 将 instance 指向内存 ctorInstance(memory); // 3. 初始化对象
那么一个对象在if(instance==null)可能会直接return一个存在引用但是未初始化完成的对象。
优点:对比整体加锁,外层的if循环可以在已经存在实例时直接返回单例对象。
5.静态内部类 1 2 3 4 5 6 7 8 9 10 11 12 public class Singleton { private Singleton () {} private static class Holder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance () { return Holder.INSTANCE; } }
外部类 Singleton 的加载 当 JVM 加载 Singleton.class 时,并不会立即加载 Holder 类。 所以此时单例对象 还没有被创建 。
Holder 的加载与初始化 只有在第一次调用 Singleton.getInstance() 时,才会触发对 Holder 类的主动使用,从而导致 Holder 被 加载并初始化 。 在 Holder 初始化阶段,INSTANCE = new Singleton() 才会执行。
线程安全保证 JVM 在类的初始化阶段会保证:
<clinit>() 方法(即类的静态初始化逻辑)对同一个类只会被执行一次
并且是由 JVM 保证的 同步过程 因此不需要 synchronized,天然线程安全。
特点:采用了JVM的同步过程保证只会加载一次。
6.枚举类 1 2 3 4 5 6 7 public enum Singleton { INSTANCE; public void doSomething () { System.out.println("working..." ); } }
特点:天然防止反射和序列化破坏。反射破坏不了 (JVM 层面禁止),序列化也破坏不了 (JVM 自动处理)。
缺点:语义上可能不如类清晰。
SLF4J的单例模式 在LoggerFactory中我们可以得到一个存储各个类的ConcurrentHashMap,使用其保证每个类只有一个实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class LoggerFactory { private static final ConcurrentHashMap<String, Logger> loggerMap = new ConcurrentHashMap <>(); public static Logger getLogger (Class<?> clazz) { return getLogger(clazz.getName()); } public static Logger getLogger (String name) { Logger logger = loggerMap.get(name); if (logger != null ) { return logger; } logger = new Logger (name); Logger existingLogger = loggerMap.putIfAbsent(name, logger); return existingLogger != null ? existingLogger : logger; } }
对于每一个类创建唯一一个Logger对象,使用ConcurrentHashMap保持线程安全
1 2 3 4 5 private static final Logger logger = LoggerFactory.getLogger(ClassA.class);private static final Logger logger = LoggerFactory.getLogger(ClassB.class);
2.工厂方法模式 核心思想 :定义一个创建对象的接口,让子类决定实例化哪个类。结构 :抽象工厂接口 + 具体工厂实现。适用场景 :需要根据环境决定创建的对象。优点 :解耦对象创建和使用。缺点 :类数量增加。应用 :SLF4J的LoggerFactory,JDBC的DriverManager.getConnection()和Iterator<E> iteator()方法
工厂方法模式主要有以下角色:
Product(产品接口/抽象类) 定义产品的抽象(如 Button 接口)。
1 2 3 public interface Button { void render () ; }
ConcreteProduct(具体产品类) 实现 Product 接口(如 WindowsButton, MacButton)。
1 2 3 4 5 6 7 8 9 10 11 12 public class WindowsButton implements Button { public void render () { System.out.println("Render a Windows style button" ); } }public class MacButton implements Button { public void render () { System.out.println("Render a Mac style button" ); } }
Creator(抽象工厂/创建者) 声明工厂方法,返回 Product。
1 2 3 4 5 6 7 8 9 10 11 public abstract class Dialog { public abstract Button createButton () ; public void renderWindow () { Button okButton = createButton(); okButton.render(); } }
ConcreteCreator(具体工厂类) 实现工厂方法,返回具体的 ConcreteProduct。
1 2 3 4 5 6 7 8 9 10 11 public class WindowsDialog extends Dialog { public Button createButton () { return new WindowsButton (); } }public class MacDialog extends Dialog { public Button createButton () { return new MacButton (); } }
客户端实例化过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Client { public static void main (String[] args) { Dialog dialog; String os = System.getProperty("os.name" ).toLowerCase(); if (os.contains("win" )) { dialog = new WindowsDialog (); } else { dialog = new MacDialog (); } dialog.renderWindow(); } }
优点
符合 开闭原则 :新增产品时,只需要新增工厂类,不改原有代码。
客户端只依赖抽象,降低耦合。
容易扩展产品族。
缺点
每增加一个产品类,就要写一个新的工厂类,类的数量会增加。
结构比简单工厂复杂。
3.抽象工厂方法模式 抽象工厂模式是一种创建型设计模式 ,它提供一个接口,可以创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
AbstractProduct(抽象产品) 每个产品的抽象(例如 Button, Checkbox)。
1 2 3 4 5 6 7 8 9 10 public interface Button { void paint () ; }public interface Checkbox { void paint () ; }
ConcreteProduct(具体产品) 具体产品实现(如 WindowsButton, MacButton)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class WindowsButton implements Button { public void paint () { System.out.println("Render a button in Windows style." ); } }public class MacButton implements Button { public void paint () { System.out.println("Render a button in Mac style." ); } }public class WindowsCheckbox implements Checkbox { public void paint () { System.out.println("Render a checkbox in Windows style." ); } }public class MacCheckbox implements Checkbox { public void paint () { System.out.println("Render a checkbox in Mac style." ); } }
AbstractFactory(抽象工厂) 定义创建一组抽象产品的方法。
1 2 3 4 5 public interface GUIFactory { Button createButton () ; Checkbox createCheckbox () ; }
ConcreteFactory(具体工厂) 实现抽象工厂的方法,生产具体产品族。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class WindowsFactory implements GUIFactory { public Button createButton () { return new WindowsButton (); } public Checkbox createCheckbox () { return new WindowsCheckbox (); } }public class MacFactory implements GUIFactory { public Button createButton () { return new MacButton (); } public Checkbox createCheckbox () { return new MacCheckbox (); } }
Client(客户端) 通过抽象工厂获取产品,只依赖抽象,不关心具体实现。
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 public class Application { private Button button; private Checkbox checkbox; public Application (GUIFactory factory) { button = factory.createButton(); checkbox = factory.createCheckbox(); } public void render () { button.paint(); checkbox.paint(); } public static void main (String[] args) { GUIFactory factory; String os = System.getProperty("os.name" ).toLowerCase(); if (os.contains("win" )) { factory = new WindowsFactory (); } else { factory = new MacFactory (); } Application app = new Application (factory); app.render(); } }
4.建造者模式 建造者模式是一种将复杂对象的构造过程与表示分离的设计模式,使得同样的构建过程可以创建不同的表示。
内部静态类 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 public class House { private String foundation; private String walls; private String roof; private boolean hasGarage; private boolean hasGarden; private House (Builder builder) { this .foundation = builder.foundation; this .walls = builder.walls; this .roof = builder.roof; this .hasGarage = builder.hasGarage; this .hasGarden = builder.hasGarden; } public static class Builder { private String foundation; private String walls; private String roof; private boolean hasGarage; private boolean hasGarden; public Builder foundation (String foundation) { this .foundation = foundation; return this ; } public Builder walls (String walls) { this .walls = walls; return this ; } public Builder roof (String roof) { this .roof = roof; return this ; } public Builder garage (boolean hasGarage) { this .hasGarage = hasGarage; return this ; } public Builder garden (boolean hasGarden) { this .hasGarden = hasGarden; return this ; } public House build () { return new House (this ); } } @Override public String toString () { return "House [foundation=" + foundation + ", walls=" + walls + ", roof=" + roof + ", garage=" + hasGarage + ", garden=" + hasGarden + "]" ; } }
客户端 1 2 3 4 5 6 7 8 9 House house = new House .Builder() .foundation("Concrete" ) .walls("Brick" ) .roof("Tile" ) .garage(true ) .garden(false ) .build(); System.out.println(house);
✅ 优点
将复杂对象的构建和表示分离,代码更清晰。
支持链式调用,易读性强。
可以复用构造步骤,创建不同对象。
符合 单一职责原则 :Builder 负责构造,Product 负责表示。
❌ 缺点
类数量可能增多(传统写法需要多个 Builder、Director)。
不适合简单对象(会显得过度设计)。
Lombok 的 @Builder Lombok 通过在类或构造器/方法上加 @Builder,自动生成内部静态 Builder 类 ,省去手写 Builder 的麻烦。
1 2 3 4 5 6 7 8 9 10 11 12 import lombok.Builder;import lombok.ToString;@Builder @ToString public class User { private String name; private int age; private String email; private String password; }
编译后,Lombok 会帮你生成一个 UserBuilder 类,支持链式调用:
1 2 3 4 5 6 7 8 9 User user = User.builder() .name("Tom" ) .age(20 ) .email("tom@example.com" ) .password("123456" ) .build(); System.out.println(user);
StringBuilder 使用append()不断追加内容,最后通过toString()得到结果。StringBuilder 不是严格的 建造者模式 ,但用法上体现了 Builder 模式的思想 :链式构建、最后生成结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Main { public static void main (String[] args) { StringBuilder sb = new StringBuilder (); String result = sb.append("Hello" ) .append(", " ) .append("World" ) .append("!" ) .toString(); System.out.println(result); } }
5.原型模式 1. 浅拷贝(Shallow Copy)
拷贝对象本身,但引用类型属性只拷贝引用,不拷贝对象本身。
即 共享引用 。
可能会引发 改一处动全身 的问题
2. 深拷贝(Deep Copy)
不仅拷贝对象本身,还拷贝它引用的所有对象。
新对象完全独立,不会共享引用。
实现方法:
手写 clone(),在里面递归克隆引用对象。
或者通过序列化/反序列化实现。
Java中应用
很多框架(如 Spring)更推荐 拷贝构造函数 / 工具类(如 Apache Commons Lang 的 SerializationUtils.clone()) 来做深拷贝。
结构型模式 解决 对象和类如何组合 的问题。
6.适配器模式 核心思想 :将不兼容的接口转换为可用接口。 结构 :Adapter 包装 Adaptee。 适用场景 :老代码接口不兼容。 优点 :复用已有类。 缺点 :类层次复杂化。 应用 :InputStreamReader,Spring MVC 参数适配器。
类适配器(继承)
组合适配(持有引用)
Adapter 持有 Adaptee 的引用,转发调用。
更灵活(可以适配多个不同的 Adaptee)。
接口适配器
提供一个抽象类,实现接口的所有方法为空实现。
子类可以选择性地重写需要的方法。
常用于回调接口场景(比如 Java AWT/Swing 的监听器)。
Java中的标准适配器
java.util.Collections#list()不完全是适配器模式,要实现适配器模式类似于以下方式,将Enumeration转为Iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class EnumerationIterator <T> implements Iterator <T> { private Enumeration<T> enumeration; public EnumerationIterator (Enumeration<T> enumeration) { this .enumeration = enumeration; } @Override public boolean hasNext () { return enumeration.hasMoreElements(); } @Override public T next () { return enumeration.nextElement(); } }
java的实现例子 让方钉适配圆孔
圆孔:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package refactoring_guru.adapter.example.round;public class RoundHole { private double radius; public RoundHole (double radius) { this .radius = radius; } public double getRadius () { return radius; } public boolean fits (RoundPeg peg) { boolean result; result = (this .getRadius() >= peg.getRadius()); return result; } }
圆钉:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package refactoring_guru.adapter.example.round;public class RoundPeg { private double radius; public RoundPeg () {} public RoundPeg (double radius) { this .radius = radius; } public double getRadius () { return radius; } }
方钉:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package refactoring_guru.adapter.example.square;public class SquarePeg { private double width; public SquarePeg (double width) { this .width = width; } public double getWidth () { return width; } public double getSquare () { double result; result = Math.pow(this .width, 2 ); return result; } }
适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package refactoring_guru.adapter.example.adapters;import refactoring_guru.adapter.example.round.RoundPeg;import refactoring_guru.adapter.example.square.SquarePeg;public class SquarePegAdapter extends RoundPeg { private SquarePeg peg; public SquarePegAdapter (SquarePeg peg) { this .peg = peg; } @Override public double getRadius () { double result; result = (Math.sqrt(Math.pow((peg.getWidth() / 2 ), 2 ) * 2 )); return result; } }
客户端
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 package refactoring_guru.adapter.example;import refactoring_guru.adapter.example.adapters.SquarePegAdapter;import refactoring_guru.adapter.example.round.RoundHole;import refactoring_guru.adapter.example.round.RoundPeg;import refactoring_guru.adapter.example.square.SquarePeg;public class Demo { public static void main (String[] args) { RoundHole hole = new RoundHole (5 ); RoundPeg rpeg = new RoundPeg (5 ); if (hole.fits(rpeg)) { System.out.println("Round peg r5 fits round hole r5." ); } SquarePeg smallSqPeg = new SquarePeg (2 ); SquarePeg largeSqPeg = new SquarePeg (20 ); SquarePegAdapter smallSqPegAdapter = new SquarePegAdapter (smallSqPeg); SquarePegAdapter largeSqPegAdapter = new SquarePegAdapter (largeSqPeg); if (hole.fits(smallSqPegAdapter)) { System.out.println("Square peg w2 fits round hole r5." ); } if (!hole.fits(largeSqPegAdapter)) { System.out.println("Square peg w20 does not fit into round hole r5." ); } } }
✅ 优点
解耦:客户端和被适配类解耦。
复用:复用已有功能,无需改源码。
灵活:对象适配器方式支持组合多个适配对象。
❌ 缺点
增加了系统复杂度,多了一层转换。
类适配器方式受限于单继承。
7.装饰器模式 核心思想 :在不修改对象代码的前提下动态添加功能。 结构 :Decorator 包含被装饰对象。 适用场景 :多层功能增强。 优点 :比继承更灵活。 缺点 :多层装饰会难以调试。 应用 :Java I/O 流。
在不改变原有对象结构的前提下,动态地给对象增加新的功能。
它通过“包装”一个对象来增强功能,而不是通过继承。
使用同一个接口,保证客户端无感知。
java实现例子 1 2 3 4 5 6 7 8 9 10 interface Component { void operation () ; }class ConcreteComponent implements Component { public void operation () { System.out .println("执行基本操作" ); } }
抽象装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 abstract class Decorator implements Component { protected Component component; public Decorator (Component component) { this .component = component; } @Override public void operation () { component.operation(); } }
具体装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class LoggingDecorator extends Decorator { public LoggingDecorator (Component component) { super (component); } @Override public void operation() { System .out.println("记录日志..." ); super .operation(); } }class SecurityDecorator extends Decorator { public SecurityDecorator (Component component) { super (component); } @Override public void operation() { System .out.println("检查权限..." ); super .operation(); } }
客户端使用
1 2 3 4 5 6 7 8 9 10 public class Client { public static void main (String[] args) { Component c = new ConcreteComponent (); Component decorated = new LoggingDecorator (new SecurityDecorator (c)); decorated.operation(); } }
现实例子 Java IO
Spring
Spring AOP 的 BeanPostProcessor 本质上也是装饰思想:在 Bean 初始化前后加功能。
GUI 框架
滚动条装饰器 ScrollBarDecorator 可以给窗口动态加滚动条。
✅ 优点
扩展性强 :不修改原有类就能添加功能。
灵活组合 :不同装饰器可以任意组合。
遵循开闭原则 :对扩展开放,对修改关闭。
❌ 缺点
对象层层包装,调试时可能比较复杂。
装饰链过长时,可能影响性能和可读性。
8.代理模式 核心思想 :通过代理对象控制对真实对象的访问。 结构 :Proxy 持有 RealSubject。 适用场景 :远程代理、安全代理、延迟加载。 优点 :控制访问、增强功能。 缺点 :增加层级,可能影响性能。 应用 :Spring AOP、JDK 动态代理。
定义接口
1 2 3 4 interface Subject { void request () ; }
真实主题
1 2 3 4 5 6 7 class RealSubject implements Subject { @Override public void request() { System.out.println("执行真实请求" ); } }
代理主题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Proxy implements Subject { private RealSubject realSubject; @Override public void request () { System.out .println("检查权限..." ); if (realSubject == null ) { realSubject = new RealSubject(); } realSubject.request(); System.out .println("记录日志..." ); } }
客户端
1 2 3 4 5 6 7 public class Client { public static void main (String [] args ) { Subject proxy = new Proxy (); proxy.request (); } }
代理模式类型
静态代理
编译期就写死了代理类。
缺点:如果接口很多,需要写很多代理类。
动态代理
JDK 动态代理 :基于 InvocationHandler + 反射,要求被代理对象必须实现接口。
CGLIB 动态代理 :基于字节码生成,可以代理没有实现接口的类。
Spring AOP 就是基于 动态代理 实现的。
✅ 优点
控制访问:隔离客户端与真实对象。
可扩展:代理可在不修改真实对象的前提下增强功能。
提高灵活性:支持远程调用、懒加载等模式。
❌ 缺点
可能增加系统复杂度。
动态代理可能影响性能(尤其是反射和字节码生成)。
9.外观模式 子系统
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 TV { public void on () { System.out .println("TV is on" ); } public void off () { System.out .println("TV is off" ); } }class SoundSystem { public void on () { System.out .println("Sound system is on" ); } public void off () { System.out .println("Sound system is off" ); } public void setVolume (int volume ) { System.out .println("Setting volume to " + volume); } }class DVDPlayer { public void on () { System.out .println("DVD player is on" ); } public void off () { System.out .println("DVD player is off" ); } public void playMovie (String movie ) { System.out .println("Playing movie: " + movie); } }
外观
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 public class HomeTheaterFacade { private TV tv; private SoundSystem soundSystem; private DVDPlayer dvdPlayer; public HomeTheaterFacade () { this .tv = new TV(); this .soundSystem = new SoundSystem(); this .dvdPlayer = new DVDPlayer(); } public void watchMovie (String movie ) { System.out .println("准备进入电影模式..." ); tv.on (); soundSystem.on (); soundSystem.setVolume(15 ); dvdPlayer.on (); dvdPlayer.playMovie(movie); System.out .println("电影模式准备就绪!" ); } public void endMovie () { System.out .println("准备退出电影模式..." ); dvdPlayer.off(); soundSystem.off(); tv.off(); System.out .println("所有设备已关闭。" ); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Client { public static void main (String[] args ) { HomeTheaterFacade homeTheater = new HomeTheaterFacade(); homeTheater.watchMovie("The Matrix" ); System.out .println("\n----------------\n" ); homeTheater.endMovie(); } }
Spring 框架
JdbcTemplate、RedisTemplate、RestTemplate 就是外观模式的应用: 它们对复杂的数据库操作、Redis 操作、HTTP 调用进行了封装,客户端只需调用简单方法。
日志框架(SLF4J)
LoggerFactory.getLogger() 就是外观,底层可能是 Logback、Log4j,但客户端只依赖统一接口。
电脑开机
按下电源键(Facade) → 调用 CPU、内存、硬盘等子系统。
API Gateway(微服务网关)
✅ 优点
简化调用 :屏蔽复杂性,让客户端更容易使用系统。
降低耦合 :客户端与子系统解耦,只依赖 Facade。
更安全 :外观类可以控制客户端访问的子系统范围。
❌ 缺点
可能成为“上帝类”,职责过多。
增加了一层间接调用,灵活性降低(客户端无法访问到子系统的所有功能)。
10.桥接模式 核心思想 :将抽象与实现分离,使它们可以独立变化,解决组合爆炸问题。 结构 :Abstraction 持有 Implementor。 适用场景 :多维度扩展(颜色+形状)。 优点 :避免类爆炸。 缺点 :增加抽象层。 应用 :JDBC 接口 + 驱动实现。
具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 interface MessageSender { void sendMessage (String message); }class EmailMessageSender implements MessageSender { @Override public void sendMessage (String message ) { System .out .println ("通过邮件发送消息: " + message); } }class SMSMessageSender implements MessageSender { @Override public void sendMessage (String message ) { System .out .println ("通过短信发送消息: " + message); } }
抽象层
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 abstract class Message { protected MessageSender sender; public Message (MessageSender sender) { this .sender = sender; } public abstract void send(String text); }class NormalMessage extends Message { public NormalMessage (MessageSender sender) { super (sender); } @Override public void send(String text) { sender.sendMessage(text); } }class UrgentMessage extends Message { public UrgentMessage (MessageSender sender) { super (sender); } @Override public void send(String text) { text = "加急:" + text; sender.sendMessage(text); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 public class Client { public static void main (String[] args) { Message normalMessage = new NormalMessage (new EmailMessageSender ()); normalMessage.send("这是一条普通消息。" ); Message urgentMessage = new UrgentMessage (new SMSMessageSender ()); urgentMessage.send("这是一条加急消息。" ); } }
✅ 优点
避免类爆炸,降低继承层次。
抽象与实现可以独立扩展,互不影响。
符合开闭原则。
❌ 缺点
增加了系统复杂性(要多设计一层 Implementor)。
适合变化维度明显的场景,不适合单一维度系统。
11.组合模式 核心思想 :将对象组合成树形结构,使用户对单个对象和组合对象使用一致接口。 结构 :Component → Leaf / Composite。 适用场景 :层次结构(文件夹/文件)。 优点 :一致性操作。 缺点 :难以限制组合层次。 应用 :Swing 组件树、XML DOM。
抽象组件
1 2 3 interface FileSystemNode { void show () ; }
叶子节点
1 2 3 4 5 6 7 8 9 10 11 12 13 class FileNode implements FileSystemNode { private String name; public FileNode (String name) { this .name = name; } @Override public void show () { System.out.println("文件: " + name); } }
容器节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.ArrayList;import java.util.List;class DirectoryNode implements FileSystemNode { private String name; private List<FileSystemNode> children = new ArrayList <>(); public DirectoryNode (String name) { this .name = name; } public void add (FileSystemNode node) { children.add(node); } @Override public void show () { System.out.println("目录: " + name); for (FileSystemNode child : children) { child.show(); } } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Client { public static void main (String[] args) { FileSystemNode file1 = new FileNode ("a.txt" ); FileSystemNode file2 = new FileNode ("b.txt" ); DirectoryNode folder = new DirectoryNode ("docs" ); folder.add(file1); folder.add(file2); DirectoryNode root = new DirectoryNode ("root" ); root.add(folder); root.add(new FileNode ("c.txt" )); root.show(); } }
文件系统
组织架构
员工(Leaf)和部门(Composite)都实现 OrganizationUnit 接口。
菜单系统(GUI)
菜单项(Leaf)和子菜单(Composite)统一处理。
图形绘制系统
线段、圆形(Leaf),组合图形(Composite)。
✅ 优点
统一性 :客户端可以统一处理单个对象和组合对象。
扩展性强 :新增叶子节点或组合节点时,不影响已有代码。
层次结构清晰 :天然适合树形数据表示。
❌ 缺点
系统会产生过多的细粒度对象(节点多时内存占用高)。
控制粒度可能变弱(比如有些方法只适用于叶子,但接口统一后容易被误用)。
12.享元模式 核心思想 :共享对象,减少内存消耗。 结构 :FlyweightFactory 管理共享对象。 适用场景 :大量细粒度对象(字符、棋子)。 优点 :节省内存。 缺点 :逻辑复杂化。 应用 :Integer.valueOf() 缓存,JVM 字符串常量池。
抽象享元
1 2 3 4 interface Flyweight { void operation (String extrinsicState) ; }
具体享元
1 2 3 4 5 6 7 8 9 10 11 12 13 class ConcreteFlyweight implements Flyweight { private final String intrinsicState; public ConcreteFlyweight (String intrinsicState) { this .intrinsicState = intrinsicState; } @Override public void operation (String extrinsicState) { System.out.println("内部状态: " + intrinsicState + ",外部状态: " + extrinsicState); } }
享元工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.HashMap;import java.util.Map;class FlyweightFactory { private final Map<String, Flyweight> pool = new HashMap <>(); public Flyweight getFlyweight (String key) { if (!pool.containsKey(key)) { pool.put(key, new ConcreteFlyweight (key)); } return pool.get(key); } public int poolSize () { return pool.size(); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Client { public static void main (String[] args) { FlyweightFactory factory = new FlyweightFactory (); Flyweight f1 = factory.getFlyweight("A" ); Flyweight f2 = factory.getFlyweight("A" ); Flyweight f3 = factory.getFlyweight("B" ); f1.operation("位置1" ); f2.operation("位置2" ); f3.operation("位置3" ); System.out.println("享元池大小: " + factory.poolSize()); } }
Java String 常量池
"abc" 字符串字面量会被放入常量池,复用相同字符串对象。
Java Integer 缓存
Integer.valueOf(127) 总是返回缓存对象,避免频繁创建。
数据库连接池、线程池
字体渲染、图标缓存
文本编辑器中重复出现的字符、图标只创建一个对象,位置作为外部状态。
游戏对象
✅ 优点
大大减少内存中对象的数量,提升性能。
共享对象更容易集中管理,节省系统资源。
❌ 缺点
引入了区分内部状态和外部状态的复杂性。
外部状态需要由客户端维护,增加了使用成本。
过度使用可能导致系统结构不清晰。
行为型模式 观察者模式 核心思想 :对象状态改变时通知所有依赖者。 结构 :Subject + Observer。 适用场景 :事件订阅。 优点 :解耦发布与订阅。 缺点 :链式通知可能影响性能。 应用 :Java Observer,GUI 事件监听。
基础发布者
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 package refactoring_guru.observer.example.publisher;import refactoring_guru.observer.example.listeners.EventListener;import java.io.File;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class EventManager { Map<String, List<EventListener>> listeners = new HashMap <>(); public EventManager (String... operations) { for (String operation : operations) { this .listeners.put(operation, new ArrayList <>()); } } public void subscribe (String eventType, EventListener listener) { List<EventListener> users = listeners.get(eventType); users.add(listener); } public void unsubscribe (String eventType, EventListener listener) { List<EventListener> users = listeners.get(eventType); users.remove(listener); } public void notify (String eventType, File file) { List<EventListener> users = listeners.get(eventType); for (EventListener listener : users) { listener.update(eventType, file); } } }
具体发布者
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 package refactoring_guru.observer.example.editor;import refactoring_guru.observer.example.publisher.EventManager;import java.io.File;public class Editor { public EventManager events; private File file; public Editor () { this .events = new EventManager ("open" , "save" ); } public void openFile (String filePath) { this .file = new File (filePath); events.notify("open" , file); } public void saveFile () throws Exception { if (this .file != null ) { events.notify("save" , file); } else { throw new Exception ("Please open a file first." ); } } }
✅ 优点
解耦 :主题和观察者之间是抽象依赖,不直接耦合。
灵活扩展 :增加新的观察者无需修改主题代码。
支持广播通信 :一个事件可以通知多个对象。
❌ 缺点
性能问题 :观察者数量多时,通知会很耗时。
通知链复杂 :若观察者之间有依赖,可能引发级联更新,难以调试。
内存泄漏风险 :如果观察者忘记移除引用,可能导致对象无法被回收。
策略模式 核心思想 :封装一系列算法,使它们可以互换。 结构 :Context + Strategy。 适用场景 :不同算法可替换。 优点 :避免大量 if-else。 缺点 :客户端必须知道所有策略。 应用 :支付方式选择。
定义一系列算法(策略),将每个算法封装起来,并使它们可以相互替换,让算法的变化独立于使用它的客户端。
📌 简单说:
把 if-else/switch 拆出来 ,封装成可替换的策略类。
客户端只依赖抽象策略,具体实现由外部注入。
环境类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class PayContext { private PayStrategy strategy; public PayContext (PayStrategy strategy) { this .strategy = strategy; } public void setStrategy (PayStrategy strategy) { this .strategy = strategy; } public void execute (double amount) { strategy.pay(amount); } }
策略接口
1 2 3 4 interface PayStrategy { void pay (double amount) ; }
具体策略类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class AliPay implements PayStrategy { @Override public void pay (double amount) { System.out.println("使用支付宝支付:" + amount + " 元" ); } }class WeChatPay implements PayStrategy { @Override public void pay (double amount) { System.out.println("使用微信支付:" + amount + " 元" ); } }class CreditCardPay implements PayStrategy { @Override public void pay (double amount) { System.out.println("使用信用卡支付:" + amount + " 元" ); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Client { public static void main (String[] args) { PayContext context = new PayContext (new AliPay ()); context.execute(100 ); context.setStrategy(new WeChatPay ()); context.execute(200 ); context.setStrategy(new CreditCardPay ()); context.execute(300 ); } }
Java 8 开始支持 lambda 方法, 它可作为一种替代策略模式的简单方式。
这里有一些核心 Java 程序库中策略模式的示例:
✅ 优点
遵循 开闭原则 :新增策略不需要改 Context。
避免大量 if-else。
算法可自由切换,灵活性高。
策略类可以复用。
❌ 缺点
会增加类的数量,每个策略都是一个类。
客户端必须了解不同策略的区别,才能正确选择。
如果策略过多,维护成本可能变高。
责任链模式 核心思想 :多个对象依次处理请求,直到被处理。 结构 :Handler 链。 适用场景 :请求过滤、拦截器。 优点 :解耦请求与处理者。 缺点 :调试困难,可能无人处理请求。 应用 :Servlet 过滤器链,日志框架。
Handler(抽象处理者)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 abstract class Approver { protected Approver next; protected String name; public Approver (String name) { this .name = name; } public void setNext (Approver next) { this .next = next; } public abstract void approve (int days) ; }
ConcreteHandler(具体处理者)
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 class TeamLeader extends Approver { public TeamLeader (String name) { super (name); } @Override public void approve (int days) { if (days <= 1 ) { System.out.println(name + " 批准了 " + days + " 天假" ); } else if (next != null ) { next.approve(days); } } }class Manager extends Approver { public Manager (String name) { super (name); } @Override public void approve (int days) { if (days <= 3 ) { System.out.println(name + " 批准了 " + days + " 天假" ); } else if (next != null ) { next.approve(days); } } }class Director extends Approver { public Director (String name) { super (name); } @Override public void approve (int days) { if (days <= 7 ) { System.out.println(name + " 批准了 " + days + " 天假" ); } else if (next != null ) { next.approve(days); } } }class CEO extends Approver { public CEO (String name) { super (name); } @Override public void approve (int days) { System.out.println(name + " 批准了 " + days + " 天假" ); } }
Client(客户端)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Client { public static void main (String[] args) { Approver leader = new TeamLeader ("组长" ); Approver manager = new Manager ("经理" ); Approver director = new Director ("总监" ); Approver ceo = new CEO ("CEO" ); leader.setNext(manager); manager.setNext(director); director.setNext(ceo); leader.approve(1 ); leader.approve(3 ); leader.approve(5 ); leader.approve(10 ); } }
Java Servlet Filter(过滤器链)
Spring AOP 拦截器链
日志处理
审批流程、工作流引擎
✅ 优点
遵循 开闭原则 :新增处理者只需要加类,不影响现有逻辑。
请求和处理逻辑解耦,灵活性高。
可以动态组合处理链。
❌ 缺点
如果链太长,请求可能会经过很多节点才被处理,效率低。
不保证一定会被处理(可能没人接收)。
调试和追踪较麻烦。
状态模式 核心思想 :对象行为随内部状态改变而改变。 结构 :Context + State。 适用场景 :状态机。 优点 :消除 if-else。 缺点 :类数量增加。 应用 :TCP 连接状态。
Context(环境类)
持有状态对象。
对外提供接口,但内部调用委托给当前状态对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class OrderContext { private OrderState state ; public OrderContext() { this.state = new PendingPayment(); // 初始状态 } public void set State(OrderState state ) { this.state = state ; } public void request() { state .handle(this); } }
State(抽象状态)
1 2 3 4 interface OrderState { void handle(OrderContext context); }
ConcreteState(具体状态)
实现具体状态下的逻辑。
可以决定是否切换到其他状态。
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 class PendingPayment implements OrderState { @Override public void handle (OrderContext context) { System.out.println("订单待支付,执行支付操作..." ); context.setState(new Paid ()); } }class Paid implements OrderState { @Override public void handle (OrderContext context) { System.out.println("订单已支付,执行发货操作..." ); context.setState(new Shipped ()); } }class Shipped implements OrderState { @Override public void handle (OrderContext context) { System.out.println("订单已发货,执行确认收货操作..." ); context.setState(new Completed ()); } }class Completed implements OrderState { @Override public void handle (OrderContext context) { System.out.println("订单已完成,不可操作。" ); } }
✅ 优点
遵循 开闭原则 :新增状态不影响已有逻辑。
状态切换逻辑清晰,避免大量 if-else。
把与状态相关的行为封装在独立类里,职责清晰。
❌ 缺点
状态类数量可能过多,增加系统复杂度。
状态切换的逻辑分散在各个状态类里,维护时可能比较麻烦。
命令模式 核心思想 :将请求封装为对象,支持撤销/排队操作。 结构 :Invoker + Command + Receiver。 适用场景 :事务、日志操作。 优点 :解耦请求与执行。 缺点 :类数量增加。 应用 :GUI 按钮命令,数据库事务日志。
抽象命令接口
1 2 3 4 5 interface Command { void execute () ; void undo () ; }
具体命令
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 class LightOnCommand implements Command { private Light light; public LightOnCommand (Light light) { this .light = light; } @Override public void execute ( ) { light.turnOn (); } @Override public void undo ( ) { light.turnOff (); } }class LightOffCommand implements Command { private Light light; public LightOffCommand (Light light) { this .light = light; } @Override public void execute ( ) { light.turnOff (); } @Override public void undo ( ) { light.turnOn (); } }
接收者
1 2 3 4 5 6 7 8 9 10 class Light { public void turnOn () { System.out.println("电灯已打开" ); } public void turnOff () { System.out.println("电灯已关闭" ); } }
调用者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class RemoteControl { private Command command; public void setCommand (Command command) { this .command = command; } public void pressButton () { command.execute(); } public void pressUndo () { command.undo(); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Client { public static void main (String[] args) { Light light = new Light (); Command lightOn = new LightOnCommand (light); Command lightOff = new LightOffCommand (light); RemoteControl remote = new RemoteControl (); remote.setCommand(lightOn); remote.pressButton(); remote.pressUndo(); remote.setCommand(lightOff); remote.pressButton(); remote.pressUndo(); } }
✅ 优点
解耦 :调用者与接收者解耦,扩展性高。
开闭原则 :新增命令只需增加类,不影响已有代码。
可撤销/重做 :命令对象可记录历史,支持回滚。
组合命令 :可实现宏命令(多个命令一起执行)。
❌ 缺点
会增加类的数量(每个命令一个类)。
如果命令过多,代码结构可能比较复杂。
迭代器模式 核心思想 :顺序访问集合元素而不暴露内部结构。 结构 :Iterator 接口 + Aggregate。 适用场景 :集合遍历。 优点 :统一遍历方式。 缺点 :额外开销。 应用 :Java 的 Iterator 接口。
提供一种方法,顺序访问聚合对象中的各个元素,而不暴露其内部表示。
📌 通俗说:
不管集合是数组、链表还是树,用户只需要用迭代器按顺序取元素,不必关心内部数据结构 。
集合类负责存储数据,迭代器负责遍历数据。
Java接口
1 2 3 4 5 6 List<String> list = new ArrayList <>(); Iterator<String> it = list.iterator();while (it.hasNext()) { System.out.println(it.next()); }
✅ 优点
遵循 单一职责原则 :集合负责存储,迭代器负责遍历。
封装性好:不用暴露集合的内部结构。
可扩展性强:支持多种遍历方式(正向、反向、跳跃)。
❌ 缺点
迭代器对象会额外消耗内存。
如果集合被修改,迭代器可能失效(Java 的 fail-fast 机制)。
备忘录模式 核心思想 :保存对象内部状态,支持撤销。 结构 :Originator + Memento + Caretaker。 适用场景 :编辑器撤销、游戏存档。 优点 :封装状态。 缺点 :内存消耗大。 应用 :IDE Undo 功能。
发起人
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 class TextEditor { private String content; public void setContent (String content) { this .content = content; } public String getContent () { return content; } public Memento save () { return new Memento (content); } public void restore (Memento memento) { this .content = memento.getContent(); } public static class Memento { private final String content; private Memento (String content) { this .content = content; } private String getContent () { return content; } } }
管理人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Caretaker { private Stack<TextEditor.Memento> history = new Stack <>(); public void save (TextEditor editor) { history.push(editor.save()); } public void undo (TextEditor editor) { if (!history.isEmpty()) { editor.restore(history.pop()); } } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Client { public static void main (String[] args ) { TextEditor editor = new TextEditor(); Caretaker caretaker = new Caretaker(); editor.setContent("第一次输入" ); caretaker.save(editor); editor.setContent("第二次输入" ); caretaker.save(editor); editor.setContent("第三次输入" ); System.out .println("当前内容: " + editor.getContent()); caretaker.undo(editor); System.out .println("撤销一次: " + editor.getContent()); caretaker.undo(editor); System.out .println("撤销两次: " + editor.getContent()); } }
✅ 优点
封装性好:不暴露对象的内部细节。
简化了发起人:只需要保存/恢复,不关心历史的管理。
符合 单一职责原则 :状态的存储交给备忘录,历史管理交给看护者。
❌ 缺点
可能消耗大量内存(如果频繁保存状态)。
在复杂对象里,备份状态的开销可能很大。
如果需要支持“增量存档”,实现会变复杂。
解释器模式 核心思想 :为语言定义文法,并解释执行。 结构 :Expression 接口 + Terminal/NonTerminal。 适用场景 :简单语言解析。 优点 :扩展性强。 缺点 :复杂文法难以维护。 应用 :正则表达式解析器。
抽象表达式
1 2 3 4 interface Expression { boolean interpret (Map <String , Boolean > context); }
终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 class VariableExpression implements Expression { private String name; public VariableExpression (String name) { this .name = name; } @Override public boolean interpret (Map <String , Boolean > context ) { return context.get (name); } }
非终结符表达式
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 AndExpression implements Expression { private Expression left, right; public AndExpression (Expression left, Expression right) { this .left = left; this .right = right; } @Override public boolean interpret (Map <String , Boolean > context ) { return left.interpret (context) && right.interpret (context); } }class OrExpression implements Expression { private Expression left, right; public OrExpression (Expression left, Expression right) { this .left = left; this .right = right; } @Override public boolean interpret (Map <String , Boolean > context ) { return left.interpret (context) || right.interpret (context); } }class NotExpression implements Expression { private Expression exp; public NotExpression (Expression exp) { this .exp = exp; } @Override public boolean interpret (Map <String , Boolean > context ) { return !exp.interpret (context); } }
客户端
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 public class Client { public static void main (String[] args) { Expression a = new VariableExpression ("a" ); Expression b = new VariableExpression ("b" ); Expression c = new VariableExpression ("c" ); Expression d = new VariableExpression ("d" ); Expression expr = new OrExpression ( new AndExpression (a, b), new AndExpression (c, new NotExpression (d)) ); Map<String, Boolean> context = new HashMap <>(); context.put("a" , true ); context.put("b" , false ); context.put("c" , true ); context.put("d" , false ); boolean result = expr.interpret(context); System.out.println("结果: " + result); } }
✅ 优点
易于扩展:每个文法规则对应一个类,新增规则时只需新增类。
代码结构清晰:将复杂表达式的解析逻辑拆分成对象树。
符合 开闭原则 。
❌ 缺点
类数量可能爆炸(每个规则一个类)。
对于复杂文法性能差,不如 编译原理里的解析器生成工具(ANTLR、Yacc) 。
可读性下降,大量小类不利于维护。
中介者模式 核心思想 :通过中介对象封装对象之间的交互。 结构 :Mediator + Colleague。 适用场景 :复杂交互。 优点 :减少对象间耦合。 缺点 :中介者可能过于复杂。 应用 :MVC 的 Controller。
抽象中介者
1 2 3 4 5 interface ChatMediator { void sendMessage(String msg, User user ); void addUser(User user ); }
具体中介者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class ChatRoom implements ChatMediator { private List <User > users = new ArrayList <>(); @Override public void sendMessage (String msg, User user ) { for (User u : users) { if (u != user) { u.receive (msg); } } } @Override public void addUser (User user ) { users.add (user); } }
抽象同事类
1 2 3 4 5 6 7 8 9 10 11 12 13 abstract class User { protected ChatMediator mediator; protected String name; public User (ChatMediator mediator, String name) { this .mediator = mediator; this .name = name; } public abstract void send (String msg) ; public abstract void receive (String msg) ; }
具体同事类
1 2 3 4 5 6 7 8 9 10 11 12 13 abstract class User { protected ChatMediator mediator; protected String name; public User (ChatMediator mediator, String name) { this .mediator = mediator; this .name = name; } public abstract void send (String msg) ; public abstract void receive (String msg) ; }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Client { public static void main (String[] args) { ChatMediator chat = new ChatRoom (); User u1 = new ChatUser (chat, "Alice" ); User u2 = new ChatUser (chat, "Bob" ); User u3 = new ChatUser (chat, "Charlie" ); chat.addUser(u1); chat.addUser(u2); chat.addUser(u3); u1.send("大家好!" ); u2.send("你好 Alice!" ); } }
GUI 框架
窗口、按钮、输入框之间的交互,通常用中介者(对话框管理器)。
聊天室 / 消息队列 / 事件总线
用户或模块之间通过中介者(聊天室、消息中心)通信。
航班调度系统
Spring ApplicationContext
Bean 之间的依赖关系,通过 IoC 容器调度,本质上也是一种中介者思想。
✅ 优点
降低对象之间的耦合(解耦合)。
将交互逻辑集中到一个中介者,便于维护。
符合 迪米特法则(最少知识原则) :对象只与中介者交互。
❌ 缺点
中介者本身可能变得过于复杂,演变成“上帝类”。
过度使用会让逻辑集中在一个类里,维护困难。
模板方法模式 核心思想 :定义算法骨架,子类实现具体步骤。 结构 :抽象类 + 具体实现类。 适用场景 :算法流程固定,但部分步骤变化。 优点 :复用流程逻辑。 缺点 :子类自由度受限。 应用 :AbstractList,Spring JdbcTemplate。
抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 abstract class DataProcessor { public final void process () { readData(); processData(); writeData(); } protected abstract void readData () ; protected abstract void processData () ; protected abstract void writeData () ; }
具体子类
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 class CSVDataProcessor extends DataProcessor { @Override protected void readData () { System.out.println("读取 CSV 数据" ); } @Override protected void processData () { System.out.println("处理 CSV 数据" ); } @Override protected void writeData () { System.out.println("写入 CSV 结果" ); } }class ExcelDataProcessor extends DataProcessor { @Override protected void readData () { System.out.println("读取 Excel 数据" ); } @Override protected void processData () { System.out.println("处理 Excel 数据" ); } @Override protected void writeData () { System.out.println("写入 Excel 结果" ); } }
客户端
1 2 3 4 5 6 7 8 9 10 public class Client { public static void main (String[] args) { DataProcessor csv = new CSVDataProcessor (); csv.process(); DataProcessor excel = new ExcelDataProcessor (); excel.process(); } }
✅ 优点
封装不变部分,扩展可变部分。
遵循 开闭原则 :新增子类即可扩展新的算法变种。
代码复用:把公共部分提取到父类。
❌ 缺点
子类数量可能过多(每个变化点一个子类)。
继承关系使得父类对子类有一定的限制(不如组合灵活)。
访问者模式 核心思想 :将操作从对象结构中分离出来,避免修改类定义。 结构 :Visitor + Element。 适用场景 :对象结构稳定,操作频繁变化。 优点 :增加新操作简单。 缺点 :增加新元素困难。 应用 :编译器语法树遍历。
访问者接口
1 2 3 4 5 interface Visitor { void visitFile (FileElement file ) ; void visitDirectory (DirectoryElement dir ) ; }
具体访问者
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 class SizeVisitor implements Visitor { private int totalSize = 0 ; @Override public void visitFile (FileElement file ) { totalSize += file .getSize(); } @Override public void visitDirectory (DirectoryElement dir ) { for (Element e : dir.getChildren()) { e.accept(this ); } } public int getTotalSize () { return totalSize; } }class PrintVisitor implements Visitor { private int indent = 0 ; @Override public void visitFile (FileElement file ) { System.out .println(" " .repeat(indent) + file .getName() + " (" + file .getSize() + ")" ); } @Override public void visitDirectory (DirectoryElement dir ) { System.out .println(" " .repeat(indent) + "[" + dir.getName() + "]" ); indent++; for (Element e : dir.getChildren()) { e.accept(this ); } indent--; } }
元素接口
1 2 3 4 interface Element { void accept(Visitor 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 class FileElement implements Element { private String name; private int size; public FileElement (String name, int size) { this .name = name; this .size = size; } public int getSize ( ) { return size; } public String getName ( ) { return name; } @Override public void accept (Visitor visitor ) { visitor.visitFile (this ); } }class DirectoryElement implements Element { private String name; private List <Element > children = new ArrayList <>(); public DirectoryElement (String name) { this .name = name; } public void add (Element e ) { children.add (e); } public List <Element > getChildren ( ) { return children; } public String getName ( ) { return name; } @Override public void accept (Visitor visitor ) { visitor.visitDirectory (this ); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Client { public static void main (String[] args ) { DirectoryElement root = new DirectoryElement("root" ); root.add (new FileElement("a.txt" , 10 )); root.add (new FileElement("b.txt" , 20 )); DirectoryElement subDir = new DirectoryElement("sub" ); subDir.add (new FileElement("c.txt" , 5 )); root.add (subDir); PrintVisitor printVisitor = new PrintVisitor(); root.accept(printVisitor); SizeVisitor sizeVisitor = new SizeVisitor(); root.accept(sizeVisitor); System.out .println("总大小: " + sizeVisitor.getTotalSize()); } }
✅ 优点
符合开闭原则 :数据结构不变,增加新操作很容易。
操作集中 :将操作逻辑集中到访问者类中,避免分散在元素类里。
支持对不同类型元素做不同操作。
❌ 缺点
增加新元素困难 :如果要给结构中加一种新元素,就要修改所有访问者 → 违背开闭原则。
结构复杂 :需要双重分派(element.accept(visitor) → visitor.visit(element))。
侵入性 :元素类必须暴露自己的 accept(),让访问者访问内部。