Java设计模式总结

发布于:2025-08-08 ⋅ 阅读:(17) ⋅ 点赞:(0)

Java设计模式详解

目录


1. 设计模式概述

1.1 什么是设计模式

设计模式(Design Pattern)是软件工程中对软件设计问题的经典解决方案。它是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

设计模式的核心要素:

  • 模式名称:用于描述设计问题、解决方案和效果的术语
  • 问题:描述何时使用模式,它解释了设计问题和产生问题的原因
  • 解决方案:描述设计的组成成分,它们之间的相互关系及各自的职责和协作方式
  • 效果:描述模式应用的效果及使用模式应权衡的问题

使用设计模式的好处:

  • 提高代码的可重用性
  • 增强代码的可读性和可维护性
  • 降低系统的耦合度
  • 使设计方案更加灵活
  • 提供了标准的设计词汇

1.2 设计模式的三大原则

设计模式基于面向对象设计的基本原则,其中最重要的是以下三大原则:

1. 开放封闭原则(Open-Closed Principle)

定义: 软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。

核心思想: 当应用的需求改变时,在不修改软件实体的源代码的前提下,扩展模块的功能,使其满足新的需求。

实现方式:

  • 抽象化是关键,通过抽象类或接口定义稳定的抽象层
  • 具体实现在子类中完成
  • 新增功能通过增加新的实现类来完成
// 抽象类定义了稳定的接口
abstract class Shape {
    abstract void draw();
}

// 具体实现可以自由扩展
class Circle extends Shape {
    void draw() { System.out.println("画圆形"); }
}

class Rectangle extends Shape {
    void draw() { System.out.println("画矩形"); }
}

// 新增三角形无需修改原有代码
class Triangle extends Shape {
    void draw() { System.out.println("画三角形"); }
}
2. 依赖倒置原则(Dependency Inversion Principle)

定义: 高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。

核心思想: 面向接口编程,不要面向实现编程。

实现方式:

  • 使用接口或抽象类制定规范
  • 具体类实现接口或继承抽象类
  • 客户端针对接口编程
// 抽象接口
interface MessageSender {
    void sendMessage(String message);
}

// 具体实现
class EmailSender implements MessageSender {
    public void sendMessage(String message) {
        System.out.println("通过邮件发送: " + message);
    }
}

class SMSSender implements MessageSender {
    public void sendMessage(String message) {
        System.out.println("通过短信发送: " + message);
    }
}

// 高层模块依赖抽象,不依赖具体实现
class NotificationService {
    private MessageSender sender;
    
    public NotificationService(MessageSender sender) {
        this.sender = sender; // 依赖注入
    }
    
    public void notify(String message) {
        sender.sendMessage(message);
    }
}
3. 单一职责原则(Single Responsibility Principle)

定义: 一个类应该只有一个引起它变化的原因。

核心思想: 每个类只负责一项职责,如果一个类承担了多项职责,就需要将类分解。

实现方式:

  • 确保每个类只有一个明确的职责
  • 当需求变化时,只修改相关的类
  • 避免一个类承担过多的功能
// 违反单一职责原则的设计
class BadUserManager {
    public void saveUser(User user) {
        // 数据验证
        if (user.getName() == null) throw new IllegalArgumentException("姓名不能为空");
        
        // 数据库操作
        Connection conn = DriverManager.getConnection("...");
        // ... 保存用户到数据库
        
        // 发送邮件
        System.out.println("发送欢迎邮件给: " + user.getEmail());
    }
}

// 符合单一职责原则的设计
class UserValidator {
    public void validate(User user) {
        if (user.getName() == null) throw new IllegalArgumentException("姓名不能为空");
    }
}

class UserRepository {
    public void save(User user) {
        Connection conn = DriverManager.getConnection("...");
        // ... 保存用户到数据库
    }
}

class EmailService {
    public void sendWelcomeEmail(User user) {
        System.out.println("发送欢迎邮件给: " + user.getEmail());
    }
}

1.3 设计模式的分类

根据模式的目的,可以将设计模式分为三大类:

1. 创建型模式(Creational Patterns)

目的: 负责对象创建机制,隐藏创建逻辑,提供灵活的对象创建方式。

主要模式:

  • 单例模式(Singleton)
  • 工厂模式(Factory Method/Abstract Factory)
  • 建造者模式(Builder)
  • 原型模式(Prototype)
2. 结构型模式(Structural Patterns)

目的: 处理类或对象的组合,形成更大的结构。

主要模式:

  • 适配器模式(Adapter)
  • 装饰器模式(Decorator)
  • 代理模式(Proxy)
  • 组合模式(Composite)
  • 外观模式(Facade)
  • 桥接模式(Bridge)
  • 享元模式(Flyweight)
3. 行为型模式(Behavioral Patterns)

目的: 关注对象之间的通信和责任分配。

主要模式:

  • 观察者模式(Observer)
  • 策略模式(Strategy)
  • 模板方法模式(Template Method)
  • 命令模式(Command)
  • 迭代器模式(Iterator)
  • 状态模式(State)
  • 访问者模式(Visitor)
  • 中介者模式(Mediator)
  • 备忘录模式(Memento)
  • 解释器模式(Interpreter)
  • 责任链模式(Chain of Responsibility)

2. 创建型模式

2.1 创建型模式概述

创建型模式关注对象的创建过程,将对象的创建和使用分离,隐藏创建的复杂性,使系统独立于对象的创建、组合和表示。

创建型模式的特点:

  • 封装创建过程:将对象的创建封装起来,客户端不需要知道具体的创建过程
  • 提高灵活性:可以在运行时决定创建哪种类型的对象
  • 降低耦合度:客户端与具体类解耦,只依赖抽象
  • 复用创建逻辑:创建逻辑可以在多个地方复用

创建型模式解决的问题:

  • 如何灵活地创建对象
  • 如何降低系统与具体类的耦合
  • 如何复用对象创建的代码
  • 如何管理对象的生命周期

2.2 单例模式

定义: 确保一个类只有一个实例,并提供一个全局访问点。

使用场景:

  • 系统只需要一个实例的类,如配置管理器、日志记录器
  • 需要频繁创建和销毁的对象
  • 创建对象耗费时间或耗费资源过多的对象

实现方式:

1. 饿汉式单例
/**
 * 饿汉式单例 - 线程安全,类加载时就创建实例
 */
