Java 中的 23 种设计模式详解
设计模式是软件开发中的最佳实践,帮助开发者在面对复杂设计问题时提供有效的解决方案。GoF(Gang of Four)在其经典著作《设计模式:可复用面向对象软件的基础》中定义了 23 种设计模式。。本文将详细介绍23种经典设计模式,包括创建型模式、结构型模式和行为型模式,提供每种模式的定义、原理、优点、Java示例代码以及详细注释。
| 目的 | 范围 | 名称 | 描述 |
|---|---|---|---|
| 创建型(Creational) | 对象 | 单例模式(Singleton) | 保证一个类仅有一个实例:并提供一个访问它的全局访问点。 |
| 原型模式(Prototype) | 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。 | ||
| 建造者模式(Builder) | 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 | ||
| 抽象工厂模式(Abstract Factory) | 提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。 | ||
| 类 | 工厂方法模式(Factory Method) | 定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使个类的实例化延迟到其子类。 | |
| 结构型(Structural) | 对象 | 适配器模式(Adapter) | 将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 |
| 桥接模式(Bridge) | 将抽象部分与它的实现部分分离,使它们都可以独立地变化。 | ||
| 组合模式(Composite) | 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。 | ||
| 装饰模式(Decorator) | 动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。 | ||
| 外观模式(Facade) | 运用共享技术有效地支持大量细粒度的对象。 | ||
| 享元模式(Flyweight) | 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 | ||
| 代理模式(Proxy) | 为其他对象提供一个代理以控制对这个对象的访问。 | ||
| 类 | 适配器模式(Adapter) | 将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 | |
| 行为型(Behavioral) | 对象 | 责任链模式(Chain of Responsibility) | 为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。 |
| 命令模式(Command) | 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。 | ||
| 迭代器模式(lterator) | 提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。 | ||
| 中介者模式(Mediator) | 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 | ||
| 备志录模式(Memento) | 在不破坏封装性的前提下,捕获一个对象的内部状态。 | ||
| 观察者模式(Observer) | 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。 | ||
| 状态模式(State) | 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。 | ||
| 策略模式(Strategy) | 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。 | ||
| 访问者模式(Visitor) | 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 | ||
| 类 | 解释器模式(Interpreter) | 给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。 | |
| 模板方法模式(Template Method) | 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Iethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步。 |
创建型模式(Creational Patterns)
创建型模式关注于对象的创建,提供了更灵活的对象创建方式。
创建型模式分为单例模式(Singleton Pattern)、原型模式(Prototype Pattern)、建造者模式(Builder Pattern)、工厂方法模式(Factory Method Pattern)、抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
问题:
在某些情况下,一个对象的创建过程非常复杂,涉及多个步骤,每个步骤都可能有不同的实现方式。如果将所有创建逻辑放在一个类中,会导致该类变得庞大且难以维护。此外,如果需要创建不同的变体对象,就需要在该类中添加更多的逻辑,使得代码变得混乱。
解决方案:
建造者模式提供了一种将一个复杂对象的构建过程与其表示分离的方法。它将对象的构建过程封装在一个独立的"建造者"类中,由该类负责逐步构建对象。这样,可以根据需要创建不同的建造者来构建不同的对象变体。通常,建造者模式涉及以下角色:
- 产品(Product):表示正在构建的复杂对象。建造者模式的目标是构建这个产品。
- 抽象建造者(Abstract Builder):定义了构建产品的步骤和方法,但没有具体的实现。不同的具体建造者可以实现不同的构建步骤,从而创建不同的产品变体。
- 具体建造者(Concrete Builder):实现了抽象建造者定义的方法,完成了产品的构建过程。每个具体建造者负责构建特定的产品变体。
- 指导者(Director):负责控制建造的过程。它通过将客户端与具体建造者分离,确保产品的构建是按照一定顺序和规则进行的。
效果:
建造者模式的效果包括:
- 分离构建过程和表示:通过建造者模式,可以将复杂对象的构建过程与其最终表示分离,使得构建过程更加清晰可控。
- 支持不同的表示:通过使用不同的具体建造者,可以创建不同的产品表示,而不改变客户端的代码。
- 更好的可扩展性:如果需要添加新的产品变体,只需创建一个新的具体建造者即可,而无需修改已有的代码。
- 隐藏产品的内部结构:客户端只需与抽象建造者和指导者交互,无需关心产品的内部构建细节。
总之,建造者模式适用于需要构建复杂对象,且构建过程涉及多个步骤或变体的情况。通过将构建过程分解为可重用的步骤,建造者模式提供了一种结构化的方法来创建对象。
常见的建造者模式实现方式有:传统实现方式(标准建造者模式)、链式调用实现(流式接口)、静态内部类实现等。
传统实现方式(标准建造者模式)
- 原理:
- 包含四个核心角色:产品类(Product)、抽象建造者(Builder)、具体建造者(ConcreteBuilder)和指挥者(Director)
- 指挥者控制构建顺序,调用具体建造者的接口
- 具体建造者实现抽象建造者的方法,负责具体部件的创建
-
优点:
- 解耦构建过程与产品细节
- 支持多产品扩展
- 可以精细控制构建过程
-
缺点:
- 需要额外定义指挥者类
- 增加系统复杂度
- 当产品内部变化时,需要修改所有建造者类
Java示例
class Computer {
private String cpu;
private String ram;
private String storage;
public void setCpu(String cpu) { this.cpu = cpu; }
public void setRam(String ram) { this.ram = ram; }
public void setStorage(String storage) { this.storage = storage; }
public void showSpecs() {
System.out.println("CPU: " + cpu + ", RAM: " + ram + ", Storage: " + storage);
}
}
interface ComputerBuilder {
void buildCpu();
void buildRam();
void buildStorage();
Computer getComputer();
}
class GamingComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildCpu() { computer.setCpu("Intel i9"); }
@Override
public void buildRam() { computer.setRam("32GB DDR5"); }
@Override
public void buildStorage() { computer.setStorage("1TB NVMe SSD"); }
@Override
public Computer getComputer() { return computer; }
}
class Director {
public Computer construct(ComputerBuilder builder) {
builder.buildCpu();
builder.buildRam();
builder.buildStorage();
return builder.getComputer();
}
}
public class BuilderPatternDemo {
public static void main(String[] args) {
// 传统实现方式
Director director = new Director();
Computer gamingPC = director.construct(new GamingComputerBuilder());
gamingPC.showSpecs();
}
}
链式调用实现(流式接口)
- 原理:
- 将建造者作为产品类的静态内部类
- 通过链式调用方法返回自身
- 产品类使用私有构造函数,通过建造者创建实例
-
优点:
- 代码可读性高,方法链直观
- 不需要指挥者类,结构更简单
- 可以灵活设置可选参数
-
缺点:
- 对必选参数支持不够友好
- 参数校验逻辑需要额外处理
- 不适合特别复杂的构建过程
Java示例
class Phone {
private final String os;
private final String chipset;
private final int ram;
private final int storage;
private String color;
private Phone(Builder builder) {
this.os = builder.os;
this.chipset = builder.chipset;
this.ram = builder.ram;
this.storage = builder.storage;
this.color = builder.color;
}
public static class Builder {
private final String os;
private final String chipset;
private final int ram;
private final int storage;
private String color = "Black";
public Builder(String os, String chipset, int ram, int storage) {
this.os = os;
this.chipset = chipset;
this.ram = ram;
this.storage = storage;
}
public Builder color(String color) {
this.color = color;
return this;
}
public Phone build() {
return new Phone(this);
}
}
public void showDetails() {
System.out.println("OS: " + os + ", Chipset: " + chipset +
", RAM: " + ram + "GB, Storage: " + storage +
"GB, Color: " + color);
}
}
public class BuilderPatternDemo {
public static void main(String[] args) {
// 链式调用实现
Phone phone = new Phone.Builder("Android", "Snapdragon 8 Gen 2", 12, 256)
.color("Blue")
.build();
phone.showDetails();
}
}
静态内部类实现
- 原理:
- 将建造者作为产品类的静态内部类
- 建造者包含必选参数的构造函数
- 通过链式方法设置可选参数
-
优点:
- 强制必选参数,编译时检查
- 可选参数设置灵活
- 代码结构紧凑
-
缺点:
- 内部类与外部类耦合
- 不适合特别复杂的构建逻辑
- 参数校验需要额外处理
Java示例
class Car {
private final String make;
private final String model;
private final int year;
private String color;
private int mileage;
private Car(Builder builder) {
this.make = builder.make;
this.model = builder.model;
this.year = builder.year;
this.color = builder.color;
this.mileage = builder.mileage;
}
public static class Builder {
private final String make;
private final String model;
private final int year;
private String color = "White";
private int mileage = 0;
public Builder(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
public Builder color(String color) {
this.color = color;
return this;
}
public Builder mileage(int mileage) {
if (mileage < 0) throw new IllegalArgumentException("Mileage cannot be negative");
this.mileage = mileage;
return this;
}
public Car build() {
return new Car(this);
}
}
public void displayInfo() {
System.out.println(make + " " + model + " (" + year + "), " +
color + ", " + mileage + " miles");
}
}
public class BuilderPatternDemo {
public static void main(String[] args) {
// 静态内部类实现
Car car = new Car.Builder("Toyota", "Camry", 2023)
.color("Red")
.mileage(15000)
.build();
car.displayInfo();
}
}
建造者模式实现方式对比及应用场景
| 实现方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 传统实现方式 | 复杂对象构建,需要严格控制构建顺序 | 构建过程与表示分离,支持多产品扩展 | 类数量多,结构复杂,维护成本高 |
| 链式调用实现 | 参数可选性高的对象构建 | 代码可读性高,使用灵活 | 对必选参数支持不足,校验逻辑复杂 |
| 静态内部类实现 | 必选参数明确的对象构建 | 强制必选参数,结构紧凑 | 耦合度高,不适合复杂构建逻辑 |
推荐使用场景
- 简单对象优先使用链式调用:对于参数可选性高的简单对象,链式调用实现最为简洁高效。
- 复杂对象使用传统实现:当对象构建过程复杂且需要严格控制构建顺序时,传统实现方式更为合适。
- 必选参数明确使用静态内部类:当对象有明确的必选参数时,静态内部类实现能提供编译时检查。
- 考虑使用Lombok简化代码:对于简单场景,可以使用Lombok的@Builder注解自动生成建造者代码。
- 合理使用参数校验:在build()方法中添加参数校验逻辑,确保构建的对象处于合法状态。
2537

被折叠的 条评论
为什么被折叠?



