Appearance
几种常用的设计模式
设计模式是软件开发领域中总结出的通用解决方案,用于解决在特定环境下经常遇到的设计问题。 它们并不是具体的代码实现,而是描述了解决某类问题的抽象思想和可复用的设计模板。 在软件开发中,设计模式帮助开发人员实现代码的可读性、扩展性和复用性,同时促进团队成员之间的高效沟通。
单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,目的是确保一个类在系统中只有一个实例,并提供一个全局访问点。单例模式常被用于表示全局唯一的资源或对象,例如配置管理器、日志系统、线程池等。
Java
package com.practice.patterns;
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}关键点:
- 使用 volatile 修饰符确保多线程环境中对变量的修改对所有线程立即可见,避免指令重排序问题。
- 私有化构造方法,禁止外部直接创建实例。
- 通过 getInstance() 获取唯一实例,确保一个类只有一个实例,并提供全局访问点。
- 双重检查锁定,第一次检查 instance 是否为 null,避免不必要的同步。进入同步块后再检查一次,以确保线程安全。
- 使用 synchronized 关键字,保证同一时间只有一个线程能执行实例化代码。
工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,其目的是通过定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式将对象的创建逻辑与使用逻辑分离,使得代码更加灵活和可维护。
定义一个接口或抽象类 Shape,描述所有具体对象的公共行为。
Java
package com.practice.service;
public interface Shape {
void draw();
}具体实现类 Circle 实现接口 Shape,提供具体行为。
Java
package com.practice.service.impl;
import com.practice.service.Shape;
public class Circle implements Shape {
public void draw() {
System.out.println("画一个圆");
}
}具体实现类 Rectangle 实现接口 Shape,提供具体行为。
Java
package com.practice.service.impl;
import com.practice.service.Shape;
public class Rectangle implements Shape {
public void draw() {
System.out.println("画一个长方形");
}
}ShapeFactory 是工厂类,根据参数 shapeType 动态返回具体对象。
Java
package com.practice.patterns;
import com.practice.service.Shape;
import com.practice.service.impl.Circle;
import com.practice.service.impl.Rectangle;
public class ShapeFactory {
public static Shape getShape(String shapeType) {
if ("CIRCLE".equalsIgnoreCase(shapeType)) {
return new Circle();
} else if ("RECTANGLE".equalsIgnoreCase(shapeType)) {
return new Rectangle();
}
return null;
}
}通过工厂获取对象,无需关心对象的具体实现细节。
Java
package com.practice.app;
import com.practice.patterns.ShapeFactory;
import com.practice.service.Shape;
public class FactoryPatternDemo {
public static void main(String[] args) {
Shape circle = ShapeFactory.getShape("CIRCLE");
circle.draw();
// 输出:画一个圆
Shape rectangle = ShapeFactory.getShape("RECTANGLE");
rectangle.draw();
// 输出:画一个长方形
}
}关键点:
- 解耦了对象的创建与使用。
- 更容易扩展,添加新类型时,只需修改工厂代码。
观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会收到通知并自动更新。
定义观察者接口,强制实现 update 方法,用于接收通知。
Java
package com.practice.service;
public interface Observer {
void update(String message);
}实现观察者接口
Java
package com.practice.service.impl;
import com.practice.service.Observer;
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received: " + message);
}
}Subject 类维护一个观察者列表,通过 addObserver 和 removeObserver 方法管理观察者。
调用 notifyObservers 通知所有观察者。
Java
package com.practice.common;
import com.practice.service.Observer;
import java.util.ArrayList;
import java.util.List;
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}动态注册观察者。
当状态变化时,所有观察者都会收到通知。
Java
package com.practice.app;
import com.practice.common.Subject;
import com.practice.service.Observer;
import com.practice.service.impl.ConcreteObserver;
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new ConcreteObserver("Observer1");
Observer observer2 = new ConcreteObserver("Observer2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers("Event 1 occurred!");
subject.notifyObservers("Event 2 occurred!");
// 输出
// Observer1 received: Event 1 occurred!
// Observer2 received: Event 1 occurred!
// Observer1 received: Event 2 occurred!
// Observer2 received: Event 2 occurred!
}
}关键点:
- 实现松耦合,Subject 不需要直接依赖具体的观察者实现。
- 常用于事件驱动的系统,如 GUI 事件系统、数据模型更新、实时消息系统。
策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,定义了一系列算法,将每种算法封装到独立的类中,并使它们可以互相替换。这种模式使得算法可以在不影响客户端的情况下发生变化,从而满足开闭原则。
定义策略接口,包含一个行为方法 execute。
Java
package com.practice.service;
public interface Strategy {
int execute(int a, int b);
}实现策略接口,提供求和算法实现。
Java
package com.practice.service.impl;
import com.practice.service.Strategy;
public class AdditionStrategy implements Strategy {
public int execute(int a, int b) {
return a + b;
}
}实现策略接口,提供乘法算法实现。
Java
package com.practice.service.impl;
import com.practice.service.Strategy;
public class MultiplicationStrategy implements Strategy {
public int execute(int a, int b) {
return a * b;
}
}StrategyContext 类持有策略引用,动态调用具体策略实现。
Java
package com.practice.common;
import com.practice.service.Strategy;
public class StrategyContext {
private Strategy strategy;
public StrategyContext(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int a, int b) {
return strategy.execute(a, b);
}
}动态切换策略,无需修改已有代码。
Java
package com.practice.app;
import com.practice.common.StrategyContext;
import com.practice.service.impl.AdditionStrategy;
import com.practice.service.impl.MultiplicationStrategy;
public class StrategyPatternDemo {
public static void main(String[] args) {
StrategyContext context = new StrategyContext(new AdditionStrategy());
System.out.println("加法计算结果: " + context.executeStrategy(5, 3));
// 输出:加法计算结果: 8
context.setStrategy(new MultiplicationStrategy());
System.out.println("乘法计算结果: " + context.executeStrategy(5, 3));
// 输出:乘法计算结果: 15
}
}关键点:
- 策略模式封装了算法,使得算法可以互换。
- 客户端代码与算法解耦,便于扩展新的算法。
装饰器模式
装饰器模式(Decorator Pattern)是一种结构型设计模式,用于在不修改现有类的情况下动态地为对象添加新的功能。通过将对象嵌套在装饰器中,可以以类似于递归的方式叠加多个功能。
定义组件接口,描述核心功能。
Java
package com.practice.service;
public interface Component {
void operation();
}实现组件接口,提供基本功能。
Java
package com.practice.service.impl;
import com.practice.service.Component;
public class ConcreteComponent implements Component {
public void operation() {
System.out.println("基本功能");
}
}抽象装饰器类持有组件引用,通过组合实现扩展。
Java
package com.practice.patterns;
import com.practice.service.Component;
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}具体装饰器实现附加功能A,通过调用父类方法保留原有功能。
Java
package com.practice.common;
import com.practice.patterns.Decorator;
import com.practice.service.Component;
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
System.out.println("添加的功能 A");
}
}具体装饰器实现附加功能B,通过调用父类方法保留原有功能。
Java
package com.practice.common;
import com.practice.patterns.Decorator;
import com.practice.service.Component;
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation();
System.out.println("添加的功能 B");
}
}自由组合装饰器,动态添加功能。
Java
package com.practice.app;
import com.practice.common.ConcreteDecoratorA;
import com.practice.common.ConcreteDecoratorB;
import com.practice.service.Component;
import com.practice.service.impl.ConcreteComponent;
public class DecoratorPatternDemo {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation();
// 输出
// 基本功能
// 添加的功能 A
// 添加的功能 B
}
}关键点:
- 动态为对象添加职责,而不是通过继承。
- 提高了系统的灵活性和可扩展性。
适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个接口转换成客户端期望的另一个接口。适配器模式让原本不兼容的类可以协同工作。
目标接口:定义客户端期望使用的接口,假设新需求是播放 MP4
Java
package com.practice.service;
public interface MediaPlayer {
void request();
}被适配者:已有的类,只支持播放 mp3
Java
package com.practice.common;
public class Mp3Player {
public void playMp3(String fileName) {
System.out.println("播放 mp3 文件: " + fileName);
}
}适配器:将 MediaPlayer 转换为 Mp3Player 的接口
Java
package com.practice.service.impl;
import com.practice.common.Mp3Player;
import com.practice.service.MediaPlayer;
public class MediaAdapter implements MediaPlayer {
private Mp3Player mp3Player;
public MediaAdapter() {
this.mp3Player = new Mp3Player();
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
mp3Player.playMp3(fileName);
} else {
System.out.println("无效的音频类型: " + audioType);
}
}
}客户端类:使用 MediaPlayer 播放音频
Java
package com.practice.service.impl;
import com.practice.service.MediaPlayer;
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("立即播放 mp3 文件: " + fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter();
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("不支持的音频类型: " + audioType);
}
}
}测试代码
Java
package com.practice.app;
import com.practice.service.impl.AudioPlayer;
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "音乐.mp3");
audioPlayer.play("mp4", "视频.mp4");
audioPlayer.play("wav", "音频.wav");
// 输出
// 立即播放 mp3 文件: 音乐.mp3
// 无效的音频类型: mp4
// 不支持的音频类型: wav
}
}关键点:
- 兼容性。
- 解耦。
- 扩展性。
总结与选择指南
在实际开发中,选择合适的设计模式可以事半功倍。以下是常用模式的快速选择指南:
| 设计模式 | 核心思想 | 适用场景 | 举例 |
|---|---|---|---|
| 单例模式 (Singleton) | 确保唯一 | 全局只需要一个实例,如配置、日志、连接池 | Runtime, Spring Bean (默认) |
| 工厂模式 (Factory) | 解耦创建 | 对象创建复杂,或需要根据条件创建不同对象 | BeanFactory, Calendar.getInstance() |
| 观察者模式 (Observer) | 事件驱动 | 一个对象变化需通知多个对象,解耦触发与响应 | Vue 响应式, EventBus, 消息队列 |
| 策略模式 (Strategy) | 算法互换 | 同一任务有多种算法,需要在运行时动态切换 | 支付方式(阿里/微信), 排序算法 |
| 装饰器模式 (Decorator) | 动态增强 | 不修改原类代码,动态添加功能,避免类爆炸 | IO流 (BufferedInputStream), 咖啡加糖 |
| 适配器模式 (Adapter) | 接口转换 | 接口不兼容,需要复用旧代码或协同工作 | Arrays.asList(), 电源适配器 |
快速判断口诀
- 全局唯一 找单例
- 对象复杂 找工厂
- 多方通知 找观察
- 算法切换 找策略
- 功能增强 找装饰
- 接口兼容 找适配