public class EagerSingleton {
    // 在类加载时就创建实例
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    
    // 私有构造函数,防止外部实例化
    private EagerSingleton() {}
    
    // 提供全局访问点
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
    
    // 业务方法
    public void doSomething() {
        System.out.println("执行业务逻辑");
    }
}
2. 懒汉式单例(双重检查锁定)
/**
 * 懒汉式单例 - 延迟初始化,双重检查锁定确保线程安全
 */
public class LazySingleton {
    // volatile确保多线程环境下的可见性
    private static volatile LazySingleton instance;
    
    private LazySingleton() {}
    
    public static LazySingleton getInstance() {
        // 第一次检查,避免不必要的同步
        if (instance == null) {
            synchronized (LazySingleton.class) {
                // 第二次检查,防止多线程同时通过第一次检查
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
    
    public void doSomething() {
        System.out.println("执行业务逻辑");
    }
}
3. 枚举单例(推荐)
/**
 * 枚举单例 - 最安全的单例实现方式
 */
public enum EnumSingleton {
    INSTANCE;
    
    public void doSomething() {
        System.out.println("执行业务逻辑");
    }
}

// 使用方式
EnumSingleton.INSTANCE.doSomething();

实际应用示例:

/**
 * 配置管理器单例
 */
public class ConfigManager {
    private static volatile ConfigManager instance;
    private Properties properties;
    
    private ConfigManager() {
        properties = new Properties();
        loadConfig();
    }
    
    public static ConfigManager getInstance() {
        if (instance == null) {
            synchronized (ConfigManager.class) {
                if (instance == null) {
                    instance = new ConfigManager();
                }
            }
        }
        return instance;
    }
    
    private void loadConfig() {
        // 加载配置文件
        try (InputStream input = getClass().getClassLoader().getResourceAsStream("config.properties")) {
            if (input != null) {
                properties.load(input);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public String getProperty(String key) {
        return properties.getProperty(key);
    }
    
    public String getProperty(String key, String defaultValue) {
        return properties.getProperty(key, defaultValue);
    }
}

2.3 工厂模式

工厂模式包括简单工厂、工厂方法和抽象工厂三种形式。

1. 简单工厂模式

定义: 由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例。

// 产品接口
interface Shape {
    void draw();
}

// 具体产品
class Circle implements Shape {
    public void draw() {
        System.out.println("绘制圆形");
    }
}

class Rectangle implements Shape {
    public void draw() {
        System.out.println("绘制矩形");
    }
}

class Triangle implements Shape {
    public void draw() {
        System.out.println("绘制三角形");
    }
}

// 简单工厂
class ShapeFactory {
    public static Shape createShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        
        switch (shapeType.toLowerCase()) {
            case "circle":
                return new Circle();
            case "rectangle":
                return new Rectangle();
            case "triangle":
                return new Triangle();
            default:
                throw new IllegalArgumentException("不支持的图形类型: " + shapeType);
        }
    }
}

// 使用示例
public class SimpleFactoryDemo {
    public static void main(String[] args) {
        Shape circle = ShapeFactory.createShape("circle");
        circle.draw();
        
        Shape rectangle = ShapeFactory.createShape("rectangle");
        rectangle.draw();
    }
}
2. 工厂方法模式

定义: 定义一个创建对象的接口,让子类决定实例化哪一个类。

// 抽象产品
abstract class Logger {
    public abstract void log(String message);
}

// 具体产品
class FileLogger extends Logger {
    public void log(String message) {
        System.out.println("文件日志: " + message);
    }
}

class ConsoleLogger extends Logger {
    public void log(String message) {
        System.out.println("控制台日志: " + message);
    }
}

class DatabaseLogger extends Logger {
    public void log(String message) {
        System.out.println("数据库日志: " + message);
    }
}

// 抽象工厂
abstract class LoggerFactory {
    public abstract Logger createLogger();
    
    // 模板方法,定义使用流程
    public void logMessage(String message) {
        Logger logger = createLogger();
        logger.log(message);
    }
}

// 具体工厂
class FileLoggerFactory extends LoggerFactory {
    public Logger createLogger() {
        return new FileLogger();
    }
}

class ConsoleLoggerFactory extends LoggerFactory {
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

class DatabaseLoggerFactory extends LoggerFactory {
    public Logger createLogger() {
        return new DatabaseLogger();
    }
}

// 使用示例
public class FactoryMethodDemo {
    public static void main(String[] args) {
        LoggerFactory fileFactory = new FileLoggerFactory();
        fileFactory.logMessage("这是一条文件日志");
        
        LoggerFactory consoleFactory = new ConsoleLoggerFactory();
        consoleFactory.logMessage("这是一条控制台日志");
    }
}
3. 抽象工厂模式

定义: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

// 抽象产品族
interface Button {
    void click();
}

interface TextField {
    void input();
}

// Windows风格产品
class WindowsButton implements Button {
    public void click() {
        System.out.println("Windows按钮被点击");
    }
}

class WindowsTextField implements TextField {
    public void input() {
        System.out.println("在Windows文本框中输入");
    }
}

// Mac风格产品
class MacButton implements Button {
    public void click() {
        System.out.println("Mac按钮被点击");
    }
}

class MacTextField implements TextField {
    public void input() {
        System.out.println("在Mac文本框中输入");
    }
}

// 抽象工厂
interface GUIFactory {
    Button createButton();
    TextField createTextField();
}

// 具体工厂
class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new WindowsButton();
    }
    
    public TextField createTextField() {
        return new WindowsTextField();
    }
}

class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }
    
    public TextField createTextField() {
        return new MacTextField();
    }
}

// 客户端
class Application {
    private Button button;
    private TextField textField;
    
    public Application(GUIFactory factory) {
        button = factory.createButton();
        textField = factory.createTextField();
    }
    
    public void interact() {
        button.click();
        textField.input();
    }
}

// 使用示例
public class AbstractFactoryDemo {
    public static void main(String[] args) {
        // Windows风格应用
        GUIFactory windowsFactory = new WindowsFactory();
        Application windowsApp = new Application(windowsFactory);
        windowsApp.interact();
        
        // Mac风格应用
        GUIFactory macFactory = new MacFactory();
        Application macApp = new Application(macFactory);
        macApp.interact();
    }
}

2.4 建造者模式

定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

使用场景:

  • 需要生成的对象具有复杂的内部结构
  • 需要生成的对象内部属性本身相互依赖
  • 与不可变对象配合使用

实现示例:

/**
 * 产品类 - 计算机
 */
public class Computer {
    // 必需参数
    private String cpu;
    private String memory;
    
    // 可选参数
    private String storage;
    private String graphics;
    private boolean hasWiFi;
    private boolean hasBluetooth;
    
    // 私有构造函数,只能通过Builder创建
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.memory = builder.memory;
        this.storage = builder.storage;
        this.graphics = builder.graphics;
        this.hasWiFi = builder.hasWiFi;
        this.hasBluetooth = builder.hasBluetooth;
    }
    
    // 静态内部Builder类
    public static class Builder {
        // 必需参数
        private String cpu;
        private String memory;
        
        // 可选参数,初始化为默认值
        private String storage = "1TB HDD";
        private String graphics = "集成显卡";
        private boolean hasWiFi = false;
        private boolean hasBluetooth = false;
        
        public Builder(String cpu, String memory) {
            this.cpu = cpu;
            this.memory = memory;
        }
        
        public Builder storage(String storage) {
            this.storage = storage;
            return this;
        }
        
        public Builder graphics(String graphics) {
            this.graphics = graphics;
            return this;
        }
        
        public Builder wifi(boolean hasWiFi) {
            this.hasWiFi = hasWiFi;
            return this;
        }
        
        public Builder bluetooth(boolean hasBluetooth) {
            this.hasBluetooth = hasBluetooth;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
    
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", memory='" + memory + '\'' +
                ", storage='" + storage + '\'' +
                ", graphics='" + graphics + '\'' +
                ", hasWiFi=" + hasWiFi +
                ", hasBluetooth=" + hasBluetooth +
                '}';
    }
}

// 使用示例
public class BuilderDemo {
    public static void main(String[] args) {
        // 基本配置
        Computer basicComputer = new Computer.Builder("Intel i5", "8GB")
                .build();
        System.out.println("基本配置: " + basicComputer);
        
        // 高端配置
        Computer gamingComputer = new Computer.Builder("Intel i9", "32GB")
                .storage("1TB SSD")
                .graphics("RTX 4080")
                .wifi(true)
                .bluetooth(true)
                .build();
        System.out.println("游戏配置: " + gamingComputer);
    }
}

2.5 原型模式

定义: 通过复制现有的实例来创建新的实例,而不是通过实例化类。

使用场景:

  • 对象的创建非常复杂或消耗大量资源
  • 系统要独立于产品的创建、构成和表示
  • 需要保存对象的状态

实现示例:

/**
 * 抽象原型类
 */
abstract class Shape implements Cloneable {
    private String id;
    protected String type;
    
    abstract void draw();
    
    public String getType() {
        return type;
    }
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    // 实现克隆方法
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

/**
 * 具体原型类
 */
class Rectangle extends Shape {
    public Rectangle() {
        type = "Rectangle";
    }
    
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

class Circle extends Shape {
    public Circle() {
        type = "Circle";
    }
    
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

class Square extends Shape {
    public Square() {
        type = "Square";
    }
    
    @Override
    public void draw() {
        System.out.println("绘制正方形");
    }
}

/**
 * 原型管理器
 */
class ShapeCache {
    private static Map<String, Shape> shapeMap = new HashMap<>();
    
    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }
    
    // 加载缓存
    public static void loadCache() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeMap.put(circle.getId(), circle);
        
        Square square = new Square();
        square.setId("2");
        shapeMap.put(square.getId(), square);
        
        Rectangle rectangle = new Rectangle();
        rectangle.setId("3");
        shapeMap.put(rectangle.getId(), rectangle);
    }
}

// 使用示例
public class PrototypeDemo {
    public static void main(String[] args) {
        ShapeCache.loadCache();
        
        Shape clonedShape1 = ShapeCache.getShape("1");
        System.out.println("Shape: " + clonedShape1.getType());
        
        Shape clonedShape2 = ShapeCache.getShape("2");
        System.out.println("Shape: " + clonedShape2.getType());
        
        Shape clonedShape3 = ShapeCache.getShape("3");
        System.out.println("Shape: " + clonedShape3.getType());
    }
}

2.6 创建型模式总结

模式名称 主要目的 使用场景 优点 缺点
单例模式 确保只有一个实例 全局配置、缓存、日志 节省内存、全局访问 违反单一职责、难以测试
简单工厂 集中创建产品 产品种类少且固定 简单易用、集中管理 违反开闭原则、职责过重
工厂方法 延迟到子类创建 需要灵活扩展产品 符合开闭原则、解耦 增加类的数量
抽象工厂 创建产品族 多个相关产品系列 产品族一致性 扩展困难
建造者模式 构建复杂对象 对象创建步骤复杂 参数清晰、可复用 代码复杂
原型模式 克隆创建对象 创建成本高 性能好、动态配置 深拷贝复杂

创建型模式的选择建议:

  • 只需要一个实例 → 单例模式
  • 简单的对象创建 → 简单工厂
  • 需要扩展新产品 → 工厂方法
  • 创建产品族 → 抽象工厂
  • 复杂对象构建 → 建造者模式
  • 克隆现有对象 → 原型模式

4. 行为型模式

4.1 行为型模式概述

行为型模式关注对象之间的通信和责任分配,关注算法和对象间职责的分配。这些模式不仅描述对象或类的模式,还描述它们之间的通信模式。

行为型模式的特点:

  • 关注对象间交互:描述对象和类之间怎样相互协作来完成单个对象无法胜任的任务
  • 分配职责:将复杂的流程分解,指定对象的职责
  • 封装行为:将一系列算法封装起来,使它们可以相互替换
  • 降低耦合度:减少对象间的直接耦合,使系统更加灵活

行为型模式解决的问题:

  • 如何在不同对象间分配职责
  • 如何简化对象间的通信
  • 如何封装变化的算法或行为
  • 如何管理对象的状态转换

3. 结构型模式

3.1 结构型模式概述

结构型模式关注如何将对象和类组装成更大的结构,同时保持结构的灵活和高效。这些模式处理类或对象的组合,通过继承和组合来组织接口和实现,从而优化类结构,实现新功能。

结构型模式的特点:

  • 关注对象组合:处理对象之间的组合关系
  • 简化复杂关系:将复杂的系统结构分解为更简单的部分
  • 提供统一接口:为不同的组件提供一致的接口
  • 增强系统灵活性:使系统更容易扩展和维护

结构型模式解决的问题:

  • 如何让不兼容的接口能够协作
  • 如何在不修改现有代码的情况下扩展功能
  • 如何简化复杂的子系统接口
  • 如何有效地组织和管理大量相似的对象

3.2 适配器模式

定义: 将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

使用场景:

  • 系统需要使用现有的类,但其接口不符合系统的需要
  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的类协同工作

实现示例:

// 目标接口 - 客户端期望的接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 适配者接口 - 需要被适配的接口
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// 适配者实现
class VlcPlayer implements AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        System.out.println("播放VLC文件: " + fileName);
    }
    
    public void playMp4(String fileName) {
        // 什么都不做
    }
}

class Mp4Player implements AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        // 什么都不做
    }
    
    public void playMp4(String fileName) {
        System.out.println("播放MP4文件: " + fileName);
    }
}

