设计模式精解:构建优雅代码的艺术(二) - 详解

继续我们上一节的设计模式之旅,接下来介绍更多常用且强大的设计模式,每种模式同样包含问题描述、解决方案、代码示例和效果分析。

一. 设计模式详解

 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 items;
    private int position = 0;
    public ConcreteIterator(List items) {
        this.items = items;
    }
    @Override
    public boolean hasNext() {
        return position < items.size();
    }
    @Override
    public Object next() {
        if (hasNext()) {
            return items.get(position++);
        }
        return null;
    }
}
// 聚合接口
interface Aggregate {
    Iterator createIterator();
}
// 具体聚合
class ConcreteAggregate implements Aggregate {
    private List items = new ArrayList<>();
    public void addItem(Object item) {
        items.add(item);
    }
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(items);
    }
}
// 客户端代码
public class IteratorDemo {
    public static void main(String[] args) {
        ConcreteAggregate aggregate = new ConcreteAggregate();
        aggregate.addItem("Item 1");
        aggregate.addItem("Item 2");
        aggregate.addItem("Item 3");
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

效果:

  • 封装遍历逻辑:隐藏了集合的内部结构
  • 支持多种遍历方式:可以为同一集合实现不同的迭代器
  • 符合单一职责原则:将遍历职责从集合中分离出来

18. 中介者模式(Mediator)

问题描述:在复杂系统中,对象之间的直接通信会导致大量的相互依赖关系,形成紧密耦合的"蜘蛛网"结构,难以维护和扩展。

解决方案:定义一个中介对象,封装一系列对象之间的交互,使对象之间不需要显式地相互引用,从而降低它们之间的耦合度。

代码示例:

import java.util.HashMap;
import java.util.Map;
// 中介者接口
interface Mediator {
    void registerColleague(String name, Colleague colleague);
    void sendMessage(String from, String to, String message);
}
// 具体中介者
class ConcreteMediator implements Mediator {
    private Map colleagues = new HashMap<>();
    @Override
    public void registerColleague(String name, Colleague colleague) {
        colleagues.put(name, colleague);
        colleague.setMediator(this);
        colleague.setName(name);
    }
    @Override
    public void sendMessage(String from, String to, String message) {
        Colleague receiver = colleagues.get(to);
        if (receiver != null) {
            receiver.receiveMessage(from, message);
        } else {
            System.out.println("Recipient " + to + " not found");
        }
    }
}
// 同事类抽象
abstract class Colleague {
    protected Mediator mediator;
    protected String name;
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
    public void setName(String name) {
        this.name = name;
    }
    public abstract void sendMessage(String to, String message);
    public abstract void receiveMessage(String from, String message);
}
// 具体同事类
class ConcreteColleague extends Colleague {
    @Override
    public void sendMessage(String to, String message) {
        System.out.println(name + " sends to " + to + ": " + message);
        mediator.sendMessage(name, to, message);
    }
    @Override
    public void receiveMessage(String from, String message) {
        System.out.println(name + " receives from " + from + ": " +
        message);
    }
}
// 客户端代码
public class MediatorDemo {
    public static void main(String[] args) {
        // 创建中介者
        Mediator mediator = new ConcreteMediator();
        // 创建同事并注册到中介者
        Colleague colleague1 = new ConcreteColleague();
        Colleague colleague2 = new ConcreteColleague();
        Colleague colleague3 = new ConcreteColleague();
        mediator.registerColleague("Alice", colleague1);
        mediator.registerColleague("Bob", colleague2);
        mediator.registerColleague("Charlie", colleague3);
        // 发送消息
        colleague1.sendMessage("Bob", "Hello Bob!");
        colleague2.sendMessage("Alice", "Hi Alice!");
        colleague3.sendMessage("Alice", "Hello Alice!");
        colleague1.sendMessage("David", "Hello David!"); // 不存在的接收者
    }
}

效果:

  • 降低耦合度:对象之间通过中介者间接通信,减少直接依赖
  • 集中控制交互:所有对象间的交互由中介者统一管理
  • 简化对象协议:对象只需与中介者交互,协议更简单

19. 备忘录模式(Memento)

问题描述:需要在不破坏封装性的前提下,捕获一个对象的内部状态,并在需要时恢复该对象到之前的状态。

解决方案:在不破坏封装性的前提下,将对象的状态保存在一个备忘录对象中,并由管理者进行保存和恢复。

代码示例:

import java.util.ArrayList;
import java.util.List;
// 备忘录类
class Memento {
    private String state;
    public Memento(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
}
// 发起人(Originator)
class Originator {
    private String state;
    public void setState(String state) {
        this.state = state;
        System.out.println("Current state: " + state);
    }
    public Memento saveStateToMemento() {
        System.out.println("Saving state: " + state);
        return new Memento(state);
    }
    public void restoreStateFromMemento(Memento memento) {
        this.state = memento.getState();
        System.out.println("Restored state: " + state);
    }
}
// 管理者(Caretaker)
class Caretaker {
    private List mementoList = new ArrayList<>();
    public void addMemento(Memento memento) {
        mementoList.add(memento);
    }
    public Memento getMemento(int index) {
        return mementoList.get(index);
    }
}
// 客户端代码
public class MementoDemo {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        // 设置状态并保存
        originator.setState("State 1");
        caretaker.addMemento(originator.saveStateToMemento());
        originator.setState("State 2");
        caretaker.addMemento(originator.saveStateToMemento());
        originator.setState("State 3");
        caretaker.addMemento(originator.saveStateToMemento());
        // 恢复到第一个状态
        originator.restoreStateFromMemento(caretaker.getMemento(0));
        // 恢复到第二个状态
        originator.restoreStateFromMemento(caretaker.getMemento(1));
    }
}

效果:

  • 保存状态快照:可以保存和恢复对象的历史状态
  • 封装性保护:备忘录对象不破坏发起人对象的封装
  • 简化发起人职责:发起人无需管理状态历史,由管理者负责

20. 观察者模式(Observer)

问题描述:在一个系统中,当一个对象的状态发生变化时,需要自动通知依赖于它的其他对象,并且这些对象需要根据状态变化做出相应的更新。

解决方案:定义对象间的一种一对多依赖关系,当一个对象(主题)状态发生改变时,所有依赖它的对象(观察者)都会得到通知并自动更新。

代码示例:

import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
    void update(String message);
}
// 具体观察者
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);
    }
}
// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
// 具体主题
class ConcreteSubject implements Subject {
    private List observers = new ArrayList<>();
    private String message;
    @Override
    public void registerObserver(Observer observer) {
        if (!observers.contains(observer)) {
            observers.add(observer);
        }
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    // 设置消息
    public void setMessage(String message) {
        this.message = message;
        notifyObservers(); // 状态改变时通知观察者
    }
}
// 客户端代码
public class ObserverDemo {
    public static void main(String[] args) {
        // 创建主题
        ConcreteSubject subject = new ConcreteSubject();
        // 创建观察者
        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");
        Observer observer3 = new ConcreteObserver("Observer 3");
        // 注册观察者
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);
        subject.registerObserver(observer3);
        // 发送消息
        subject.setMessage("Hello, observers!");
        // 移除一个观察者
        subject.removeObserver(observer2);
        // 再次发送消息
        subject.setMessage("Observer 2 has been removed!");
    }
}

