设计模式是前辈们对软件开发中反复出现的问题的成熟解决方案。掌握它们让你的代码更具弹性、可复用性与可维护性。前言设计模式是软件工程的“词汇表”它让开发者能够用简洁的术语描述复杂的架构思想。Java 作为经典的面向对象语言天然支持大部分 GoF 设计模式。但在实际项目中很多同学要么过度设计模式滥用要么对模式一知半解实现僵硬。本文将系统讲解23 种 GoF 设计模式在 Java 中的实现涵盖创建型、结构型、行为型三大类每个模式都会提供解决的核心问题UML 角色与结构说明完整可运行的 Java 代码示例含现代 Lambda 优化JDK/Spring 等框架中的实际应用使用场景、优缺点与常见误区读前提示本文较长建议收藏。可以先阅读创建型模式结合项目中的实际场景逐步消化。目录设计模式概述与分类创建型模式2.1 单例模式Singleton2.2 工厂方法模式Factory Method2.3 抽象工厂模式Abstract Factory2.4 建造者模式Builder2.5 原型模式Prototype结构型模式3.1 适配器模式Adapter3.2 装饰器模式Decorator3.3 代理模式Proxy3.4 外观模式Facade3.5 桥接模式Bridge3.6 组合模式Composite3.7 享元模式Flyweight行为型模式4.1 策略模式Strategy4.2 模板方法模式Template Method4.3 观察者模式Observer4.4 责任链模式Chain of Responsibility4.5 命令模式Command4.6 状态模式State4.7 迭代器模式Iterator4.8 访问者模式Visitor设计模式综合对比与选型建议总结1. 设计模式概述与分类设计模式分为三大类类型关注点包含模式创建型对象创建机制隐藏实例化逻辑单例、工厂方法、抽象工厂、建造者、原型结构型类与对象的组合形成更大的结构适配器、装饰器、代理、外观、桥接、组合、享元行为型对象之间的职责分配与通信策略、模板方法、观察者、责任链、命令、状态、迭代器、访问者、中介者、备忘录、解释器本文会覆盖最常用的15种模式对于解释器等日常开发较少使用的模式仅作简要介绍。2. 创建型模式2.1 单例模式Singleton确保一个类只有一个实例并提供全局访问点。实现方式线程安全优先① 饿汉式线程安全推荐javapublic class Singleton { private static final Singleton INSTANCE new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }② 静态内部类懒加载线程安全javapublic class Singleton { private Singleton() {} private static class Holder { private static final Singleton INSTANCE new Singleton(); } public static Singleton getInstance() { return Holder.INSTANCE; } }③ 双重检查锁DCL需注意 volatilejavapublic 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; } }④ 枚举最简洁天然防反射/序列化javapublic enum SingletonEnum { INSTANCE; public void doSomething() { ... } }使用场景配置管理类、日志类、数据库连接池。需要严格控制全局唯一资源的场景。注意事项反射可以破坏私有构造器枚举可以防御。序列化需实现readResolve()方法返回单例。2.2 工厂方法模式Factory Method定义一个创建对象的接口让子类决定实例化哪一个类。将对象的实例化延迟到子类。结构Product产品接口ConcreteProduct具体产品Factory工厂接口声明工厂方法ConcreteFactory具体工厂实现工厂方法返回具体产品代码示例java// 产品接口 interface Product { void doStuff(); } // 具体产品 A class ConcreteProductA implements Product { Override public void doStuff() { System.out.println(Product A); } } // 具体产品 B class ConcreteProductB implements Product { Override public void doStuff() { System.out.println(Product B); } } // 工厂接口 interface Factory { Product createProduct(); } // 具体工厂 A class FactoryA implements Factory { Override public Product createProduct() { return new ConcreteProductA(); } } class FactoryB implements Factory { Override public Product createProduct() { return new ConcreteProductB(); } } // 使用 Factory factory new FactoryA(); Product product factory.createProduct(); product.doStuff();实际应用java.util.Collection中的iterator()方法可以看作工厂方法不同集合返回不同迭代器。JDBC 中Connection.createStatement()返回Statement对象。优点单一职责产品创建与使用分离。开闭原则新增产品只需新增工厂类。2.3 抽象工厂模式Abstract Factory创建一系列相关或相互依赖的对象族而无需指定它们具体的类。场景需要生产不同品牌如 Windows、Mac的 UI 组件Button、Checkbox。代码示例java// 产品族1按钮 interface Button { void paint(); } class WinButton implements Button { public void paint() { System.out.println(Win Button); } } class MacButton implements Button { public void paint() { System.out.println(Mac Button); } } // 产品族2复选框 interface Checkbox { void paint(); } class WinCheckbox implements Checkbox { public void paint() { System.out.println(Win Checkbox); } } class MacCheckbox implements Checkbox { public void paint() { System.out.println(Mac Checkbox); } } // 抽象工厂 interface GUIFactory { Button createButton(); Checkbox createCheckbox(); } // 具体工厂Windows 风格 class WinFactory implements GUIFactory { public Button createButton() { return new WinButton(); } public Checkbox createCheckbox() { return new WinCheckbox(); } } // 具体工厂Mac 风格 class MacFactory implements GUIFactory { public Button createButton() { return new MacButton(); } public Checkbox createCheckbox() { return new MacCheckbox(); } } // 客户端代码 class Application { private Button button; private Checkbox checkbox; public Application(GUIFactory factory) { button factory.createButton(); checkbox factory.createCheckbox(); } public void paint() { button.paint(); checkbox.paint(); } }与工厂方法的区别工厂方法一个工厂生产一种产品。抽象工厂一个工厂生产一系列相关联的产品。实际应用javax.xml.parsers.DocumentBuilderFactory返回DocumentBuilder和SAXParser等系列产品。2.4 建造者模式Builder将一个复杂对象的构建与表示分离使得同样的构建过程可以创建不同的表示。适用于参数众多、部分可选、构造时需校验的对象如消息体、HTTP 请求。经典写法链式调用javapublic class User { private final String name; // 必填 private final int age; // 必填 private final String phone; // 可选 private final String address; // 可选 private User(Builder builder) { this.name builder.name; this.age builder.age; this.phone builder.phone; this.address builder.address; } public static class Builder { // 必填参数 private final String name; private final int age; // 可选参数 private String phone ; private String address ; public Builder(String name, int age) { this.name name; this.age age; } public Builder phone(String phone) { this.phone phone; return this; } public Builder address(String address) { this.address address; return this; } public User build() { // 可添加校验逻辑 if (age 0 || age 150) throw new IllegalArgumentException(age invalid); return new User(this); } } // getters 省略 } // 使用 User user new User.Builder(张三, 25) .phone(13800000000) .address(北京) .build();实际应用StringBuilder、StringBuffer 的append链式调用。Lombok 的Builder注解自动生成。Spring 中的UriComponentsBuilder。2.5 原型模式Prototype通过复制已有实例来创建新对象而不是通过 new 关键字。实现方式实现Cloneable接口重写clone()方法。javapublic class Sheep implements Cloneable { private String name; private Date birth; public Sheep(String name, Date birth) { ... } Override protected Sheep clone() throws CloneNotSupportedException { Sheep clone (Sheep) super.clone(); // 浅拷贝 // 如果需要深拷贝对引用类型也进行克隆 clone.birth (Date) this.birth.clone(); return clone; } }使用场景对象创建成本高如数据库连接、复杂计算。需要大量相似对象且属性差异不大。注意默认super.clone()是浅拷贝需要深拷贝时需手动处理引用类型。也可使用序列化方式实现深拷贝。3. 结构型模式3.1 适配器模式Adapter将一个类的接口转换为客户希望的另一个接口使得原本不兼容的类可以一起工作。类适配器继承 vs 对象适配器组合对象适配器示例优先使用组合java// 已有类接口不匹配 class LegacyPrinter { public void printOld(String text) { System.out.println(Legacy: text); } } // 目标接口 interface Printer { void print(String message); } // 适配器 class PrinterAdapter implements Printer { private LegacyPrinter legacy; public PrinterAdapter(LegacyPrinter legacy) { this.legacy legacy; } Override public void print(String message) { legacy.printOld(message); } } // 使用 LegacyPrinter old new LegacyPrinter(); Printer p new PrinterAdapter(old); p.print(Hello);应用场景将旧系统接口适配到新接口。java.io.InputStreamReader将字节流适配为字符流。3.2 装饰器模式Decorator动态地给对象添加额外的职责比继承更灵活。经典咖啡订单系统java// 抽象组件 interface Coffee { double cost(); String description(); } // 具体组件 class SimpleCoffee implements Coffee { public double cost() { return 2.0; } public String description() { return Simple coffee; } } // 装饰器抽象类 abstract class CoffeeDecorator implements Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee coffee; } } // 具体装饰器加牛奶 class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); } public double cost() { return decoratedCoffee.cost() 0.5; } public String description() { return decoratedCoffee.description() , milk; } } // 具体装饰器加糖 class SugarDecorator extends CoffeeDecorator { public SugarDecorator(Coffee coffee) { super(coffee); } public double cost() { return decoratedCoffee.cost() 0.2; } public String description() { return decoratedCoffee.description() , sugar; } } // 使用 Coffee coffee new SimpleCoffee(); coffee new MilkDecorator(coffee); coffee new SugarDecorator(coffee); System.out.println(coffee.description() - $ coffee.cost());对比代理模式装饰器增强原有功能客户端可以嵌套多层。代理控制访问通常不添加新功能。Java I/O 经典应用javanew BufferedInputStream(new FileInputStream(file.txt));3.3 代理模式Proxy为其他对象提供一种代理以控制对这个对象的访问。静态代理javainterface Image { void display(); } class RealImage implements Image { private String file; public RealImage(String file) { this.file file; loadFromDisk(); } private void loadFromDisk() { System.out.println(Loading file); } public void display() { System.out.println(Displaying file); } } class ProxyImage implements Image { private RealImage realImage; private String file; public ProxyImage(String file) { this.file file; } public void display() { if (realImage null) realImage new RealImage(file); realImage.display(); } }动态代理基于 JDK Proxyjava// 需要接口 InvocationHandler handler (proxy, method, args) - { System.out.println(Before method); Object result method.invoke(target, args); System.out.println(After method); return result; }; Image proxy (Image) Proxy.newProxyInstance( Image.class.getClassLoader(), new Class[]{Image.class}, handler ); proxy.display();常见应用Spring AOP基于动态代理。延迟加载Hibernate 懒加载。远程调用RMI。3.4 外观模式Facade为子系统中的一组接口提供一个一致的界面简化调用。java// 复杂子系统 class CPU { public void start() {...} } class Memory { public void load() {...} } class HardDrive { public void read() {...} } // 外观类 class ComputerFacade { private CPU cpu; private Memory memory; private HardDrive disk; public ComputerFacade() { this.cpu new CPU(); this.memory new Memory(); this.disk new HardDrive(); } public void start() { cpu.start(); memory.load(); disk.read(); } } // 客户端仅调用外观方法 ComputerFacade computer new ComputerFacade(); computer.start();应用java.nio.file.Files提供文件操作的简化方法。Spring JDBC 的JdbcTemplate封装了数据库操作的细节。3.5 桥接模式Bridge将抽象部分与实现部分分离使它们都可以独立变化。场景不同形状圆形、方形与不同颜色红色、蓝色的组合避免类爆炸。java// 实现类接口颜色 interface Color { void applyColor(); } class Red implements Color { public void applyColor() { System.out.println(red); } } class Blue implements Color { public void applyColor() { System.out.println(blue); } } // 抽象类形状 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); } void draw() { System.out.print(Circle fill ); color.applyColor(); } } class Square extends Shape { public Square(Color color) { super(color); } void draw() { System.out.print(Square fill ); color.applyColor(); } }优点避免继承爆炸M×N 组合只需 MN 个类。符合开闭原则。3.6 组合模式Composite将对象组合成树形结构以表示“部分-整体”层次结构使客户端对单个对象和组合对象的使用具有一致性。java// 组件接口 interface FileSystemNode { void ls(); } // 叶子节点 class File implements FileSystemNode { private String name; public File(String name) { this.name name; } public void ls() { System.out.println(File: name); } } // 容器节点 class Directory implements FileSystemNode { private String name; private ListFileSystemNode children new ArrayList(); public Directory(String name) { this.name name; } public void add(FileSystemNode node) { children.add(node); } public void ls() { System.out.println(Directory: name); children.forEach(FileSystemNode::ls); } }应用文件系统。GUI 容器与组件Swing 的Container和Component。3.7 享元模式Flyweight运用共享技术有效地支持大量细粒度对象减少内存占用。典型围棋棋子颜色相同可共享位置不同为外部状态java// 享元类内部状态颜色 class ChessPiece { private String color; public ChessPiece(String color) { this.color color; } public void place(int x, int y) { System.out.println(color piece at ( x , y )); } } // 工厂管理享元 class ChessPieceFactory { private static final MapString, ChessPiece pool new HashMap(); public static ChessPiece getPiece(String color) { return pool.computeIfAbsent(color, ChessPiece::new); } } // 客户端使用 ChessPiece black1 ChessPieceFactory.getPiece(black); black1.place(1, 1); ChessPiece black2 ChessPieceFactory.getPiece(black); // 同一个对象应用Integer 缓存-128~127。String 常量池。数据库连接池虽然后者更接近对象池模式。4. 行为型模式4.1 策略模式Strategy定义一系列算法将每个算法封装起来并使它们可以互相替换。示例促销活动java// 策略接口 interface PromotionStrategy { double applyDiscount(double price); } // 具体策略 class NoDiscount implements PromotionStrategy { public double applyDiscount(double price) { return price; } } class PercentageDiscount implements PromotionStrategy { private double percent; public PercentageDiscount(double percent) { this.percent percent; } public double applyDiscount(double price) { return price * (1 - percent / 100); } } // 上下文 class Order { private PromotionStrategy strategy; public void setStrategy(PromotionStrategy strategy) { this.strategy strategy; } public double finalPrice(double original) { return strategy.applyDiscount(original); } } // 使用也可结合Lambda简化 Order order new Order(); order.setStrategy(new PercentageDiscount(20)); System.out.println(order.finalPrice(100.0)); // 80.0Java 8 简化策略java// 使用函数式接口 public class Order { private FunctionDouble, Double strategy Function.identity(); public void setStrategy(FunctionDouble, Double strategy) { this.strategy strategy; } public double finalPrice(double price) { return strategy.apply(price); } } order.setStrategy(price - price * 0.8);应用java.util.Comparator的不同排序策略。Spring 的Resource加载策略ClassPathResource,FileSystemResource。4.2 模板方法模式Template Method定义一个算法的骨架将一些步骤延迟到子类中实现不改变算法结构的情况下重定义某些步骤。javaabstract class DataProcessor { // 模板方法声明为 final 防止子类修改算法顺序 public final void process() { readData(); processData(); writeData(); } protected abstract void readData(); protected abstract void processData(); protected void writeData() { System.out.println(Writing to default output); } } class CSVProcessor extends DataProcessor { protected void readData() { System.out.println(Reading CSV); } protected void processData() { System.out.println(Processing CSV); } } class XMLProcessor extends DataProcessor { protected void readData() { System.out.println(Reading XML); } protected void processData() { System.out.println(Processing XML); } // 可覆盖 writeData }应用Java 集合的AbstractList中的addAll方法。Servlet 中的doGet、doPostHttpServlet 的 service 方法是模板方法。钩子方法允许子类控制算法中的某些步骤例如提供一个boolean方法供子类覆盖。4.3 观察者模式Observer定义对象间的一对多依赖关系当一个对象状态改变时所有依赖它的对象自动收到通知。Java 内置实现已过时推荐自定义javaimport java.util.ArrayList; import java.util.List; // 主题 class NewsAgency { private ListChannel channels new ArrayList(); public void addChannel(Channel channel) { channels.add(channel); } public void removeChannel(Channel channel) { channels.remove(channel); } public void sendNews(String news) { for (Channel c : channels) c.update(news); } } // 观察者接口 interface Channel { void update(String news); } // 具体观察者 class NewsChannel implements Channel { private String news; public void update(String news) { this.news news; System.out.println(Received: news); } } // 使用 NewsAgency agency new NewsAgency(); agency.addChannel(new NewsChannel()); agency.sendNews(Hello World!);Java 9FlowAPI响应式流java// 参考 java.util.concurrent.Flow 实现发布订阅框架应用Spring 事件机制ApplicationEventEventListener。消息队列MQ本质也是观察者模式的分布式变体。4.4 责任链模式Chain of Responsibility将请求的发送者和接收者解耦多个对象都有机会处理该请求形成一条链。java// 抽象处理器 abstract class Logger { public static int INFO 1; public static int DEBUG 2; public static int ERROR 3; protected int level; protected Logger nextLogger; public void setNext(Logger next) { this.nextLogger next; } public void logMessage(int level, String msg) { if (this.level level) { write(msg); } if (nextLogger ! null) nextLogger.logMessage(level, msg); } protected abstract void write(String msg); } class ConsoleLogger extends Logger { public ConsoleLogger(int level) { this.level level; } protected void write(String msg) { System.out.println(Console: msg); } } class FileLogger extends Logger { public FileLogger(int level) { this.level level; } protected void write(String msg) { System.out.println(File: msg); } }应用Servlet 的FilterChain。Spring Security 的过滤器链。日志框架如 Log4j 的 Appender 链。4.5 命令模式Command将请求封装为对象从而支持请求的排队、记录日志、撤销等操作。java// 命令接口 interface Command { void execute(); void undo(); } // 接收者 class Light { public void on() { System.out.println(Light On); } public void off() { System.out.println(Light Off); } } // 具体命令 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 pressButton() { command.execute(); } }应用线程池中的Runnable本质是命令模式。事务操作的回滚。菜单项与按钮的操作。4.6 状态模式State允许对象在内部状态改变时改变它的行为对象看起来像是修改了它的类。java// 状态接口 interface State { void handle(); } class ConcreteStateA implements State { public void handle() { System.out.println(State A handling); } } class Context { private State state; public void setState(State state) { this.state state; } public void request() { state.handle(); } }对比策略模式策略模式行为由外部传入互不感知。状态模式状态之间可以转换常由 Context 管理。应用工作流引擎请假审批的不同状态。订单状态机。4.7 迭代器模式Iterator提供一种方法顺序访问聚合对象中的各个元素而不暴露其内部表示。Java 已经内置了java.util.Iterator自定义示例javaclass MyListT implements IterableT { private T[] items; public MyList(T... items) { this.items items; } Override public IteratorT iterator() { return new IteratorT() { private int index 0; public boolean hasNext() { return index items.length; } public T next() { return items[index]; } }; } }实际应用所有 Java 集合框架的iterator()方法。4.8 访问者模式Visitor将算法与数据结构分离使得在不改变元素类的前提下增加作用于这些元素的新操作。java// 元素接口 interface Element { void accept(Visitor visitor); } // 具体元素 class Book implements Element { public void accept(Visitor visitor) { visitor.visit(this); } public String getTitle() { return Design Patterns; } } // 访问者接口 interface Visitor { void visit(Book book); void visit(Fruit fruit); } // 具体访问者计算价格 class PriceVisitor implements Visitor { public void visit(Book book) { System.out.println(Book price: $30); } public void visit(Fruit fruit) { System.out.println(Fruit price: $5); } }优缺点增加新操作容易增加 Visitor 实现类。增加新元素困难需修改所有 Visitor 接口。破坏了封装性。应用ASM、ANTLR 等编译器工具。Spring 中BeanDefinitionVisitor。5. 设计模式综合对比与选型建议需求/场景推荐模式只需要一个全局实例单例创建复杂对象参数多且有可选字段建造者需要创建一系列相关产品抽象工厂动态给对象添加职责装饰器控制对象访问权限、懒加载代理简化复杂子系统调用外观多种算法可互换策略算法固定部分步骤可变模板方法一对多通知更新观察者请求逐级处理责任链对象状态变化导致行为变化状态扩展类的功能而不修改类访问者谨慎使用6. 总结设计模式是前人智慧的结晶但切忌生搬硬套。遵循以下原则优先使用组合而非继承如策略、装饰器模式。针对接口编程不针对实现编程。开闭原则对扩展开放对修改关闭。单一职责原则每个模式都体现了职责分离。现代 Java 开发中许多模式已被函数式编程Lambda、Stream简化如策略模式可以用函数式接口替代。建议结合 Spring 框架的源码学习体会设计模式在实际框架中的落地。最后送上一句“过度设计是罪恶没有设计是灾难。”如果本文对你有帮助欢迎点赞、收藏、转发关于设计模式在实际项目中的应用有任何疑问请留言讨论。