// 适配器类
class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedPlayer;
    
    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedPlayer = new Mp4Player();
        }
    }
    
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedPlayer.playMp4(fileName);
        }
    }
}

// 客户端
class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;
    
    public void play(String audioType, String fileName) {
        // 内置支持mp3格式的播放
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("播放MP3文件: " + fileName);
        }
        // mediaAdapter提供了播放其他格式的支持
        else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("不支持的媒体格式: " + audioType);
        }
    }
}

// 使用示例
public class AdapterPatternDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();
        
        audioPlayer.play("mp3", "beyond_the_horizon.mp3");
        audioPlayer.play("mp4", "alone.mp4");
        audioPlayer.play("vlc", "far_far_away.vlc");
        audioPlayer.play("avi", "mind_me.avi");
    }
}

3.3 装饰器模式

定义: 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活。

使用场景:

  • 需要扩展一个类的功能,或给一个类添加附加职责
  • 需要动态地给一个对象添加功能,这些功能可以再动态地撤销
  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能

实现示例:

// 抽象组件
interface Coffee {
    String getDescription();
    double getCost();
}

// 具体组件
class SimpleCoffee implements Coffee {
    public String getDescription() {
        return "简单咖啡";
    }
    
    public double getCost() {
        return 10.0;
    }
}

// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    
    public String getDescription() {
        return coffee.getDescription();
    }
    
    public double getCost() {
        return coffee.getCost();
    }
}

// 具体装饰器
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + " + 牛奶";
    }
    
    public double getCost() {
        return coffee.getCost() + 2.0;
    }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + " + 糖";
    }
    
    public double getCost() {
        return coffee.getCost() + 1.0;
    }
}

class ChocolateDecorator extends CoffeeDecorator {
    public ChocolateDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + " + 巧克力";
    }
    
    public double getCost() {
        return coffee.getCost() + 3.0;
    }
}

// 使用示例
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " 价格: $" + coffee.getCost());
        
        // 添加牛奶
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " 价格: $" + coffee.getCost());
        
        // 添加糖
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " 价格: $" + coffee.getCost());
        
        // 添加巧克力
        coffee = new ChocolateDecorator(coffee);
        System.out.println(coffee.getDescription() + " 价格: $" + coffee.getCost());
    }
}

3.4 代理模式

定义: 为其他对象提供一种代理以控制对这个对象的访问。

使用场景:

  • 远程代理:为一个对象在不同的地址空间提供局部代表
  • 虚拟代理:根据需要创建开销很大的对象
  • 保护代理:控制对原始对象的访问
  • 智能指引:在访问对象时执行一些附加操作

实现示例:

// 主题接口
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String fileName;
    
    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk(fileName);
    }
    
    public void display() {
        System.out.println("显示图片: " + fileName);
    }
    
    private void loadFromDisk(String fileName) {
        System.out.println("从磁盘加载图片: " + fileName);
    }
}

// 代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String fileName;
    
    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }
    
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(fileName);
        }
        realImage.display();
    }
}

// 使用示例
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        
        // 图片将从磁盘加载
        image.display();
        System.out.println("");
        
        // 图片不会从磁盘加载
        image.display();
    }
}

3.5 组合模式

定义: 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

使用场景:

  • 想表示对象的部分-整体层次结构
  • 希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象

实现示例:

// 组件抽象类
abstract class Component {
    protected String name;
    
    public Component(String name) {
        this.name = name;
    }
    
    public abstract void add(Component component);
    public abstract void remove(Component component);
    public abstract void display(int depth);
}

// 叶子节点
class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }
    
    public void add(Component component) {
        System.out.println("叶子节点不能添加子节点");
    }
    
    public void remove(Component component) {
        System.out.println("叶子节点不能删除子节点");
    }
    
    public void display(int depth) {
        System.out.println(new String(new char[depth]).replace("\0", "-") + name);
    }
}

// 组合节点
class Composite extends Component {
    private List<Component> children = new ArrayList<>();
    
    public Composite(String name) {
        super(name);
    }
    
    public void add(Component component) {
        children.add(component);
    }
    
    public void remove(Component component) {
        children.remove(component);
    }
    
    public void display(int depth) {
        System.out.println(new String(new char[depth]).replace("\0", "-") + name);
        for (Component component : children) {
            component.display(depth + 2);
        }
    }
}

// 使用示例
public class CompositePatternDemo {
    public static void main(String[] args) {
        Component root = new Composite("根节点");
        root.add(new Leaf("叶子A"));
        root.add(new Leaf("叶子B"));
        
        Component comp = new Composite("组合X");
        comp.add(new Leaf("叶子XA"));
        comp.add(new Leaf("叶子XB"));
        
        root.add(comp);
        
        Component comp2 = new Composite("组合Y");
        comp2.add(new Leaf("叶子YA"));
        comp2.add(new Leaf("叶子YB"));
        
        comp.add(comp2);
        
        root.display(1);
    }
}

3.6 外观模式

定义: 为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。

使用场景:

  • 为复杂的模块或子系统提供外界访问的模块
  • 子系统相对独立
  • 预防低水平人员带来的风险

实现示例:

// 子系统类
class CPU {
    public void freeze() {
        System.out.println("CPU冻结");
    }
    
    public void jump(long position) {
        System.out.println("CPU跳转到位置: " + position);
    }
    
    public void execute() {
        System.out.println("CPU执行");
    }
}