效果:

  • 解耦通知者与接收者:主题和观察者之间是松耦合的
  • 动态订阅:观察者可以动态地订阅和取消订阅
  • 广播通信:主题可以同时向多个观察者发送通知

21. 状态模式(State)

问题描述:当一个对象的行为取决于其状态,并且它必须在运行时根据状态改变其行为时,使用大量的条件语句会使代码难以维护。

解决方案:将对象的各种状态封装成独立的类,让对象的行为随其状态的改变而改变,每个状态类负责处理特定状态下的行为。

代码示例:

// 状态接口
interface State {
    void handle(Context context);
}
// 具体状态A
class ConcreteStateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("Handling in State A");
        // 转换到状态B
        context.setState(new ConcreteStateB());
    }
}
// 具体状态B
class ConcreteStateB implements State {
    @Override
    public void handle(Context context) {
        System.out.println("Handling in State B");
        // 转换到状态A
        context.setState(new ConcreteStateA());
    }
}
// 上下文类
class Context {
    private State state;
    public Context(State initialState) {
        this.state = initialState;
    }
    public void setState(State state) {
        this.state = state;
    }
    public void request() {
        state.handle(this);
    }
}
// 客户端代码
public class StateDemo {
    public static void main(String[] args) {
        // 创建初始状态
        State initialState = new ConcreteStateA();
        // 创建上下文并设置初始状态
        Context context = new Context(initialState);
        // 执行请求,触发状态转换
        context.request(); // 从A转换到B
        context.request(); // 从B转换到A
        context.request(); // 从A转换到B
    }
}

效果:

  • 消除条件语句:将与状态相关的逻辑分散到各个状态类中
  • 状态转换显式化:状态转换逻辑清晰可见
  • 易于扩展:添加新状态只需创建新的状态类

22. 策略模式(Strategy)

问题描述:在一个系统中,一个类可能有多种算法或行为,使用条件语句会使代码复杂且难以扩展。

解决方案:定义一系列算法,将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

