Java中常见的设计模式
Java 中有 23 种经典设计模式,通常被分为三大类:创建型、结构型和行为型。每个设计模式都解决了不同类型的设计问题。以下是几种常见设计模式的总结,并附带了实际应用场景、示例代码和详细的注释说明。
一、创建型设计模式
这些设计模式关注对象的创建方式,避免在代码中直接创建对象。
1. 单例模式(Singleton Pattern)
-
定义:
单例模式确保一个类只有一个实例,并提供一个全局的访问点来获取该实例。
-
应用场景:
常用于配置类、数据库连接池、日志类等。
-
示例代码:
java
public class Singleton {
// 1. 声明一个私有静态实例变量
private static Singleton instance;
// 2. 私有构造方法,防止外部创建多个实例
private Singleton() {}
// 3. 提供公共的静态方法,返回唯一实例
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) { // 4. 双重检查锁定,确保线程安全
if (instance == null) {
instance = new Singleton(); // 5. 创建实例
}
}
}
return instance; // 6. 返回单例实例
}
}
- 解释:
通过private构造器防止外部创建多个实例。
使用getInstance()方法获取唯一的实例,采用双重锁定来保证线程安全。
2. 工厂模式(Factory Pattern)
-
定义:
工厂模式提供一个创建对象的接口,但由子类决定实例化哪一个类。它让客户端无需知道具体的实现类,就可以创建出所需的对象。
-
应用场景:
用于创建对象的场景,尤其是类的实例化非常复杂或需要根据不同条件创建不同的对象时。
-
示例代码:
java
// 1. 定义产品接口
public interface Animal {
void sound();
}
// 2. 具体产品类:Dog
public class Dog implements Animal {
public void sound() {
System.out.println("Woof!");
}
}
// 3. 具体产品类:Cat
public class Cat implements Animal {
public void sound() {
System.out.println("Meow!");
}
}
// 4. 工厂类,负责创建产品实例
public class AnimalFactory {
public Animal createAnimal(String type) {
if ("dog".equalsIgnoreCase(type)) {
return new Dog(); // 5. 创建Dog对象
} else if ("cat".equalsIgnoreCase(type)) {
return new Cat(); // 6. 创建Cat对象
}
return null; // 7. 返回null表示无法创建对象
}
}
// 8. 客户端代码
public class Client {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory(); // 9. 创建工厂对象
Animal dog = factory.createAnimal("dog"); // 10. 通过工厂创建Dog对象
dog.sound(); // 11. 输出:Woof!
Animal cat = factory.createAnimal("cat"); // 12. 通过工厂创建Cat对象
cat.sound(); // 13. 输出:Meow!
}
}
- 解释:
AnimalFactory负责根据参数创建不同的Animal类型对象,避免客户端直接依赖具体类。
3. 抽象工厂模式(Abstract Factory Pattern)
- 定义:
抽象工厂模式提供一个接口,用来创建一系列相关或相互依赖的对象,而无需指定具体的类。 - 应用场景:
需要创建一系列相关的对象,而无需指定具体类。
用于产品族的创建,确保一系列相关的对象符合某种约定。 - 示例代码:
java
// 1. 定义抽象产品接口:ProductA
public interface ProductA {
void doSomething();
}
// 2. 具体产品A1
public class ProductA1 implements ProductA {
public void doSomething() {
System.out.println("ProductA1 does something");
}
}
// 3. 具体产品A2
public class ProductA2 implements ProductA {
public void doSomething() {
System.out.println("ProductA2 does something");
}
}
// 4. 定义抽象产品接口:ProductB
public interface ProductB {
void doSomethingElse();
}
// 5. 具体产品B1
public class ProductB1 implements ProductB {
public void doSomethingElse() {
System.out.println("ProductB1 does something else");
}
}
// 6. 具体产品B2
public class ProductB2 implements ProductB {
public void doSomethingElse() {
System.out.println("ProductB2 does something else");
}
}
// 7. 定义抽象工厂接口
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 8. 具体工厂A1
public class ConcreteFactoryA1 implements AbstractFactory {
public ProductA createProductA() {
return new ProductA1(); // 9. 返回ProductA1
}
public ProductB createProductB() {
return new ProductB1(); // 10. 返回ProductB1
}
}
// 10. 具体工厂A2
public class ConcreteFactoryA2 implements AbstractFactory {
public ProductA createProductA() {
return new ProductA2(); // 11. 返回ProductA2
}
public ProductB createProductB() {
return new ProductB2(); // 12. 返回ProductB2
}
}
// 13. 客户端代码
public class Client {
public static void main(String[] args) {
AbstractFactory factory = new ConcreteFactoryA1(); // 14. 使用工厂A1
ProductA productA = factory.createProductA(); // 15. 创建ProductA
productA.doSomething(); // 16. 输出:ProductA1 does something
ProductB productB = factory.createProductB(); // 17. 创建ProductB
productB.doSomethingElse(); // 18. 输出:ProductB1 does something else
}
}
- 解释:
AbstractFactory定义了两个产品的创建方法,具体工厂实现不同产品的创建。
ConcreteFactoryA1和ConcreteFactoryA2根据需要创建一系列产品。
tips: Java中工厂模式和抽象工厂模式的区别
二、结构型设计模式
这些设计模式主要关注类和对象的组合,帮助我们设计灵活、易于扩展和维护的系统。
4. 适配器模式(Adapter Pattern)
- 定义:
适配器模式通过将一个类的接口转换成客户端期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。 - 应用场景:
用于将一个类的接口转换为客户期望的另一个接口,常见于第三方库的集成时。 - 示例代码:
java
// 1. 目标接口
public interface Target {
void request();
}
// 2. 适配者类,已经存在的接口
public class Adaptee {
public void specificRequest() {
System.out.println("Specific request");
}
}
// 3. 适配器类,实现目标接口,并委托调用适配者的方法
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee; // 4. 构造方法,传入适配者
}
public void request() {
adaptee.specificRequest(); // 5. 调用适配者的特定方法
}
}
// 6. 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee(); // 7. 创建适配者对象
Target target = new Adapter(adaptee); // 8. 使用适配器
target.request(); // 9. 输出:Specific request
}
}
- 解释:
Target是客户期望的接口,Adaptee是已经存在的接口,通过Adapter类适配两者的差异。
5. 桥接模式(Bridge Pattern)
-
定义:
桥接模式通过将抽象部分和实现部分分离,使它们可以独立变化。它主要用于接口和实现的解耦。
-
应用场景:
用于将抽象部分与实现部分分离,使它们可以独立变化。常用于图形绘制、设备控制等场景。
-
示例代码:
java
// 1. 抽象类
public abstract class Shape {
protected DrawingAPI drawingAPI; // 2. 依赖抽象的实现类
public Shape(DrawingAPI drawingAPI) {
this.drawingAPI = drawingAPI;
}
public abstract void draw(); // 3. 抽象方法
}
// 4. 具体形状类:Circle
public class Circle extends Shape {
private double x, y, radius;
public Circle(double x, double y, double radius, DrawingAPI drawingAPI) {
super(drawingAPI); // 5. 调用父类构造器,传入实现类
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawingAPI.drawCircle(x, y, radius); // 6. 委托给实现类
}
}
// 7. 抽象实现类
public interface DrawingAPI {
void drawCircle(double x, double y, double radius); // 8. 绘制圆的方法
}
// 9. 具体实现类:DrawingAPI1
public class DrawingAPI1 implements DrawingAPI {
public void drawCircle(double x, double y, double radius) {
System.out.println("Drawing Circle using DrawingAPI1 at (" + x + ", " + y + ") with radius " + radius);
}
}
// 10. 具体实现类:DrawingAPI2
public class DrawingAPI2 implements DrawingAPI {
public void drawCircle(double x, double y, double radius) {
System.out.println("Drawing Circle using DrawingAPI2 at (" + x + ", " + y + ") with radius " + radius);
}
}
// 11. 客户端代码
public class Client {
public static void main(String[] args) {
Shape shape1 = new Circle(1, 2, 3, new DrawingAPI1()); // 12. 使用API1
shape1.draw(); // 13. 输出:Drawing Circle using DrawingAPI1 at (1, 2) with radius 3
Shape shape2 = new Circle(4, 5, 6, new DrawingAPI2()); // 14. 使用API2
shape2.draw(); // 15. 输出:Drawing Circle using DrawingAPI2 at (4, 5) with radius 6
}
}
- 解释:
Shape类定义了抽象的draw()方法,依赖于DrawingAPI接口。
Circle类实现了具体的图形操作,将绘制行为委托给具体的实现类(DrawingAPI1或DrawingAPI2)。
三、行为型设计模式
6. 策略模式(Strategy Pattern)
-
定义:
策略模式定义了一系列算法,将每一个算法封装起来,并使它们可以互换。它让算法的变化独立于使用算法的客户。
-
应用场景:
策略模式用于定义一系列算法或策略,并允许在运行时切换策略。策略模式可以让你避免使用大量的 if-else 或 switch 语句来处理不同的行为。
-
示例代码:
假设你在开发一个支付系统,需要根据不同的支付方式(如支付宝、微信支付、信用卡支付)选择不同的支付策略。
java
// 策略接口,定义支付行为
interface PaymentStrategy {
void pay(int amount);
}
// 具体策略:支付宝支付
class AlipayPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Using Alipay to pay " + amount + " units.");
}
}
// 具体策略:微信支付
class WeChatPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Using WeChat to pay " + amount + " units.");
}
}
// 具体策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Using Credit Card to pay " + amount + " units.");
}
}
// 上下文类,持有一个策略对象
class PaymentContext {
private PaymentStrategy paymentStrategy;
// 设置支付策略
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 执行支付
public void executePayment(int amount) {
paymentStrategy.pay(amount);
}
}
// 客户端代码
public class StrategyPatternExample {
public static void main(String[] args) {
// 创建上下文对象
PaymentContext paymentContext = new PaymentContext();
// 设置支付宝支付策略
paymentContext.setPaymentStrategy(new AlipayPayment());
paymentContext.executePayment(100); // 输出: Using Alipay to pay 100 units.
// 设置微信支付策略
paymentContext.setPaymentStrategy(new WeChatPayment());
paymentContext.executePayment(200); // 输出: Using WeChat to pay 200 units.
// 设置信用卡支付策略
paymentContext.setPaymentStrategy(new CreditCardPayment());
paymentContext.executePayment(300); // 输出: Using Credit Card to pay 300 units.
}
}
- 解释:
- PaymentStrategy 是一个策略接口,定义了支付方法。
- AlipayPayment、WeChatPayment、CreditCardPayment 是具体的支付策略,分别实现了 PaymentStrategy 接口。
- PaymentContext 类持有一个支付策略对象,并在运行时动态改变使用的支付策略。
- 在客户端代码中,使用不同的支付策略(支付宝、微信、信用卡)来执行支付。
7. 观察者模式(Observer Pattern)
-
定义:
观察者模式定义了对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会自动更新。
-
应用场景:
观察者模式用于一对多的场景,一个对象的状态改变时,所有依赖于它的对象都会得到通知并自动更新。比如在实现事件监听机制时,常常使用观察者模式。
-
示例代码:
假设你在开发一个天气预报系统,当天气变化时,所有的观察者(如显示板、手机应用等)都需要得到通知并更新天气信息。
java
import java.util.ArrayList;
import java.util.List;
// 观察者接口,定义更新方法
interface Observer {
void update(String weather);
}
// 具体观察者:显示板
class DisplayBoard implements Observer {
@Override
public void update(String weather) {
System.out.println("DisplayBoard updated with weather: " + weather);
}
}
// 具体观察者:手机应用
class MobileApp implements Observer {
@Override
public void update(String weather) {
System.out.println("MobileApp updated with weather: " + weather);
}
}
// 被观察者:天气数据
class WeatherData {
private List<Observer> observers = new ArrayList<>();
private String weather;
// 添加观察者
public void addObserver(Observer observer) {
observers.add(observer);
}
// 移除观察者
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// 设置天气信息并通知所有观察者
public void setWeather(String weather) {
this.weather = weather;
notifyObservers();
}
// 通知所有观察者更新
private void notifyObservers() {
for (Observer observer : observers) {
observer.update(weather);
}
}
}
// 客户端代码
public class ObserverPatternExample {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
// 创建观察者
DisplayBoard displayBoard = new DisplayBoard();
MobileApp mobileApp = new MobileApp();
// 添加观察者
weatherData.addObserver(displayBoard);
weatherData.addObserver(mobileApp);
// 改变天气信息,通知所有观察者
weatherData.setWeather("Sunny"); // 输出: DisplayBoard updated with weather: Sunny
// 输出: MobileApp updated with weather: Sunny
// 修改天气信息,观察者会自动更新
weatherData.setWeather("Rainy"); // 输出: DisplayBoard updated with weather: Rainy
// 输出: MobileApp updated with weather: Rainy
}
}
- 解释:
- Observer 是观察者接口,定义了 update 方法来接收通知。
- DisplayBoard 和 MobileApp 是具体的观察者,分别实现了 Observer 接口。
- WeatherData 是被观察者,保存了观察者的列表,并在天气变化时通知所有观察者。
- 在客户端代码中,当天气信息发生变化时,所有已注册的观察者都会接收到更新通知。
8. 命令模式(Command Pattern)
- 定义:
命令模式将请求封装为对象,从而使用户可以通过不同的请求对客户端进行参数化。 - 应用场景:
命令模式将请求封装成对象,从而使你可以用不同的请求、队列和日志来参数化其他对象。它通常用于需要进行操作的场景,尤其是按钮点击、任务调度等。 - 示例代码:
假设你在设计一个遥控器系统,每个按钮上绑定不同的命令操作(如开灯、关灯)。
java
// 命令接口,定义执行操作的方法
interface Command {
void execute();
}
// 具体命令:开灯命令
class TurnOnLightCommand implements Command {
private Light light;
public TurnOnLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
// 具体命令:关灯命令
class TurnOffLightCommand implements Command {
private Light light;
public TurnOffLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
// 接收者类:灯
class Light {
public void turnOn() {
System.out.println("The light is on.");
}
public void turnOff() {
System.out.println("The light is off.");
}
}
// 调用者类:遥控器
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// 客户端代码
public class CommandPatternExample {
public static void main(String[] args) {
Light light = new Light();
Command turnOn = new TurnOnLightCommand(light);
Command turnOff = new TurnOffLightCommand(light);
RemoteControl remoteControl = new RemoteControl();
// 按下开灯按钮
remoteControl.setCommand(turnOn);
remoteControl.pressButton(); // 输出: The light is on.
// 按下关灯按钮
remoteControl.setCommand(turnOff);
remoteControl.pressButton(); // 输出: The light is off.
}
}
- 解释:
- Command 是命令接口,定义了 execute 方法来执行具体操作。
- TurnOnLightCommand 和 TurnOffLightCommand 是具体命令类,实现了 Command 接口,封装了开灯和关灯操作。
- Light 是接收者类,实际执行开关灯操作。
- RemoteControl 是调用者类,接收命令并调用命令的 execute 方法。
9. 状态模式(State Pattern)
-
定义:
状态模式允许一个对象在其内部状态发生改变时改变它的行为,看起来像是改变了其类。
-
应用场景:
状态之间的转换依赖于外部条件,常用于有限状态机(例如游戏中的状态机:开始、暂停、结束)。
10. 责任链模式(Chain of Responsibility Pattern)
-
定义:
责任链模式使得多个对象有机会处理请求,从而避免了请求的发送者和接收者之间的直接耦合。将请求沿着责任链传递,直到有一个对象处理它。
-
应用场景:
多个处理对象可能处理同一个请求时,比如日志过滤器、权限验证等。
11. 中介者模式(Mediator Pattern)
-
定义:
中介者模式通过定义一个中介对象来封装一组对象之间的交互,避免了对象间的直接引用,使得松耦合的设计变得更加容易。
-
应用场景:
多个类之间有复杂的交互时,使用中介者来集中管理这些交互,例如聊天室应用中的用户之间的消息传递。
12. 备忘录模式(Memento Pattern)
-
定义:
备忘录模式允许在不暴露对象实现细节的情况下保存和恢复对象的内部状态。
-
应用场景:
在需要保存对象历史状态的场景中,比如撤销操作、保存游戏进度等。
13. 模板方法模式(Template Method Pattern)
-
定义:
模板方法模式定义了一个操作中的算法的骨架,将一些步骤的实现延迟到子类中。子类可以在不改变算法结构的情况下重新定义该算法的某些特定步骤。
-
应用场景:
一些固定的操作流程和步骤,但某些步骤需要子类提供具体实现时。
14. 访问者模式(Visitor Pattern)
-
定义:
访问者模式将数据结构和操作分开,使得可以在不修改数据结构的情况下添加新的操作。
-
应用场景:
对多个类操作进行扩展,但不想修改类的实现时,常用于编译器、图形结构等。
四、总结
这些行为型设计模式能够让你灵活地处理对象之间的交互,特别是在复杂系统中,能够有效解耦和简化代码。