class Memory {
    public void load(long position, byte[] data) {
        System.out.println("内存加载数据到位置: " + position);
    }
}

class HardDrive {
    public byte[] read(long lba, int size) {
        System.out.println("硬盘读取数据,LBA: " + lba + ", 大小: " + size);
        return new byte[size];
    }
}

// 外观类
class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDrive hd;
    
    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDrive();
    }
    
    public void start() {
        processor.freeze();
        ram.load(0, hd.read(0, 1024));
        processor.jump(0);
        processor.execute();
    }
}

// 使用示例
public class FacadePatternDemo {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

3.7 桥接模式

定义: 将抽象部分与它的实现部分分离,使它们都可以独立地变化。

使用场景:

  • 不希望在抽象和它的实现部分之间有一个固定的绑定关系
  • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩展
  • 对一个抽象的实现部分的修改应对客户不产生影响

实现示例:

// 实现接口
interface DrawAPI {
    void drawCircle(int radius, int x, int y);
}

// 具体实现
class RedCircle implements DrawAPI {
    public void drawCircle(int radius, int x, int y) {
        System.out.println("画红色圆形,半径: " + radius + ", 坐标: (" + x + "," + y + ")");
    }
}

class GreenCircle implements DrawAPI {
    public void drawCircle(int radius, int x, int y) {
        System.out.println("画绿色圆形,半径: " + radius + ", 坐标: (" + x + "," + y + ")");
    }
}

// 抽象类
abstract class Shape {
    protected DrawAPI drawAPI;
    
    protected Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }
    
    public abstract void draw();
}

// 扩展抽象类
class Circle extends Shape {
    private int x, y, radius;
    
    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }
    
    public void draw() {
        drawAPI.drawCircle(radius, x, y);
    }
}

// 使用示例
public class BridgePatternDemo {
    public static void main(String[] args) {
        Shape redCircle = new Circle(100, 100, 10, new RedCircle());
        Shape greenCircle = new Circle(100, 100, 10, new GreenCircle());
        
        redCircle.draw();
        greenCircle.draw();
    }
}

3.8 享元模式

定义: 运用共享技术有效地支持大量细粒度的对象。

使用场景:

  • 系统中有大量对象,这些对象消耗大量内存
  • 对象的大部分状态都可以外部化
  • 对象可以按照内在状态分为很多组,当把外在对象从对象中剔除出来时,每一组对象都可以用一个对象来代替

实现示例:

// 享元接口
interface Shape {
    void draw(int x, int y);
}

// 具体享元
class Circle implements Shape {
    private String color;
    private int radius;
    
    public Circle(String color) {
        this.color = color;
    }
    
    public void setRadius(int radius) {
        this.radius = radius;
    }
    
    public void draw(int x, int y) {
        System.out.println("画圆形,颜色: " + color + ", 半径: " + radius + ", 坐标: (" + x + "," + y + ")");
    }
}

// 享元工厂
class ShapeFactory {
    private static final Map<String, Shape> circleMap = new HashMap<>();
    
    public static Shape getCircle(String color) {
        Circle circle = (Circle) circleMap.get(color);
        
        if (circle == null) {
            circle = new Circle(color);
            circleMap.put(color, circle);
            System.out.println("创建新的圆形,颜色: " + color);
        }
        return circle;
    }
    
    public static int getCreatedShapes() {
        return circleMap.size();
    }
}

// 使用示例
public class FlyweightPatternDemo {
    private static final String colors[] = {"红色", "绿色", "蓝色", "白色", "黑色"};
    
    public static void main(String[] args) {
        for (int i = 0; i < 20; ++i) {
            Circle circle = (Circle) ShapeFactory.getCircle(getRandomColor());
            circle.setRadius(getRandomRadius());
            circle.draw(getRandomX(), getRandomY());
        }
        
        System.out.println("创建的圆形对象数量: " + ShapeFactory.getCreatedShapes());
    }
    
    private static String getRandomColor() {
        return colors[(int) (Math.random() * colors.length)];
    }
    
    private static int getRandomX() {
        return (int) (Math.random() * 100);
    }
    
    private static int getRandomY() {
        return (int) (Math.random() * 100);
    }
    
    private static int getRandomRadius() {
        return (int) (Math.random() * 10) + 1;
    }
}

3.9 结构型模式总结

模式名称 主要目的 使用场景 优点 缺点
适配器模式 接口转换 现有类接口不匹配 重用现有类、解耦 增加系统复杂性
装饰器模式 动态添加功能 需要扩展对象功能 灵活扩展、符合开闭原则 产生很多小对象
代理模式 控制对象访问 需要控制访问权限 职责清晰、保护目标对象 增加系统复杂性
组合模式 树形结构处理 部分-整体层次结构 客户端调用简单 设计较复杂
外观模式 简化接口 子系统复杂 降低耦合、简化接口 可能违反开闭原则
桥接模式 分离抽象和实现 抽象和实现需独立变化 分离接口和实现 增加理解复杂性
享元模式 减少对象数量 大量相似对象 减少内存消耗 提高复杂性

结构型模式的选择建议:

  • 接口不兼容 → 适配器模式
  • 动态增加功能 → 装饰器模式
  • 控制对象访问 → 代理模式
  • 树形结构操作 → 组合模式
  • 简化复杂系统 → 外观模式
  • 抽象与实现分离 → 桥接模式
  • 大量相似对象 → 享元模式

4.2 观察者模式

定义: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

使用场景:

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面
  • 一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
  • 一个对象必须通知其他对象,而又不能假定其他对象是谁

实现示例:

// 抽象观察者
interface Observer {
    void update(String message);
}

// 抽象被观察者
abstract class Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    protected void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

// 具体被观察者
class NewsAgency extends Subject {
    private String news;
    
    public void setNews(String news) {
        this.news = news;
        notifyObservers(news);
    }
    
    public String getNews() {
        return news;
    }
}

// 具体观察者
class NewsChannel implements Observer {
    private String name;
    private String news;
    
    public NewsChannel(String name) {
        this.name = name;
    }
    
    public void update(String news) {
        this.news = news;
        System.out.println(name + " 收到新闻: " + news);
    }
    
    public String getNews() {
        return news;
    }
}

class Newspaper implements Observer {
    private String name;
    private String news;
    
    public Newspaper(String name) {
        this.name = name;
    }
    
    public void update(String news) {
        this.news = news;
        System.out.println(name + " 准备刊登新闻: " + news);
    }
}