代码示例:

// 策略接口
interface Strategy {
    int execute(int a, int b);
}
// 具体策略A:加法
class ConcreteStrategyAdd implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a + b;
    }
}
// 具体策略B:减法
class ConcreteStrategySubtract implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a - b;
    }
}
// 具体策略C:乘法
class ConcreteStrategyMultiply implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a * b;
    }
}
// 上下文类
class Context {
    private Strategy strategy;
    // 设置策略
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    // 执行策略
    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }
}
// 客户端代码
public class StrategyDemo {
    public static void main(String[] args) {
        Context context = new Context();
        // 使用加法策略
        context.setStrategy(new ConcreteStrategyAdd());
        int resultAdd = context.executeStrategy(10, 5);
        System.out.println("10 + 5 = " + resultAdd);
        // 使用减法策略
        context.setStrategy(new ConcreteStrategySubtract());
        int resultSubtract = context.executeStrategy(10, 5);
        System.out.println("10 - 5 = " + resultSubtract);
        // 使用乘法策略
        context.setStrategy(new ConcreteStrategyMultiply());
        int resultMultiply = context.executeStrategy(10, 5);
        System.out.println("10 * 5 = " + resultMultiply);
    }
}

效果:

  • 避免条件语句:消除了复杂的条件判断
  • 运行时切换算法:可以在运行时动态切换算法
  • 易于扩展:添加新策略只需实现接口,符合开闭原则

        23. 访问者模式(Visitor)

        问题描述:在对象结构相对稳定,但操作算法经常变化的情况下,直接在对象类中添加新操作会导致类不断修改,违反开闭原则。

        解决方案:将数据结构与数据操作分离,通过一个访问者对象定义作用于各元素的新操作,使得可以在不改变元素类的前提下定义新的操作。

        代码示例:

        import java.util.ArrayList;
        import java.util.List;
        // 元素接口
        interface Element {
            void accept(Visitor visitor);
        }
        // 具体元素A
        class ConcreteElementA implements Element {
            @Override
            public void accept(Visitor visitor) {
                visitor.visitConcreteElementA(this);
            }
            public String operationA() {
                return "ConcreteElementA operation";
            }
        }
        // 具体元素B
        class ConcreteElementB implements Element {
            @Override
            public void accept(Visitor visitor) {
                visitor.visitConcreteElementB(this);
            }
            public String operationB() {
                return "ConcreteElementB operation";
            }
        }
        // 访问者接口
        interface Visitor {
            void visitConcreteElementA(ConcreteElementA element);
            void visitConcreteElementB(ConcreteElementB element);
        }
        // 具体访问者1
        class ConcreteVisitor1 implements Visitor {
            @Override
            public void visitConcreteElementA(ConcreteElementA element) {
                System.out.println("Visitor1 processing " + element.operationA());
            }
            @Override
            public void visitConcreteElementB(ConcreteElementB element) {
                System.out.println("Visitor1 processing " + element.operationB());
            }
        }
        // 具体访问者2
        class ConcreteVisitor2 implements Visitor {
            @Override
            public void visitConcreteElementA(ConcreteElementA element) {
                System.out.println("Visitor2 processing " + element.operationA());
            }
            @Override
            public void visitConcreteElementB(ConcreteElementB element) {
                System.out.println("Visitor2 processing " + element.operationB());
            }
        }
        // 对象结构
        class ObjectStructure {
            private List elements = new ArrayList<>();
            public void addElement(Element element) {
                elements.add(element);
            }
            public void accept(Visitor visitor) {
                for (Element element : elements) {
                    element.accept(visitor);
                }
            }
        }
        // 客户端代码
        public class VisitorDemo {
            public static void main(String[] args) {
                // 创建对象结构
                ObjectStructure objectStructure = new ObjectStructure();
                // 添加元素
                objectStructure.addElement(new ConcreteElementA());
                objectStructure.addElement(new ConcreteElementB());
                // 创建访问者并执行操作
                Visitor visitor1 = new ConcreteVisitor1();
                objectStructure.accept(visitor1);
                System.out.println();
                Visitor visitor2 = new ConcreteVisitor2();
                objectStructure.accept(visitor2);
            }
        }

        效果:

        • 操作与数据分离:可以在不修改元素类的情况下添加新操作
        • 双分派机制:根据访问者类型和元素类型动态决定执行的操作
        • 易于添加新操作:添加新访问者即可实现新功能,符合开闭原则

        二. 设计模式间的关系与选择

        各种设计模式之间并非孤立存在,它们有着密切的联系,在实际应用中也经常组合使用:

        1. 创建型模式之间的关系:

        • 工厂方法是模板方法在对象创建中的应用
        • 抽象工厂可以使用工厂方法来创建产品
        • 建造者关注复杂对象的构造过程,而抽象工厂关注产品家族
        • 原型和单例都涉及对象创建,但目的相反(原型创建多个对象,单例确保唯一对象)

        2. 结构型模式之间的关系:

        • 适配器改变接口,装饰器不改变接口但增强功能
        • 桥接和装饰器都基于组合而非继承
        • 外观提供简化接口,适配器转换接口

        3. 行为型模式之间的关系:

        • 策略封装算法,命令封装请求
        • 观察者和中介者都处理对象间通信,但观察者是一对多,中介者是多对多
        • 状态和策略结构相似,但状态的行为变化由对象内部状态驱动,策略由客户端选择

        如何选择合适的设计模式:

        1. 分析问题本质:理解需要解决的核心问题是什么
        2. 考虑系统需求:可扩展性、可维护性、性能等要求
        3. 评估模式适用性:每种模式都有其适用场景
        4. 权衡设计复杂度:不要过度设计,避免为了使用模式而使用模式
        5. 结合实际经验:根据项目经验和团队熟悉度选择

        三. 设计模式在实际开发中的应用

        1. 企业应用架构中的设计模式

        在企业级应用开发中,设计模式的应用非常广泛:

        1. MVC架构:

        • 模型层:使用工厂模式创建领域对象
        • 视图层:使用装饰器模式增强UI组件
        • 控制器:使用策略模式处理不同请求

        2. Spring框架中的设计模式:

        • 单例模式:默认情况下,Spring容器中的Bean是单例的
        • 工厂模式:BeanFactory和ApplicationContext用于创建对象
        • 代理模式:AOP功能基于代理模式实现
        • 观察者模式:事件监听机制

        3. 微服务架构中的设计模式:

        •  外观模式:API网关作为客户端和微服务之间的统一接口
        •  策略模式:不同服务的负载均衡策略
        •  断路器模式:防止系统级联故障

        2. 性能优化中的设计模式

        设计模式也常用于性能优化:

        1. 享元模式 :用于缓存对象,减少内存使用
        2. 单例模式 :避免重复创建重量级对象
        3. 命令模式 :用于批处理和队列任务
        4. 装饰器模式 :在不影响性能的情况下动态增强功能

        四. 设计模式的未来发展

        随着软件开发的不断演进,设计模式也在不断发展:

        1. 与敏捷开发的结合:

        • 在敏捷开发中,设计模式作为重构的目标,而不是预先设计
        • 通过持续重构,逐步引入适当的设计模式

        2. 与函数式编程的融合:   

        • 函数式接口与策略模式的结合
        • Lambda表达式简化观察者、命令等模式的实现
        • 不可变对象和设计模式的结合

        3. 领域驱动设计(DDD)中的应用:

        • 实体、值对象、领域服务等概念与设计模式的结合
        • 聚合根与组合模式
        • 领域事件与观察者模式

        4. 微服务架构中的新模式:

        • API网关模式
        • 服务发现模式
        • 断路器模式
        • 事件溯源模式

        五. 设计模式学习路径

        为了更有效地学习和应用设计模式,推荐以下学习路径:

        1. 基础阶段:

        • 掌握面向对象设计原则
        • 学习常用的设计模式(单例、工厂、观察者等)
        • 通过简单示例理解模式的基本思想

        2. 进阶阶段:

        • 学习剩余的设计模式
        • 理解模式之间的关系和组合使用
        • 分析开源框架中的设计模式应用

        3. 实践阶段:

        • 在实际项目中应用设计模式
        • 进行代码重构,引入合适的设计模式
        • 总结和分享应用经验

        4. 精通阶段:

        • 能够根据问题选择最合适的设计模式
        • 能够识别过度设计和模式滥用
        • 能够创新和定制设计模式

        总结

        设计模式是软件设计的宝贵经验总结,是连接理论和实践的桥梁。通过系统学习和应用设计模式,我们可以:

        1. 提高代码质量:编写更加灵活、可维护的代码
        2. 增强系统可扩展性:更容易应对需求变化
        3. 促进团队协作:使用共同的设计语言进行沟通
        4. 加速开发进程:复用经过验证的设计方案
        5. 提升架构能力:培养良好的软件设计思维

        记住,设计模式不是银弹,而是工具。真正优秀的设计应该是简单、清晰且能够解决实际问题的。学习设计模式的最终目标是形成自己的设计思想,而不仅仅是记住模式的实现。

        希望本文的设计模式系列能够帮助你在软件开发的道路上走得更远、更稳!

        posted @ 2025-11-16 08:03  gccbuaa  阅读(10)  评论(0)    收藏  举报