设计模式精解:构建优雅代码的艺术(二) - 详解
继续我们上一节的设计模式之旅,接下来介绍更多常用且强大的设计模式,每种模式同样包含问题描述、解决方案、代码示例和效果分析。
一. 设计模式详解
6. 适配器模式(Adapter)
问题描述:在软件系统集成过程中,我们经常面临接口不兼容的挑战:
- 现有组件提供的接口与系统需求不匹配
- 第三方库的API设计与项目内部接口规范不一致
- 遗留系统需要与新系统协同工作
- 不同团队开发的模块接口定义存在差异
直接修改现有代码可能违反开闭原则,且在某些情况下(如第三方库)可能根本不可行。
解决方案:通过引入一个中间层(适配器),解决了接口不兼容的问题。该模式的核心思想是:
1. 识别目标接口:定义客户端期望使用的标准接口
2. 封装适配者:将需要适配的类(适配者)封装在适配器内部
3. 实现接口转换:适配器实现目标接口,并在内部将调用转换为适配者的方法
4. 透明使用:客户端只需与目标接口交互,无需关心底层实现细节。
代码示例:
// ===== 1. 对象适配器示例 =====
// 目标接口 - 现代音频播放器接口
interface MediaPlayer {
void play(String audioType, String fileName);
}
// 适配者类 - 遗留的MP3播放器
class LegacyMP3Player {
public void playMP3(String fileName) {
System.out.println("播放MP3文件: " + fileName);
}
}
// 适配者类 - 高级音频解码器
class AdvancedAudioDecoder {
public void decodeMP4(String fileName) {
System.out.println("解码MP4文件: " + fileName);
}
public void decodeVLC(String fileName) {
System.out.println("解码VLC文件: " + fileName);
}
}
// 对象适配器 - 连接MediaPlayer接口与AdvancedAudioDecoder
class MediaAdapter implements MediaPlayer {
private AdvancedAudioDecoder decoder; // 组合方式持有适配者引用
public MediaAdapter(String audioType) {
// 根据音频类型创建相应的解码器
if (audioType.equalsIgnoreCase("mp4")) {
decoder = new AdvancedAudioDecoder();
} else if (audioType.equalsIgnoreCase("vlc")) {
decoder = new AdvancedAudioDecoder();
}
}
@Override
public void play(String audioType, String fileName) {
// 将MediaPlayer接口的调用转换为AdvancedAudioDecoder的方法调用
if (audioType.equalsIgnoreCase("mp4")) {
decoder.decodeMP4(fileName);
} else if (audioType.equalsIgnoreCase("vlc")) {
decoder.decodeVLC(fileName);
}
}
}
// 客户端类 - 音频播放器
class AudioPlayer implements MediaPlayer {
private LegacyMP3Player mp3Player; // 直接使用MP3播放器
@Override
public void play(String audioType, String fileName) {
// 处理原生支持的MP3格式
if (audioType.equalsIgnoreCase("mp3")) {
if (mp3Player == null) {
mp3Player = new LegacyMP3Player();
}
mp3Player.playMP3(fileName);
}
// 使用适配器处理其他格式
else if (audioType.equalsIgnoreCase("mp4") || audioType.equalsIgnoreCase("vlc")) {
MediaAdapter adapter = new MediaAdapter(audioType);
adapter.play(audioType, fileName);
} else {
System.out.println("不支持的音频格式: " + audioType);
}
}
}
// ===== 2. 类适配器示例 =====
// 目标接口 - 电源接口
interface PowerOutlet {
void provideElectricity();
}
// 适配者类 - 220V电源
class Voltage220V {
public void output220VPower() {
System.out.println("提供220V电压");
}
}
// 类适配器 - 将220V电源适配为标准电源接口
class PowerAdapter extends Voltage220V implements PowerOutlet {
@Override
public void provideElectricity() {
// 内部调用父类的方法,并可以添加电压转换逻辑
System.out.println("[适配器工作中] 连接220V电源");
super.output220VPower();
System.out.println("[适配器工作中] 转换为标准电源输出");
}
}
// ===== 3. 接口适配器示例 =====
// 大型接口 - 包含多个方法
interface SmartDevice {
void powerOn();
void powerOff();
void connectWifi();
void disconnectWifi();
void updateFirmware();
void resetSettings();
// 更多方法...
}
// 抽象适配器类 - 提供默认实现
abstract class AbstractDeviceAdapter implements SmartDevice {
@Override
public void powerOn() {}
@Override
public void powerOff() {}
@Override
public void connectWifi() {}
@Override
public void disconnectWifi() {}
@Override
public void updateFirmware() {}
@Override
public void resetSettings() {}
// 其他方法的默认实现...
}
// 具体适配器 - 只重写需要的方法
class SimpleDeviceAdapter extends AbstractDeviceAdapter {
@Override
public void powerOn() {
System.out.println("设备已开机");
}
@Override
public void powerOff() {
System.out.println("设备已关机");
}
@Override
public void connectWifi() {
System.out.println("设备已连接Wi-Fi");
}
// 其他方法使用默认实现
}
// 客户端代码
public class AdapterPatternDemo {
public static void main(String[] args) {
System.out.println("===== 对象适配器示例 =====");
AudioPlayer player = new AudioPlayer();
player.play("mp3", "music.mp3"); // 原生支持
player.play("mp4", "video.mp4"); // 通过适配器支持
player.play("vlc", "movie.vlc"); // 通过适配器支持
player.play("avi", "film.avi"); // 不支持的格式
System.out.println("\n===== 类适配器示例 =====");
PowerOutlet outlet = new PowerAdapter();
outlet.provideElectricity();
System.out.println("\n===== 接口适配器示例 =====");
SmartDevice device = new SimpleDeviceAdapter();
device.powerOn();
device.connectWifi();
device.updateFirmware(); // 使用默认空实现,无输出
device.powerOff();
}
}
效果:
- 兼容性增强:允许不兼容的组件协同工作
- 代码复用:复用现有代码而无需修改
- 透明性:客户端无需了解适配细节
- 低耦合:适配器隔离了客户端和适配者
- 符合开闭原则:扩展功能不修改现有代码
7. 桥接模式(Bridge)
问题描述:当一个类存在两个或多个独立变化的维度时,使用继承会导致类爆炸问题,增加系统复杂度且难以维护。
解决方案:将抽象部分与实现部分分离,使它们可以独立变化。通过组合关系替代继承关系,将多维度变化转化为多个单一维度的独立扩展。
代码示例:
// 实现部分接口
interface Implementor {
void operationImpl();
}
// 具体实现A
class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorA implementation");
}
}
// 具体实现B
class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorB implementation");
}
}
// 抽象部分
abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
// 扩展抽象部分
class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
System.out.println("RefinedAbstraction operation");
implementor.operationImpl();
}
}
// 客户端代码
public class BridgeDemo {
public static void main(String[] args) {
// 创建实现对象
Implementor implA = new ConcreteImplementorA();
Implementor implB = new ConcreteImplementorB();
// 创建抽象对象并注入实现
Abstraction abstraction1 = new RefinedAbstraction(implA);
abstraction1.operation();
Abstraction abstraction2 = new RefinedAbstraction(implB);
abstraction2.operation();
}
}
效果:
- 分离关注点:抽象和实现可以独立变化,便于维护
- 避免类爆炸:使用组合而非继承,减少类的数量
- 更好的扩展性:可以独立扩展抽象部分和实现部分
8. 组合模式(Composite)
问题描述:需要表示对象的部分-整体层次结构,使得客户端可以统一处理单个对象和对象组合。
解决方案:将对象组合成树形结构以表示"部分-整体"的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
代码示例:
import java.util.ArrayList;
import java.util.List;
// 组件接口
interface Component {
void add(Component component);
void remove(Component component);
Component getChild(int index);
void display(int depth);
}
// 叶子节点
class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void add(Component component) {
System.out.println("Cannot add to a leaf");
}
@Override
public void remove(Component component) {
System.out.println("Cannot remove from a leaf");
}
@Override
public Component getChild(int index) {
return null;
}
@Override
public void display(int depth) {
System.out.println("- ".repeat(depth) + name);
}
}
// 组合节点
class Composite implements Component {
private String name;
private List children = new ArrayList<>();
public Composite(String name) {
this.name = name;
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
@Override
public Component getChild(int index) {
return children.get(index);
}
@Override
public void display(int depth) {
System.out.println("+ ".repeat(depth) + name);
for (Component child : children) {
child.display(depth + 1);
}
}
}
// 客户端代码
public class CompositeDemo {
public static void main(String[] args) {
// 创建根节点
Composite root = new Composite("Root");
// 创建一级子节点
Composite branch1 = new Composite("Branch 1");
Composite branch2 = new Composite("Branch 2");
// 创建叶子节点
Leaf leaf1 = new Leaf("Leaf 1");
Leaf leaf2 = new Leaf("Leaf 2");
Leaf leaf3 = new Leaf("Leaf 3");
Leaf leaf4 = new Leaf("Leaf 4");
// 构建树结构
root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch1.add(leaf2);
branch2.add(leaf3);
branch2.add(leaf4);
// 显示树结构
root.display(1);
}
}
效果 :
- 统一处理:客户端可以统一处理单个对象和组合对象
- 易于扩展:可以方便地添加新的组件类型
- 树形结构:自然地表示对象的层次关系
9. 装饰器模式(Decorator)
问题描述:需要动态地向一个对象添加额外的责任,而不修改其原始结构。继承可能导致类爆炸,且静态扩展不够灵活。
解决方案:通过创建包装类(装饰器),在保持被装饰对象接口不变的前提下,动态地给对象添加额外功能。
代码示例:
// 组件接口
interface Component {
void operation();
}
// 具体组件
class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("ConcreteComponent operation");
}
}
// 装饰器抽象类
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
addedFunctionA();
}
private void addedFunctionA() {
System.out.println("Added function A");
}
}
// 具体装饰器B
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
addedFunctionB();
}
private void addedFunctionB() {
System.out.println("Added function B");
}
}
// 客户端代码
public class DecoratorDemo {
public static void main(String[] args) {
// 创建基本组件
Component component = new ConcreteComponent();
// 添加装饰A
Component decoratorA = new ConcreteDecoratorA(component);
decoratorA.operation();
System.out.println();
// 添加装饰B
Component decoratorB = new ConcreteDecoratorB(component);
decoratorB.operation();
System.out.println();
// 装饰器嵌套使用
Component decoratorAB = new ConcreteDecoratorB(new ConcreteDecoratorA(component));
decoratorAB.operation();
}
}
效果:
- 动态扩展:可以在运行时动态地为对象添加功能
- 灵活组合:可以任意组合不同的装饰器,实现多种功能组合
- 遵循开闭原则:无需修改原有代码即可扩展功能
10. 外观模式(Facade)
问题描述:在复杂系统中,客户端需要与多个子系统交互,导致客户端代码复杂且难以维护。
解决方案:为子系统中的一组接口提供一个统一的高层接口,使客户端可以通过简单的接口与子系统通信,而不需要了解子系统的内部细节。
代码示例:
// 子系统A
class SubsystemA {
public void operationA() {
System.out.println("SubsystemA operation");
}
}
// 子系统B
class SubsystemB {
public void operationB() {
System.out.println("SubsystemB operation");
}
}
// 子系统C
class SubsystemC {
public void operationC() {
System.out.println("SubsystemC operation");
}
}
// 外观类
class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
private SubsystemC subsystemC;
public Facade() {
this.subsystemA = new SubsystemA();
this.subsystemB = new SubsystemB();
this.subsystemC = new SubsystemC();
}
// 提供简化的接口
public void operation1() {
System.out.println("Facade operation 1:");
subsystemA.operationA();
subsystemB.operationB();
}
public void operation2() {
System.out.println("Facade operation 2:");
subsystemB.operationB();
subsystemC.operationC();
}
public void operation3() {
System.out.println("Facade operation 3:");
subsystemA.operationA();
subsystemB.operationB();
subsystemC.operationC();
}
}
// 客户端代码
public class FacadeDemo {
public static void main(String[] args) {
// 通过外观类访问子系统
Facade facade = new Facade();
// 执行不同的操作组合
facade.operation1();
System.out.println();
facade.operation2();
System.out.println();
facade.operation3();
}
}
效果:
- 简化客户端:隐藏子系统复杂性,提供简单接口
- 降低耦合度:减少客户端与子系统的直接交互
- 更好的分层:清晰划分系统层次,有利于维护
11. 享元模式(Flyweight)
问题描述:当需要创建大量相似对象时,会消耗过多内存,影响系统性能。
解决方案:通过共享多个对象所共有的相同状态,来减少内存使用和提高性能。
代码示例:
import java.util.HashMap;
import java.util.Map;
// 享元接口
interface Flyweight {
void operation(String extrinsicState);
}
// 具体享元
class ConcreteFlyweight implements Flyweight {
private String intrinsicState; // 内部状态,可共享
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String extrinsicState) {
System.out.println("Intrinsic State: " + intrinsicState + ",Extrinsic State: " + extrinsicState);
}
}
// 享元工厂
class FlyweightFactory {
private Map flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
if (!flyweights.containsKey(key)) {
// 创建新的享元对象
flyweights.put(key, new ConcreteFlyweight(key));
System.out.println("Creating flyweight for key: " + key);
}
return flyweights.get(key);
}
public int getFlyweightCount() {
return flyweights.size();
}
}
// 客户端代码
public class FlyweightDemo {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
// 获取享元对象
Flyweight flyweight1 = factory.getFlyweight("A");
flyweight1.operation("First call");
Flyweight flyweight2 = factory.getFlyweight("B");
flyweight2.operation("Second call");
// 复用已存在的享元对象
Flyweight flyweight3 = factory.getFlyweight("A");
flyweight3.operation("Third call");
// 验证是否为同一个对象
System.out.println("flyweight1 and flyweight3 are the same object: " + (flyweight1 == flyweight3));
// 显示创建的享元对象数量
System.out.println("Number of flyweight objects created: " + factory.getFlyweightCount());
}
}
效果:
- 减少对象创建:共享相同内部状态的对象,减少内存占用
- 提高性能:避免创建大量相似对象带来的性能开销
- 分离内部/外部状态:将状态分为可共享的内部状态和不可共享的外部状态
12. 代理模式(Proxy)
问题描述:在软件系统中,直接访问某些对象可能会带来复杂性或安全性问题。直接修改原始对象会破坏封装性和单一职责原则,因此需要一种机制在不改变原始对象的情况下控制对其的访问。
解决方案:通过引入代理对象作为原始对象的"替身",在保持与原始对象相同接口的同时,提供额外的控制层。当客户端请求到达时,代理对象可以在调用真实对象前后执行额外操作,或者完全拦截请求,实现对真实对象的透明控制。代理模式的核心结构包括:
- 抽象主题(Subject):定义代理对象和真实主题的共同接口
- 真实主题(RealSubject):实际执行业务逻辑的对象
- 代理(Proxy):持有对真实主题的引用,控制对真实主题的访问,并可以添加额外功能
代码示例:
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
// 抽象主题 - 图片接口
interface Image {
void display();
String getFilename();
}
// 真实主题 - 实际的图片对象
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk(); // 加载图片是一个开销较大的操作
}
private void loadImageFromDisk() {
System.out.println("从磁盘加载图片: " + filename);
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void display() {
System.out.println("显示图片: " + filename);
}
@Override
public String getFilename() {
return filename;
}
}
// 1. 虚拟代理 - 延迟加载图片
class VirtualImageProxy implements Image {
private String filename;
private RealImage realImage; // 延迟初始化
public VirtualImageProxy(String filename) {
this.filename = filename;
}
@Override
public void display() {
// 只有在真正需要时才创建RealImage对象
if (realImage == null) {
System.out.println("[虚拟代理] 延迟初始化图片对象");
realImage = new RealImage(filename);
}
realImage.display();
}
@Override
public String getFilename() {
return filename;
}
}
// 2. 保护代理 - 控制访问权限
class ProtectionImageProxy implements Image {
private Image realImage;
private String userRole;
public ProtectionImageProxy(Image realImage, String userRole) {
this.realImage = realImage;
this.userRole = userRole;
}
@Override
public void display() {
// 检查用户权限
if (userRole.equals("admin") || userRole.equals("user")) {
System.out.println("[保护代理] 权限验证通过");
realImage.display();
} else {
System.out.println("[保护代理] 权限不足,无法访问图片: " + realImage.getFilename());
}
}
@Override
public String getFilename() {
return realImage.getFilename();
}
}
// 3. 缓存代理 - 缓存已加载的图片
class CachedImageProxy implements Image {
private static Map imageCache = new HashMap<>();
private String filename;
public CachedImageProxy(String filename) {
this.filename = filename;
}
@Override
public void display() {
// 检查缓存
if (!imageCache.containsKey(filename)) {
System.out.println("[缓存代理] 缓存未命中,创建新图片对象");
imageCache.put(filename, new RealImage(filename));
} else {
System.out.println("[缓存代理] 从缓存获取图片");
}
imageCache.get(filename).display();
}
@Override
public String getFilename() {
return filename;
}
}
// 4. 日志记录代理
class LoggingImageProxy implements Image {
private static final Logger logger = Logger.getLogger(LoggingImageProxy.class.getName());
private Image realImage;
public LoggingImageProxy(Image realImage) {
this.realImage = realImage;
}
@Override
public void display() {
// 访问前记录日志
System.out.println("[日志代理] 开始访问图片: " + realImage.getFilename());
long startTime = System.currentTimeMillis();
realImage.display(); // 调用真实对象
long endTime = System.currentTimeMillis();
// 访问后记录日志
System.out.println("[日志代理] 图片访问完成,耗时: " + (endTime - startTime) + "ms");
}
@Override
public String getFilename() {
return realImage.getFilename();
}
}
// 5. 复合代理 - 组合多种代理功能
class CompositeImageProxy implements Image {
private Image proxiedImage;
public CompositeImageProxy(String filename, String userRole) {
// 构建代理链: 虚拟代理 -> 保护代理 -> 日志代理
proxiedImage = new VirtualImageProxy(filename);
proxiedImage = new ProtectionImageProxy(proxiedImage, userRole);
proxiedImage = new LoggingImageProxy(proxiedImage);
}
@Override
public void display() {
proxiedImage.display();
}
@Override
public String getFilename() {
return proxiedImage.getFilename();
}
}
// 客户端代码
public class ImageProxyDemo {
public static void main(String[] args) {
System.out.println("===== 测试虚拟代理 =====");
Image virtualProxy = new VirtualImageProxy("nature.jpg");
System.out.println("图片代理已创建,但实际图片尚未加载");
virtualProxy.display(); // 首次调用时加载图片
virtualProxy.display(); // 第二次调用时已加载
System.out.println("\n===== 测试保护代理 =====");
Image realImage = new RealImage("confidential.jpg");
Image adminProxy = new ProtectionImageProxy(realImage, "admin");
Image guestProxy = new ProtectionImageProxy(realImage, "guest");
adminProxy.display(); // 管理员可以访问
guestProxy.display(); // 访客无权访问
System.out.println("\n===== 测试缓存代理 =====");
Image cacheProxy1 = new CachedImageProxy("landscape.jpg");
Image cacheProxy2 = new CachedImageProxy("landscape.jpg");
cacheProxy1.display(); // 第一次访问,创建对象
cacheProxy2.display(); // 第二次访问,使用缓存
System.out.println("\n===== 测试日志代理 =====");
Image loggingProxy = new LoggingImageProxy(new RealImage("document.jpg"));
loggingProxy.display();
System.out.println("\n===== 测试复合代理 =====");
Image compositeProxy = new CompositeImageProxy("complex.jpg", "user");
compositeProxy.display(); // 依次应用:虚拟代理、保护代理、日志代理
}
}
效果:
- 职责分离:将访问控制逻辑与业务逻辑分离
- 开闭原则:无需修改原始对象即可添加新功能
- 透明度:客户端无需关心是否使用代理
- 灵活性:可以动态切换不同类型的代理
13. 解释器模式(Interpreter)
问题描述:当需要解释一门简单语言的语法或表达式时,直接编写复杂的解析逻辑会导致代码难以维护。
解决方案:定义语言的文法,并且建立解释器来解释该语言中的表达式。
代码示例:
// 抽象表达式
interface Expression {
boolean interpret(String context);
}
// 终结表达式
class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data) {
this.data = data;
}
@Override
public boolean interpret(String context) {
return context.contains(data);
}
}
// 非终结表达式 - AND
class AndExpression implements Expression {
private Expression expr1;
private Expression expr2;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
// 客户端代码
public class InterpreterPatternDemo {
public static void main(String[] args) {
// 创建表达式: (Robert AND John) OR (Alice)
Expression robert = new TerminalExpression("Robert");
Expression john = new TerminalExpression("John");
Expression andExpr = new AndExpression(robert, john);
Expression alice = new TerminalExpression("Alice");
// OR表达式的实现类似,这里省略
System.out.println("'Robert John' 包含 'Robert AND John': " +
andExpr.interpret("Robert John"));
}
}
效果:
- 易于实现简单语言
- 可扩展性强
- 复杂语法难以维护
14. 模板方法模式(Template Method)
问题描述:在软件设计中,经常遇到这样的场景:多个类实现了相似的算法流程,但其中某些步骤在不同类中有特定实现。直接复制算法框架会导致代码冗余,而完全分离算法又会破坏整体结构的一致性,难以维护。
解决方案:在抽象父类中定义算法的整体流程,使用一系列方法调用组成算法步骤,子类通过重写抽象方法和钩子方法,定制算法中的可变部分,同时保留算法骨架不变。
代码示例:
// 抽象基类 - 定义饮料制作的算法骨架
abstract class Beverage {
// 模板方法 - 定义算法的骨架,声明为final防止子类修改流程
public final void prepareBeverage() {
boilWater(); // 步骤1:烧水
brew(); // 步骤2:冲泡(抽象方法,由子类实现)
pourInCup(); // 步骤3:倒入杯中
// 钩子方法 - 子类可选择是否覆盖
if (customerWantsCondiments()) {
addCondiments(); // 步骤4:添加调料(抽象方法,由子类实现)
}
System.out.println("饮料准备完成!\n");
}
// 具体方法 - 父类已实现的共同步骤
private void boilWater() {
System.out.println("将水煮沸");
}
private void pourInCup() {
System.out.println("倒入杯中");
}
// 抽象方法 - 由子类实现的特定步骤
protected abstract void brew();
protected abstract void addCondiments();
// 钩子方法 - 子类可以覆盖,也可以不覆盖
protected boolean customerWantsCondiments() {
return true; // 默认添加调料
}
}
// 具体子类 - 实现咖啡的制作
class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("添加糖和牛奶");
}
// 覆盖钩子方法,提供自定义行为
@Override
protected boolean customerWantsCondiments() {
// 在实际应用中,这里可能会询问用户
return true; // 假设用户想要添加调料
}
}
// 具体子类 - 实现茶的制作
class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("用沸水浸泡茶包");
}
@Override
protected void addCondiments() {
System.out.println("添加柠檬");
}
// 覆盖钩子方法,提供自定义行为
@Override
protected boolean customerWantsCondiments() {
// 在实际应用中,这里可能会询问用户
return true; // 假设用户想要添加调料
}
}
// 具体子类 - 实现绿茶的制作(不添加调料)
class GreenTea extends Beverage {
@Override
protected void brew() {
System.out.println("用温水冲泡绿茶叶");
}
@Override
protected void addCondiments() {
System.out.println("添加蜂蜜");
}
// 覆盖钩子方法,不添加调料
@Override
protected boolean customerWantsCondiments() {
return false; // 绿茶通常不加调料
}
}
// 客户端代码
public class BeveragePreparation {
public static void main(String[] args) {
System.out.println("===== 准备咖啡 =====");
Beverage coffee = new Coffee();
coffee.prepareBeverage();
System.out.println("===== 准备茶 =====");
Beverage tea = new Tea();
tea.prepareBeverage();
System.out.println("===== 准备绿茶 =====");
Beverage greenTea = new GreenTea();
greenTea.prepareBeverage();
}
}
效果:
- 代码复用最大化:核心算法框架集中在父类,消除冗余代码
- 开闭原则体现:扩展新算法变体只需添加子类,无需修改现有代码
- 结构一致性保证:所有子类共享相同的算法流程,确保行为符合预期
- 分离关注点:将固定部分与变化部分清晰分离,提高代码可读性
- 控制反转:父类控制算法整体流程,子类只负责实现特定步骤
15. 责任链模式(Chain of Responsibility)
问题描述:在许多场景中,一个请求需要经过多个对象的处理流程,每个对象都可能需要处理该请求或将其传递给下一个对象。传统实现方式会导致发送者与接收者之间的紧密耦合,难以灵活调整处理流程。
解决方案:责任链模式通过构建处理对象的链式结构,优雅地解决了这一问题。在该模式中:
1. 抽象处理者(Handler):定义处理请求的接口,并持有对下一处理者的引用
2. 具体处理者(ConcreteHandlers):实现处理逻辑,决定是处理请求还是传递给下一处理者
3. 链式构建:客户端负责构建处理链,确定处理顺序。
代码示例:
// 抽象处理者(Handler)类
abstract class Handler {
protected Handler nextHandler; // 对下一个处理者的引用
// 设置下一个处理者
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
// 声明处理请求的抽象方法
public abstract void handleRequest(int request);
}
// 具体处理者 - 处理1-10的请求
class ConcreteHandler1 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 1 && request <= 10) {
System.out.println("ConcreteHandler1 处理请求: " + request);
} else if (nextHandler != null) {
// 如果不能处理,将请求传递给下一个处理者
System.out.println("ConcreteHandler1 无法处理请求: " + request + ",传递给下一个处理者");
nextHandler.handleRequest(request);
} else {
System.out.println("请求: " + request + " 无人处理");
}
}
}
// 具体处理者 - 处理11-20的请求
class ConcreteHandler2 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 11 && request <= 20) {
System.out.println("ConcreteHandler2 处理请求: " + request);
} else if (nextHandler != null) {
System.out.println("ConcreteHandler2 无法处理请求: " + request + ",传递给下一个处理者");
nextHandler.handleRequest(request);
} else {
System.out.println("请求: " + request + " 无人处理");
}
}
}
// 具体处理者 - 处理21-30的请求
class ConcreteHandler3 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 21 && request <= 30) {
System.out.println("ConcreteHandler3 处理请求: " + request);
} else if (nextHandler != null) {
System.out.println("ConcreteHandler3 无法处理请求: " + request + ",传递给下一个处理者");
nextHandler.handleRequest(request);
} else {
System.out.println("请求: " + request + " 无人处理");
}
}
}
// 主类 - 客户端代码
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// 创建具体处理者对象
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
// 创建处理链,设置处理顺序
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
// 测试不同的请求
System.out.println("===== 测试责任链模式 =====");
handler1.handleRequest(5); // 应由ConcreteHandler1处理
System.out.println();
handler1.handleRequest(15); // 应由ConcreteHandler2处理
System.out.println();
handler1.handleRequest(25); // 应由ConcreteHandler3处理
System.out.println();
handler1.handleRequest(35); // 超出处理范围,无人处理
// 演示动态改变处理链顺序
System.out.println("\n===== 演示动态改变处理链顺序 =====");
handler2.setNextHandler(handler1); // 改变处理顺序
handler1.setNextHandler(handler3);
handler2.handleRequest(5); // 由于处理顺序改变,流程会不同
}
}
效果:
- 耦合度降低:发送者无需知道具体由哪个对象处理请求
- 灵活性高:可动态调整处理链的顺序和各处理者职责
- 易于扩展:添加新的处理者无需修改现有代码,符合开闭原则
- 单一职责:每个处理者专注于自己的处理逻辑,提高代码可维护性
16. 命令模式(Command)
问题描述:需要将请求的发送者和接收者解耦,使发送者不直接依赖于接收者的具体实现,并且希望支持请求的撤销、重做等操作。
解决方案:将请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,支持可撤销操作。
代码示例:
import java.util.Stack;
// 命令接口
interface Command {
void execute();
void undo();
}
// 接收者
class Receiver {
public void action(String message) {
System.out.println("Receiver: " + message);
}
}
// 具体命令
class ConcreteCommand implements Command {
private Receiver receiver;
private String message;
public ConcreteCommand(Receiver receiver, String message) {
this.receiver = receiver;
this.message = message;
}
@Override
public void execute() {
receiver.action(message);
}
@Override
public void undo() {
receiver.action("Undo: " + message);
}
}
// 调用者
class Invoker {
private Stack commandHistory = new Stack<>();
public void executeCommand(Command command) {
command.execute();
commandHistory.push(command);
}
public void undoCommand() {
if (!commandHistory.isEmpty()) {
Command command = commandHistory.pop();
command.undo();
} else {
System.out.println("Nothing to undo");
}
}
}
// 客户端代码
public class CommandDemo {
public static void main(String[] args) {
// 创建接收者
Receiver receiver = new Receiver();
// 创建命令
Command command1 = new ConcreteCommand(receiver, "Command 1 executed");
Command command2 = new ConcreteCommand(receiver, "Command 2 executed");
// 创建调用者
Invoker invoker = new Invoker();
// 执行命令
invoker.executeCommand(command1);
invoker.executeCommand(command2);
// 撤销命令
invoker.undoCommand();
invoker.undoCommand();
invoker.undoCommand(); // 尝试撤销不存在的命令
}
}
效果:
- 解耦发送者和接收者:发送者不需要知道接收者如何执行命令
- 支持撤销/重做:可以轻松实现命令的撤销和重做功能
- 复合命令:可以组合多个命令形成更复杂的宏命令
17. 迭代器模式(Iterator)
问题描述:需要在不暴露集合内部结构的情况下,提供一种方法来访问集合中的元素,并且支持不同的遍历方式。
解决方案:提供一个对象来顺序访问聚合对象中的元素,而不暴露聚合对象的内部表示。
代码示例:
import java.util.ArrayList;
import java.util.List;
// 迭代器接口
interface Iterator {
boolean hasNext();
Object next();
}
// 具体迭代器
class ConcreteIterator implements Iterator {
private List

浙公网安备 33010602011771号