// 使用示例
public class ObserverPatternDemo {
    public static void main(String[] args) {
        NewsAgency agency = new NewsAgency();
        
        NewsChannel channel1 = new NewsChannel("CNN");
        NewsChannel channel2 = new NewsChannel("BBC");
        Newspaper newspaper = new Newspaper("纽约时报");
        
        agency.attach(channel1);
        agency.attach(channel2);
        agency.attach(newspaper);
        
        agency.setNews("重大新闻:观察者模式实现成功!");
        
        System.out.println("\n移除BBC后:");
        agency.detach(channel2);
        agency.setNews("又一重大新闻发布!");
    }
}

4.3 策略模式

定义: 定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。

使用场景:

  • 一个系统有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
  • 一个系统需要动态地在几种算法中选择一种
  • 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现

实现示例:

// 策略接口
interface PaymentStrategy {
    void pay(int amount);
}

// 具体策略实现
class CreditCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;
    
    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }
    
    public void pay(int amount) {
        System.out.println(amount + "元 通过信用卡支付");
        System.out.println("持卡人: " + name);
        System.out.println("卡号: " + cardNumber);
    }
}

class PayPalStrategy implements PaymentStrategy {
    private String emailId;
    private String password;
    
    public PayPalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }
    
    public void pay(int amount) {
        System.out.println(amount + "元 通过PayPal支付");
        System.out.println("邮箱: " + emailId);
    }
}

class WeChatPayStrategy implements PaymentStrategy {
    private String phoneNumber;
    
    public WeChatPayStrategy(String phone) {
        this.phoneNumber = phone;
    }
    
    public void pay(int amount) {
        System.out.println(amount + "元 通过微信支付");
        System.out.println("手机号: " + phoneNumber);
    }
}

// 上下文类
class ShoppingCart {
    private List<Item> items;
    
    public ShoppingCart() {
        this.items = new ArrayList<>();
    }
    
    public void addItem(Item item) {
        this.items.add(item);
    }
    
    public void removeItem(Item item) {
        this.items.remove(item);
    }
    
    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }
    
    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

// 商品类
class Item {
    private String upcCode;
    private int price;
    
    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }
    
    public String getUpcCode() {
        return upcCode;
    }
    
    public int getPrice() {
        return price;
    }
}

// 使用示例
public class StrategyPatternDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        
        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);
        
        cart.addItem(item1);
        cart.addItem(item2);
        
        // 使用PayPal支付
        cart.pay(new PayPalStrategy("myemail@example.com", "mypwd"));
        
        System.out.println("\n--- 换一种支付方式 ---");
        
        // 使用信用卡支付
        cart.pay(new CreditCardStrategy("张三", "1234567890123456", "786", "12/15"));
        
        System.out.println("\n--- 再换一种支付方式 ---");
        
        // 使用微信支付
        cart.pay(new WeChatPayStrategy("13800138000"));
    }
}

4.4 模板方法模式

定义: 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

使用场景:

  • 有多个子类共有的方法,且逻辑相同
  • 重要的、复杂的方法,可以考虑作为模板方法
  • 重构时,把相同的代码抽取到父类中,然后通过钩子函数约束其行为

实现示例:

// 抽象模板类
abstract class DataMiner {
    
    // 模板方法 - 定义算法骨架
    public final void mineData(String path) {
        openFile(path);
        byte[] rawData = extractData();
        byte[] data = parseData(rawData);
        byte[] analysis = analyzeData(data);
        sendReport(analysis);
        closeFile();
    }
    
    // 具体方法 - 所有子类都相同的步骤
    private void openFile(String path) {
        System.out.println("打开文件: " + path);
    }
    
    private void closeFile() {
        System.out.println("关闭文件");
    }
    
    // 抽象方法 - 子类必须实现
    protected abstract byte[] extractData();
    protected abstract byte[] parseData(byte[] rawData);
    
    // 默认实现 - 子类可以选择重写
    protected byte[] analyzeData(byte[] data) {
        System.out.println("执行默认数据分析");
        return data;
    }
    
    // 钩子方法 - 子类可以通过重写来影响模板方法的行为
    protected void sendReport(byte[] analysis) {
        System.out.println("发送默认格式报告");
    }
}

// 具体实现类 - PDF数据挖掘
class PDFDataMiner extends DataMiner {
    
    protected byte[] extractData() {
        System.out.println("从PDF文件提取数据");
        return new byte[]{1, 2, 3};
    }
    
    protected byte[] parseData(byte[] rawData) {
        System.out.println("解析PDF数据格式");
        return rawData;
    }
    
    @Override
    protected void sendReport(byte[] analysis) {
        System.out.println("发送PDF格式报告");
    }
}

// 具体实现类 - CSV数据挖掘
class CSVDataMiner extends DataMiner {
    
    protected byte[] extractData() {
        System.out.println("从CSV文件提取数据");
        return new byte[]{4, 5, 6};
    }
    
    protected byte[] parseData(byte[] rawData) {
        System.out.println("解析CSV数据格式");
        return rawData;
    }
    
    @Override
    protected byte[] analyzeData(byte[] data) {
        System.out.println("执行CSV特定的数据分析");
        return data;
    }
}

// 具体实现类 - Excel数据挖掘
class ExcelDataMiner extends DataMiner {
    
    protected byte[] extractData() {
        System.out.println("从Excel文件提取数据");
        return new byte[]{7, 8, 9};
    }
    
    protected byte[] parseData(byte[] rawData) {
        System.out.println("解析Excel数据格式");
        return rawData;
    }
    
    @Override
    protected byte[] analyzeData(byte[] data) {
        System.out.println("执行Excel特定的数据分析");
        return data;
    }
    
    @Override
    protected void sendReport(byte[] analysis) {
        System.out.println("发送Excel格式报告");
    }
}

// 使用示例
public class TemplateMethodDemo {
    public static void main(String[] args) {
        System.out.println("=== PDF数据挖掘 ===");
        DataMiner pdfMiner = new PDFDataMiner();
        pdfMiner.mineData("data.pdf");
        
        System.out.println("\n=== CSV数据挖掘 ===");
        DataMiner csvMiner = new CSVDataMiner();
        csvMiner.mineData("data.csv");
        
        System.out.println("\n=== Excel数据挖掘 ===");
        DataMiner excelMiner = new ExcelDataMiner();
        excelMiner.mineData("data.xlsx");
    }
}

4.5 命令模式

定义: 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

使用场景:

  • 需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
  • 需要在不同的时间指定、排列和执行请求
  • 需要支持命令的撤销操作
  • 需要支持事务操作

实现示例:

// 命令接口
interface Command {
    void execute();
    void undo();
}

// 接收者 - 电视
class Television {
    private boolean isOn = false;
    private int volume = 0;
    private int channel = 1;
    
    public void turnOn() {
        isOn = true;
        System.out.println("电视已打开");
    }
    
    public void turnOff() {
        isOn = false;
        System.out.println("电视已关闭");
    }
    
    public void volumeUp() {
        if (isOn) {
            volume++;
            System.out.println("音量增加到: " + volume);
        }
    }
    
    public void volumeDown() {
        if (isOn && volume > 0) {
            volume--;
            System.out.println("音量减小到: " + volume);
        }
    }
    
    public void channelUp() {
        if (isOn) {
            channel++;
            System.out.println("频道切换到: " + channel);
        }
    }
    
    public void channelDown() {
        if (isOn && channel > 1) {
            channel--;
            System.out.println("频道切换到: " + channel);
        }
    }
}

// 具体命令实现
class TurnOnCommand implements Command {
    private Television tv;
    
    public TurnOnCommand(Television tv) {
        this.tv = tv;
    }
    
    public void execute() {
        tv.turnOn();
    }
    
    public void undo() {
        tv.turnOff();
    }
}

class TurnOffCommand implements Command {
    private Television tv;
    
    public TurnOffCommand(Television tv) {
        this.tv = tv;
    }
    
    public void execute() {
        tv.turnOff();
    }
    
    public void undo() {
        tv.turnOn();
    }
}

class VolumeUpCommand implements Command {
    private Television tv;
    
    public VolumeUpCommand(Television tv) {
        this.tv = tv;
    }
    
    public void execute() {
        tv.volumeUp();
    }
    
    public void undo() {
        tv.volumeDown();
    }
}

class ChannelUpCommand implements Command {
    private Television tv;
    
    public ChannelUpCommand(Television tv) {
        this.tv = tv;
    }
    
    public void execute() {
        tv.channelUp();
    }
    
    public void undo() {
        tv.channelDown();
    }
}

// 调用者 - 遥控器
class RemoteControl {
    private Command[] commands;
    private Command lastCommand;
    
    public RemoteControl() {
        commands = new Command[7]; // 假设有7个按钮
    }
    
    public void setCommand(int slot, Command command) {
        commands[slot] = command;
    }
    
    public void pressButton(int slot) {
        if (commands[slot] != null) {
            commands[slot].execute();
            lastCommand = commands[slot];
        }
    }
    
    public void pressUndoButton() {
        if (lastCommand != null) {
            lastCommand.undo();
        }
    }
}

// 使用示例
public class CommandPatternDemo {
    public static void main(String[] args) {
        // 创建接收者
        Television tv = new Television();
        
        // 创建命令
        Command turnOn = new TurnOnCommand(tv);
        Command turnOff = new TurnOffCommand(tv);
        Command volumeUp = new VolumeUpCommand(tv);
        Command channelUp = new ChannelUpCommand(tv);
        
        // 创建调用者
        RemoteControl remote = new RemoteControl();
        
        // 设置命令
        remote.setCommand(0, turnOn);
        remote.setCommand(1, turnOff);
        remote.setCommand(2, volumeUp);
        remote.setCommand(3, channelUp);
        
        // 执行命令
        remote.pressButton(0); // 开机
        remote.pressButton(2); // 音量+
        remote.pressButton(2); // 音量+
        remote.pressButton(3); // 频道+
        
        System.out.println("\n=== 撤销操作 ===");
        remote.pressUndoButton(); // 撤销最后一个操作
        
        remote.pressButton(1); // 关机
        remote.pressUndoButton(); // 撤销关机操作
    }
}

4.7 状态模式

定义: 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

使用场景:

  • 代码中包含大量与对象状态有关的条件语句
  • 对象的行为随着状态改变而改变
  • 条件语句的分支过多且依赖于对象的状态

实现示例:

// 状态接口
interface State {
    void insertQuarter();
    void ejectQuarter();
    void turnCrank();
    void dispense();
}

// 上下文类 - 糖果机
class GumballMachine {
    private State soldOutState;
    private State noQuarterState;
    private State hasQuarterState;
    private State soldState;
    
    private State currentState;
    private int count = 0;
    
    public GumballMachine(int numberGumballs) {
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
        
        this.count = numberGumballs;
        if (numberGumballs > 0) {
            currentState = noQuarterState;
        } else {
            currentState = soldOutState;
        }
    }
    
    public void insertQuarter() {
        currentState.insertQuarter();
    }
    
    public void ejectQuarter() {
        currentState.ejectQuarter();
    }
    
    public void turnCrank() {
        currentState.turnCrank();
        currentState.dispense();
    }
    
    public void setState(State state) {
        this.currentState = state;
    }
    
    public void releaseBall() {
        System.out.println("糖果正在出来...");
        if (count != 0) {
            count = count - 1;
        }
    }
    
    public int getCount() {
        return count;
    }
    
    public State getSoldOutState() { return soldOutState; }
    public State getNoQuarterState() { return noQuarterState; }
    public State getHasQuarterState() { return hasQuarterState; }
    public State getSoldState() { return soldState; }
}

// 具体状态实现
class NoQuarterState implements State {
    private GumballMachine gumballMachine;
    
    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    
    public void insertQuarter() {
        System.out.println("您投入了硬币");
        gumballMachine.setState(gumballMachine.getHasQuarterState());
    }
    
    public void ejectQuarter() {
        System.out.println("您还没有投入硬币");
    }
    
    public void turnCrank() {
        System.out.println("您转动了手柄,但是没有硬币");
    }
    
    public void dispense() {
        System.out.println("您需要先投入硬币");
    }
}

class HasQuarterState implements State {
    private GumballMachine gumballMachine;
    
    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    
    public void insertQuarter() {
        System.out.println("您不能再投入硬币");
    }
    
    public void ejectQuarter() {
        System.out.println("硬币已退出");
        gumballMachine.setState(gumballMachine.getNoQuarterState());
    }
    
    public void turnCrank() {
        System.out.println("您转动了手柄...");
        gumballMachine.setState(gumballMachine.getSoldState());
    }
    
    public void dispense() {
        System.out.println("没有糖果出来");
    }
}

class SoldState implements State {
    private GumballMachine gumballMachine;
    
    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    
    public void insertQuarter() {
        System.out.println("请等待,我们正在给您糖果");
    }
    
    public void ejectQuarter() {
        System.out.println("对不起,您已经转动了手柄");
    }
    
    public void turnCrank() {
        System.out.println("转动两次手柄不会给您更多糖果");
    }
    
    public void dispense() {
        gumballMachine.releaseBall();
        if (gumballMachine.getCount() > 0) {
            gumballMachine.setState(gumballMachine.getNoQuarterState());
        } else {
            System.out.println("糖果已售完");
            gumballMachine.setState(gumballMachine.getSoldOutState());
        }
    }
}

class SoldOutState implements State {
    private GumballMachine gumballMachine;
    
    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    
    public void insertQuarter() {
        System.out.println("您不能投入硬币,机器已售完");
    }
    
    public void ejectQuarter() {
        System.out.println("您不能退出硬币,您还没有投入硬币");
    }
    
    public void turnCrank() {
        System.out.println("您转动了手柄,但是没有糖果");
    }
    
    public void dispense() {
        System.out.println("没有糖果出来");
    }
}

// 使用示例
public class StatePatternDemo {
    public static void main(String[] args) {
        GumballMachine gumballMachine = new GumballMachine(5);
        
        System.out.println("=== 第一次购买 ===");
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        
        System.out.println("\n=== 第二次购买 ===");
        gumballMachine.insertQuarter();
        gumballMachine.ejectQuarter();
        
        System.out.println("\n=== 第三次购买 ===");
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        
        System.out.println("\n=== 无硬币操作 ===");
        gumballMachine.turnCrank();
    }
}

4.12 责任链模式

定义: 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

使用场景:

  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
  • 可动态指定一组对象处理请求

实现示例:

// 抽象处理者
abstract class Handler {
    protected Handler nextHandler;
    
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
    
    public abstract void handleRequest(Request request);
}

// 请求类
class Request {
    private String type;
    private int amount;
    
    public Request(String type, int amount) {
        this.type = type;
        this.amount = amount;
    }
    
    public String getType() { return type; }
    public int getAmount() { return amount; }
}

// 具体处理者
class TeamLeader extends Handler {
    public void handleRequest(Request request) {
        if (request.getType().equals("请假") && request.getAmount() <= 1) {
            System.out.println("团队主管批准了" + request.getAmount() + "天的请假申请");
        } else if (nextHandler != null) {
            System.out.println("团队主管无法处理,转给上级");
            nextHandler.handleRequest(request);
        } else {
            System.out.println("没有合适的处理者");
        }
    }
}

class Manager extends Handler {
    public void handleRequest(Request request) {
        if (request.getType().equals("请假") && request.getAmount() <= 3) {
            System.out.println("部门经理批准了" + request.getAmount() + "天的请假申请");
        } else if (request.getType().equals("加薪") && request.getAmount() <= 1000) {
            System.out.println("部门经理批准了" + request.getAmount() + "元的加薪申请");
        } else if (nextHandler != null) {
            System.out.println("部门经理无法处理,转给上级");
            nextHandler.handleRequest(request);
        } else {
            System.out.println("没有合适的处理者");
        }
    }
}

class Director extends Handler {
    public void handleRequest(Request request) {
        if (request.getType().equals("请假") && request.getAmount() <= 7) {
            System.out.println("总监批准了" + request.getAmount() + "天的请假申请");
        } else if (request.getType().equals("加薪") && request.getAmount() <= 5000) {
            System.out.println("总监批准了" + request.getAmount() + "元的加薪申请");
        } else if (nextHandler != null) {
            System.out.println("总监无法处理,转给上级");
            nextHandler.handleRequest(request);
        } else {
            System.out.println("没有合适的处理者");
        }
    }
}

class CEO extends Handler {
    public void handleRequest(Request request) {
        if (request.getType().equals("请假")) {
            System.out.println("CEO批准了" + request.getAmount() + "天的请假申请");
        } else if (request.getType().equals("加薪")) {
            System.out.println("CEO批准了" + request.getAmount() + "元的加薪申请");
        } else {
            System.out.println("CEO无法处理此类申请");
        }
    }
}

// 使用示例
public class ChainOfResponsibilityDemo {
    public static void main(String[] args) {
        // 构建责任链
        Handler teamLeader = new TeamLeader();
        Handler manager = new Manager();
        Handler director = new Director();
        Handler ceo = new CEO();
        
        teamLeader.setNextHandler(manager);
        manager.setNextHandler(director);
        director.setNextHandler(ceo);
        
        // 测试请求
        System.out.println("=== 1天请假申请 ===");
        teamLeader.handleRequest(new Request("请假", 1));
        
        System.out.println("\n=== 5天请假申请 ===");
        teamLeader.handleRequest(new Request("请假", 5));
        
        System.out.println("\n=== 500元加薪申请 ===");
        teamLeader.handleRequest(new Request("加薪", 500));
        
        System.out.println("\n=== 10000元加薪申请 ===");
        teamLeader.handleRequest(new Request("加薪", 10000));
    }
}

4.13 行为型模式总结

模式名称 主要目的 使用场景 优点 缺点
观察者模式 一对多依赖关系 状态变化需通知多个对象 松耦合、支持广播 可能造成内存泄漏
策略模式 算法族封装 多种算法可互换 算法独立、易扩展 客户端必须知道策略
模板方法 算法骨架定义 算法步骤固定但细节不同 代码复用、控制流程 子类数量可能较多
命令模式 请求封装 需要记录、撤销操作 解耦调用者和接收者 增加系统复杂度
状态模式 状态转换 对象行为随状态改变 状态转换明确 状态类数量较多
责任链模式 请求传递链 多个对象可处理请求 降低耦合、灵活分配 性能受影响

行为型模式的选择建议:

  • 一对多通知 → 观察者模式
  • 算法策略选择 → 策略模式
  • 算法步骤固定 → 模板方法模式
  • 请求排队撤销 → 命令模式
  • 对象状态转换 → 状态模式
  • 请求处理链 → 责任链模式


网站公告

今日签到

点亮在社区的每一天
去签到