Java23种设计模式案例

news/2025/2/26 7:40:12

目录

一、概述

二、创建型模式 (Creational Patterns)

单例模式 (Singleton Pattern)  

工厂方法模式 (Factory Method Pattern)  

抽象工厂模式 (Abstract Factory Pattern)  

建造者模式 (Builder Pattern)  

原型模式 (Prototype Pattern)  

三、结构型模式 (Structural Patterns)

适配器模式 (Adapter Pattern)  

装饰器模式 (Decorator Pattern)  

代理模式 (Proxy Pattern)  

桥接模式 (Bridge Pattern)  

组合模式 (Composite Pattern)  

外观模式 (Facade Pattern)  

享元模式 (Flyweight Pattern)  

四、行为型模式 (Behavioral Patterns)

责任链模式 (Chain of Responsibility Pattern)  

命令模式 (Command Pattern)  

解释器模式 (Interpreter Pattern)  

迭代器模式 (Iterator Pattern)  

中介者模式 (Mediator Pattern)  

备忘录模式 (Memento Pattern)  

状态模式 (State Pattern)  

策略模式 (Strategy Pattern)  

模板方法模式 (Template Method Pattern)  

访问者模式 (Visitor Pattern)  

观察者模式 (Observer Pattern)  

五、使用场景

场景一

策略模式 (Strategy Pattern)  

模板方法模式 (Template Method Pattern)  

命令模式 (Command Pattern)  

适配器模式 (Adapter Pattern)  


一、概述

在Java开发中,设计模式是解决常见问题的最佳实践,通常被归纳为23种经典设计模式,这些模式源自《设计模式:可复用面向对象软件的基础》一书(由GoF四人组提出)。这些模式分为三大类:创建型模式、结构型模式和行为型模式。提升代码的可维护性、可复用性、可扩展性。下面讲解这23种设计模式,包括定义、使用场景和简要示例。

创建型模式(Creational Patterns)

这些设计模式主要解决对象的创建问题。

单例模式(Singleton)

保证类只有一个实例,并提供全局访问点。

工厂方法模式(Factory Method)

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

抽象工厂模式(Abstract Factory)

提供一个接口,创建相关或依赖对象的家族,而不需要指定具体类。

建造者模式(Builder)

使用多个简单的对象一步步构建成一个复杂的对象,解耦了对象的创建和表示。

原型模式(Prototype)

通过复制现有的对象来创建新对象,避免重复创建相似对象。

结构型模式(Structural Patterns)

这些模式主要解决类和对象的组合结构问题。

适配器模式(Adapter)

将一个类的接口转换成客户端所期望的另一个接口,使得原本不兼容的接口可以一起工作。

桥接模式(Bridge)

将抽象部分与实现部分分离,使得两者可以独立变化。

过滤器模式(Filter)

通过组合多个过滤条件来筛选对象集合,链式调用,简化复杂的条件判断。

组合模式(Composite)

将对象组合成树形结构来表示“部分-整体”层次结构,使得客户端可以一致地对待单个对象和组合对象。

装饰器模式(Decorator)

动态地给一个对象添加额外的职责,而不影响其他对象。

外观模式(Facade)

为子系统中的一组接口提供一个统一的高层接口,简化客户端的使用。

享元模式(Flyweight)

用共享对象来支持大量细粒度的对象,减少内存占用。

观察者模式(Proxy)

这种模式也称为“发布-订阅”模式。它解耦了事件的发布者和消费者。  

行为型模式(Behavioral Patterns)

这些模式主要解决对象之间的通信问题和算法的设计。

责任链模式(Chain of Responsibility)

通过一系列处理对象来形成链条,客户端请求沿着链条传递,直到某个对象处理该请求。

命令模式(Command)

将请求封装为一个对象,从而允许用户使用不同的请求、队列或日志请求,并支持可撤销的操作。

解释器模式(Interpreter)

给定一个语言,定义一个文法,并通过解释器来解释该语言的句子。

迭代器模式(Iterator)

提供一种方法访问集合对象中的元素,而无需暴露集合的内部表示。

中介者模式(Mediator)

通过一个中介者对象来协调各个对象之间的交互,减少类之间的直接依赖。

备忘录模式(Memento)

在不暴露对象内部状态的情况下,捕获对象的状态并在需要时恢复。

观察者模式(Observer)

定义对象之间的一对多依赖关系,当一个对象的状态改变时,所有依赖它的对象都会收到通知并自动更新。

状态模式(State)

允许对象在内部状态改变时改变其行为,使得对象看起来像是修改了其类。

策略模式(Strategy)

定义一系列算法,将每一个算法封装起来,并使它们可以互换,允许在运行时选择算法。

模板方法模式(Template Method)

定义一个操作中的算法骨架,允许子类为一个或多个步骤提供具体实现。

这些设计模式被广泛应用于实际开发中,能够帮助开发者解决常见问题,并使代码更易于维护和扩展。

、创建型模式 (Creational Patterns)

这些模式关注对象的创建过程,帮助解耦对象的创建和使用。

单例模式 (Singleton Pattern)  

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

使用场景:需要唯一实例的场景,如日志记录器、配置管理器、线程池、数据库连接池等。  

示例:

下面是一个Java中**单例模式 (Singleton Pattern)**的示例。我们将以“日志记录器”为例,展示如何通过单例模式确保一个类只有一个实例,并提供全局访问点。

单例模式有多种实现方式,我会提供几种常见实现,并解释它们的优缺点。

示例 1:懒汉式(延迟加载,非线程安全)

java">// 1. 懒汉式单例
class Logger {
    private static Logger instance;

    // 私有构造器,防止外部实例化
    private Logger() {
        System.out.println("Logger 创建");
    }

    // 提供全局访问点
    public static Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }

    public void log(String message) {
        System.out.println("日志: " + message);
    }
}

// 测试代码
public class SingletonPatternDemo {
    public static void main(String[] args) {
        Logger logger1 = Logger.getInstance();
        Logger logger2 = Logger.getInstance();

        logger1.log("第一次记录");
        logger2.log("第二次记录");

        System.out.println("logger1 == logger2: " + (logger1 == logger2));
    }
}

输出结果

Logger 创建

日志: 第一次记录

日志: 第二次记录

logger1 == logger2: true

解析

特点:延迟加载(懒汉式),只有在第一次调用 getInstance 时才创建实例。

缺点:线程不安全,多线程环境下可能创建多个实例。

示例 2:懒汉式(线程安全,使用同步)

java">class Logger {
    private static Logger instance;

    private Logger() {
        System.out.println("Logger 创建");
    }

    // 使用 synchronized 确保线程安全
    public static synchronized Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }

    public void log(String message) {
        System.out.println("日志: " + message);
    }
}

输出结果

与示例 1 相同,但线程安全。

解析

改进:通过 synchronized 关键字实现线程安全。

缺点:每次调用 getInstance 都会加锁,性能开销较大。

示例 3:双重检查锁定(Double-Checked Locking)

java">class Logger {
    private static volatile Logger instance; // 使用 volatile 防止指令重排序

    private Logger() {
        System.out.println("Logger 创建");
    }

    public static Logger getInstance() {
        if (instance == null) {
            synchronized (Logger.class) {
                if (instance == null) {
                    instance = new Logger();
                }
            }
        }
        return instance;
    }

    public void log(String message) {
        System.out.println("日志: " + message);
    }
}

输出结果

与示例 1 相同,但线程安全且性能优化。

解析

改进:双重检查锁定,只有在实例未创建时才加锁,提高性能。

注意:使用 volatile 防止指令重排序,确保线程安全(Java 1.5+)。

示例 4:饿汉式(静态初始化)

java">class Logger {
    private static final Logger instance = new Logger(); // 类加载时创建

    private Logger() {
        System.out.println("Logger 创建");
    }

    public static Logger getInstance() {
        return instance;
    }

    public void log(String message) {
        System.out.println("日志: " + message);
    }
}

输出结果

Logger 创建

日志: 第一次记录

日志: 第二次记录

logger1 == logger2: true

解析

特点:饿汉式,类加载时立即创建实例。

优点:线程安全,简单。

缺点:不支持延迟加载,即使不使用也会创建实例。

示例 5:静态内部类(推荐)

java">class Logger {
    private Logger() {
        System.out.println("Logger 创建");
    }

    // 静态内部类,延迟加载
    private static class LoggerHolder {
        private static final Logger INSTANCE = new Logger();
    }

    public static Logger getInstance() {
        return LoggerHolder.INSTANCE;
    }

    public void log(String message) {
        System.out.println("日志: " + message);
    }
}

输出结果

Logger 创建

日志: 第一次记录

日志: 第二次记录

logger1 == logger2: true

解析

特点:利用静态内部类的特性,只有在调用 getInstance 时才加载 LoggerHolder,实现延迟加载。

优点:线程安全、无锁高性能、延迟加载,是推荐的实现方式。

示例 6:枚举单例(最简洁)

java">enum Logger {
    INSTANCE; // 唯一实例

    public void log(String message) {
        System.out.println("日志: " + message);
    }
}

// 测试代码
public class SingletonPatternDemo {
    public static void main(String[] args) {
        Logger logger1 = Logger.INSTANCE;
        Logger logger2 = Logger.INSTANCE;

        logger1.log("第一次记录");
        logger2.log("第二次记录");

        System.out.println("logger1 == logger2: " + (logger1 == logger2));
    }
}

输出结果

日志: 第一次记录

日志: 第二次记录

logger1 == logger2: true

解析

特点:利用Java枚举的特性,天生单例且线程安全。

优点:最简洁、防反射攻击、防序列化问题。

缺点:不支持延迟加载,枚举类加载时即创建。

单例模式的优点

唯一实例:确保全局只有一个实例,节省资源。

全局访问:提供统一的访问点,方便使用。

注意事项

线程安全:在多线程环境中需选择合适的实现(如双重检查、静态内部类)。

反射与序列化:普通单例可能被反射或序列化破坏,枚举单例可避免这些问题。

工厂方法模式 (Factory Method Pattern)  

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

使用场景需要创建不同种类对象的场景,尤其是当创建对象的具体类在运行时决定时。比如日志系统的不同日志写入方式,或数据库连接的不同实现。

示例:假设我们要创建一个车辆工厂,可以生产不同类型的车辆(如汽车和摩托车)。工厂模式的核心是通过一个工厂类来封装对象的创建逻辑。

java">// 1. 定义车辆接口
interface Vehicle {
    void drive();
}

// 2. 实现具体车辆类
class Car implements Vehicle {
    @Override
    public void drive() {
        System.out.println("驾驶一辆汽车!");
    }
}

class Motorcycle implements Vehicle {
    @Override
    public void drive() {
        System.out.println("驾驶一辆摩托车!");
    }
}

// 3. 创建工厂类
class VehicleFactory {
    // 根据类型参数创建对应的车辆对象
    public static Vehicle createVehicle(String type) {
        if ("car".equalsIgnoreCase(type)) {
            return new Car();
        } else if ("motorcycle".equalsIgnoreCase(type)) {
            return new Motorcycle();
        } else {
            throw new IllegalArgumentException("未知的车辆类型: " + type);
        }
    }
}

// 4. 测试代码
public class FactoryPatternDemo {
    public static void main(String[] args) {
        // 通过工厂创建汽车
        Vehicle car = VehicleFactory.createVehicle("car");
        car.drive();

        // 通过工厂创建摩托车
        Vehicle motorcycle = VehicleFactory.createVehicle("motorcycle");
        motorcycle.drive();

        // 测试无效输入
        try {
            Vehicle unknown = VehicleFactory.createVehicle("bike");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

工厂模式的优点

封装创建逻辑:调用者无需知道具体类的实现细节,只需通过工厂获取对象。

易于扩展:如果需要添加新类型(如“Truck”),只需新增类并修改工厂逻辑,不影响现有代码。

解耦:客户端代码与具体实现类解耦,符合开闭原则。

抽象工厂模式 (Abstract Factory Pattern)  

定义:提供一个接口,用于创建一系列相关或依赖对象的家族。  

使用场景:当需要创建一系列相关或依赖对象时,且客户端不需要指定具体类。比如操作系统的界面组件库,或跨平台的UI组件。  

示例:假设我们要为不同操作系统(如Windows和Mac)创建UI组件(按钮和文本框),抽象工厂模式可以帮助我们生产一组风格一致的对象

java">// 1. 定义抽象产品接口
interface Button {
    void render();
}

interface TextBox {
    void display();
}

// 2. 实现具体产品类(Windows风格)
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染一个Windows风格的按钮");
    }
}

class WindowsTextBox implements TextBox {
    @Override
    public void display() {
        System.out.println("显示一个Windows风格的文本框");
    }
}

// 3. 实现具体产品类(Mac风格)
class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染一个Mac风格的按钮");
    }
}

class MacTextBox implements TextBox {
    @Override
    public void display() {
        System.out.println("显示一个Mac风格的文本框");
    }
}

// 4. 定义抽象工厂接口
interface UIFactory {
    Button createButton();
    TextBox createTextBox();
}

// 5. 实现具体工厂类
class WindowsUIFactory implements UIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}

class MacUIFactory implements UIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public TextBox createTextBox() {
        return new MacTextBox();
    }
}

// 6. 测试代码
public class AbstractFactoryDemo {
    public static void main(String[] args) {
        // 创建Windows风格的UI组件
        UIFactory windowsFactory = new WindowsUIFactory();
        Button windowsButton = windowsFactory.createButton();
        TextBox windowsTextBox = windowsFactory.createTextBox();

        windowsButton.render();
        windowsTextBox.display();

        // 创建Mac风格的UI组件
        UIFactory macFactory = new MacUIFactory();
        Button macButton = macFactory.createButton();
        TextBox macTextBox = macFactory.createTextBox();

        macButton.render();
        macTextBox.display();
    }
}

抽象工厂模式的优点

产品族一致性:确保创建的对象属于同一个家族(如Windows风格的按钮和文本框)。

解耦:客户端代码只依赖抽象接口,不关心具体实现。

易于扩展新产品族:添加新风格(如Linux)只需新增一个具体工厂类和相关产品类。

与工厂方法的区别

工厂方法模式:关注单个对象的创建,一个工厂方法创建一个产品。

抽象工厂模式:关注一组相关对象的创建,一个工厂创建整个产品族。

建造者模式 (Builder Pattern)  

定义:将复杂对象的构建与其表示分离,逐步构建对象。  

使用场景:用于构建复杂对象的场景,尤其是在构建过程中的各个部分需要分步骤组合时。比如在创建复杂对象时,想要解耦构建过程与对象表示(例如,构建HTML页面,或者生成复杂的配置对象)。

示例:假设我们要构建一台计算机,包含多个部件(如CPU、内存、硬盘)。建造者模式可以将构建过程与最终对象的表示分离,支持灵活配置。

java">// 1. 定义产品类(计算机)
class Computer {
    private String cpu;
    private String ram;
    private String storage;

    // 私有构造器,只能通过Builder创建
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
    }

    @Override
    public String toString() {
        return "Computer [CPU=" + cpu + ", RAM=" + ram + ", Storage=" + storage + "]";
    }

    // 2. 定义内部建造者类
    public static class Builder {
        private String cpu;
        private String ram;
        private String storage;

        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder setRam(String ram) {
            this.ram = ram;
            return this;
        }

        public Builder setStorage(String storage) {
            this.storage = storage;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }
}

// 3. 测试代码
public class BuilderPatternDemo {
    public static void main(String[] args) {
        // 使用建造者构建基本配置计算机
        Computer basicComputer = new Computer.Builder()
            .setCpu("Intel i5")
            .setRam("8GB")
            .build();
        System.out.println("基本配置: " + basicComputer);

        // 使用建造者构建高配计算机
        Computer highEndComputer = new Computer.Builder()
            .setCpu("Intel i9")
            .setRam("32GB")
            .setStorage("1TB SSD")
            .build();
        System.out.println("高配: " + highEndComputer);
    }
}

建造者模式的优点

分步构建:将复杂对象的构造过程分解为多个步骤。

灵活性:支持创建不同配置的对象,属性设置顺序无关。

不可变性:产品对象可以通过私有构造器和无 setter 方法保持不可变。

与工厂模式的区别

建造者模式:关注分步构造复杂对象,强调灵活性和过程控制。

工厂模式:关注一次性创建对象,通常不涉及逐步构建。

原型模式 (Prototype Pattern)  

定义:通过复制现有对象来创建新对象。  

使用场景:当需要复制大量相似对象,并且希望避免重复创建时。比如游戏中角色的副本、文件系统中的文件复制等。

示例:假设我们有一个图形类(如圆形),支持克隆操作。原型模式允许我们通过复制原型对象来生成新实例,而无需从头构造。

java">// 1. 定义原型接口
interface Prototype {
    Prototype clone(); // 克隆方法
    void setColor(String color);
    String getColor();
}

// 2. 实现具体原型类(圆形)
class Circle implements Prototype, Cloneable {
    private int radius;
    private String color;

    public Circle(int radius, String color) {
        this.radius = radius;
        this.color = color;
    }

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone(); // 使用Object的clone方法进行浅克隆
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String getColor() {
        return color;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public int getRadius() {
        return radius;
    }

    @Override
    public String toString() {
        return "Circle [radius=" + radius + ", color=" + color + "]";
    }
}

// 3. 测试代码
public class PrototypePatternDemo {
    public static void main(String[] args) {
        // 创建原型对象
        Circle prototype = new Circle(10, "红色");
        System.out.println("原型对象: " + prototype);

        // 克隆对象并修改
        Circle circle1 = (Circle) prototype.clone();
        circle1.setColor("蓝色");
        System.out.println("克隆对象1: " + circle1);

        Circle circle2 = (Circle) prototype.clone();
        circle2.setRadius(20);
        circle2.setColor("绿色");
        System.out.println("克隆对象2: " + circle2);

        // 原型对象保持不变
        System.out.println("原型对象未变: " + prototype);
    }
}

原型模式的优点

性能提升:通过复制已有对象创建新实例,避免从头构造的开销。

简化创建:适用于构造复杂或耗时的对象。

动态性:可以运行时生成不同状态的对象。

浅克隆 vs 深克隆

上述示例使用的是浅克隆(Object.clone()),只复制对象的基本字段。如果对象包含引用类型(如集合),需要实现深克隆。以下是深克隆的示例:

深克隆示例

java">import java.util.ArrayList;
import java.util.List;

class ComplexCircle implements Prototype, Cloneable {
    private int radius;
    private String color;
    private List<String> tags; // 引用类型字段

    public ComplexCircle(int radius, String color) {
        this.radius = radius;
        this.color = color;
        this.tags = new ArrayList<>();
    }

    @Override
    public Prototype clone() {
        try {
            ComplexCircle cloned = (ComplexCircle) super.clone();
            cloned.tags = new ArrayList<>(this.tags); // 深克隆引用类型
            return cloned;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String getColor() {
        return color;
    }

    public void addTag(String tag) {
        tags.add(tag);
    }

    @Override
    public String toString() {
        return "ComplexCircle [radius=" + radius + ", color=" + color + ", tags=" + tags + "]";
    }
}

// 测试深克隆
public class PrototypePatternDemo {
    public static void main(String[] args) {
        ComplexCircle prototype = new ComplexCircle(10, "红色");
        prototype.addTag("圆形");
        System.out.println("原型对象: " + prototype);

        ComplexCircle cloned = (ComplexCircle) prototype.clone();
        cloned.setColor("蓝色");
        cloned.addTag("克隆");
        System.out.println("克隆对象: " + cloned);
        System.out.println("原型对象未变: " + prototype);
    }
}

输出

原型对象: ComplexCircle [radius=10, color=红色, tags=[圆形]]

克隆对象: ComplexCircle [radius=10, color=蓝色, tags=[圆形, 克隆]]

原型对象未变: ComplexCircle [radius=10, color=红色, tags=[圆形]]

在深克隆中,tags 列表被独立复制,修改克隆对象的 tags 不会影响原型。

、结构型模式 (Structural Patterns)

这些模式关注类和对象的组合,优化结构。

适配器模式 (Adapter Pattern)  

定义:将不兼容的接口转换为可用的接口。  

使用场景:用于解决接口不兼容的问题。比如当需要让新系统与旧系统交互时,可以使用适配器模式。另一个常见的例子是数据库的多种实现(JDBC、Hibernate)之间的适配。

示例:假设我们有一个旧的电源接口(输出220V),但新设备需要110V的电源。适配器模式可以将旧接口适配为新接口。

java">// 1. 定义目标接口(新设备期望的接口)
interface TargetVoltage {
    int get110V(); // 提供110V电压
}

// 2. 定义被适配者(旧电源)
class OldPower {
    public int get220V() {
        System.out.println("旧电源提供 220V 电压");
        return 220V;
    }
}

// 3. 实现适配器类
class PowerAdapter implements TargetVoltage {
    private OldPower oldPower;

    public PowerAdapter(OldPower oldPower) {
        this.oldPower = oldPower;
    }

    @Override
    public int get110V() {
        int voltage = oldPower.get220V();
        int adaptedVoltage = voltage / 2; // 简单模拟转换
        System.out.println("适配器将 220V 转换为 110V");
        return adaptedVoltage;
    }
}

// 4. 测试代码
public class AdapterPatternDemo {
    public static void main(String[] args) {
        // 创建旧电源
        OldPower oldPower = new OldPower();

        // 使用适配器将旧电源适配为新接口
        TargetVoltage adapter = new PowerAdapter(oldPower);

        // 新设备使用适配后的电源
        System.out.println("新设备使用电压: " + adapter.get110V());
    }
}

适配器模式的优点

兼容性:将不兼容的接口转换为目标接口,复用现有代码。

解耦:客户端只依赖目标接口,与被适配者解耦。

灵活性:适配器可以在不同场景中桥接不同接口。

适配器模式的两种形式

类适配器:通过继承实现(需要多重继承,Java中较少用)。

对象适配器:通过组合实现(上例使用此方式,更常用)。

类适配器示例

java">interface TargetVoltage {
    int get110V();
}

class OldPower {
    public int get220V() {
        System.out.println("旧电源提供 220V 电压");
        return 220V;
    }
}

// 类适配器通过继承
class ClassPowerAdapter extends OldPower implements TargetVoltage {
    @Override
    public int get110V() {
        int voltage = get220V();
        int adaptedVoltage = voltage / 2;
        System.out.println("类适配器将 220V 转换为 110V");
        return adaptedVoltage;
    }
}

// 测试
public class AdapterPatternDemo {
    public static void main(String[] args) {
        TargetVoltage adapter = new ClassPowerAdapter();
        System.out.println("新设备使用电压: " + adapter.get110V());
    }
}

装饰器模式 (Decorator Pattern)  

定义:动态为对象添加职责,不改变其接口。  

使用场景:用于动态地给对象添加功能而不改变其结构。比如,咖啡店中的各种咖啡加料场景(加奶、加糖等)。

示例:假设我们有一个基础咖啡类,用户可以选择添加不同的配料(如牛奶、糖),装饰器模式允许我们在运行时动态组合这些配料。

java">// 1. 定义组件接口
interface Coffee {
    String getDescription(); // 获取描述
    double getCost();        // 获取价格
}

// 2. 实现具体组件(基础咖啡)
class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "简单咖啡";
    }

    @Override
    public double getCost() {
        return 5.0;
    }
}

// 3. 定义装饰器抽象类
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

// 4. 实现具体装饰器
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + " + 牛奶";
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 2.0;
    }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + " + 糖";
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 1.0;
    }
}

// 5. 测试代码
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee simpleCoffee = new SimpleCoffee();
        System.out.println(simpleCoffee.getDescription() + " 价格: " + simpleCoffee.getCost());

        // 加牛奶的咖啡
        Coffee milkCoffee = new MilkDecorator(simpleCoffee);
        System.out.println(milkCoffee.getDescription() + " 价格: " + milkCoffee.getCost());

        // 加牛奶和糖的咖啡
        Coffee milkSugarCoffee = new SugarDecorator(new MilkDecorator(simpleCoffee));
        System.out.println(milkSugarCoffee.getDescription() + " 价格: " + milkSugarCoffee.getCost());
    }
}

装饰器模式的优点

动态扩展:可以在运行时为对象添加功能,无需修改原有类。

灵活组合:支持多种装饰器的自由组合。

符合开闭原则:对扩展开放,对修改关闭。

Java中的实际应用

Java I/O类(如 InputStream)广泛使用装饰器模式。例如:

java">import java.io.*;

public class JavaIODemo {
    public static void main(String[] args) throws IOException {
        InputStream input = new FileInputStream("test.txt");
        InputStream bufferedInput = new BufferedInputStream(input); // 装饰器添加缓冲功能
        BufferedReader reader = new BufferedReader(new InputStreamReader(bufferedInput)); // 再装饰为字符流
        System.out.println(reader.readLine());
        reader.close();
    }
}

代理模式 (Proxy Pattern)  

定义:为对象提供代理,控制对其访问。  

使用场景:用于控制对对象的访问,常用于需要延迟初始化或访问控制的场景。例如,数据库访问代理、图片的延迟加载代理、Spring AOP等。

示例:假设我们要加载一张图片,但图片加载可能很耗时。我们可以使用代理模式,在需要时才加载真实图片,而代理对象先提供占位功能。

java">// 1. 定义主题接口
interface Image {
    void display(); // 显示图片
}

// 2. 实现真实主题(真实图片)
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadImageFromDisk(); // 模拟从磁盘加载
    }

    private void loadImageFromDisk() {
        System.out.println("从磁盘加载图片: " + filename);
    }

    @Override
    public void display() {
        System.out.println("显示图片: " + filename);
    }
}

// 3. 实现代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename); // 延迟加载
        }
        realImage.display();
    }
}

// 4. 测试代码
public class ProxyPatternDemo {
    public static void main(String[] args) {
        // 创建代理图片对象
        Image image1 = new ProxyImage("photo1.jpg");
        Image image2 = new ProxyImage("photo2.jpg");

        // 第一次显示图片(触发加载)
        System.out.println("第一次显示图片:");
        image1.display();

        // 第二次显示图片(直接使用已加载的实例)
        System.out.println("\n第二次显示图片:");
        image1.display();

        // 显示另一张图片
        System.out.println("\n显示另一张图片:");
        image2.display();
    }
}

和装饰者模式较为相似

代理模式的优点

访问控制:代理可以延迟加载、权限检查等,控制对真实对象的访问。

性能优化:如本例中的延迟加载,减少不必要的资源消耗。

解耦:客户端只与代理交互,不直接依赖真实对象。

代理模式的常见类型

虚拟代理:如本例,用于延迟加载。

保护代理:添加权限控制。

远程代理:封装远程对象访问。

Java中的代理支持

Java提供了动态代理(java.lang.reflect.Proxy),可以运行时生成代理对象。例如:

java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

class DynamicProxyHandler implements InvocationHandler {
    private Object target;

    public DynamicProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理调用方法: " + method.getName());
        return method.invoke(target, args);
    }
}

public class DynamicProxyDemo {
    public static void main(String[] args) {
        RealImage realImage = new RealImage("photo.jpg");
        Image proxyImage = (Image) Proxy.newProxyInstance(
            Image.class.getClassLoader(),
            new Class[]{Image.class},
            new DynamicProxyHandler(realImage)
        );
        proxyImage.display();
    }
}

桥接模式 (Bridge Pattern)  

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

使用场景:当你需要将抽象与其实现解耦时。比如图形库中,既有抽象的图形(如Shape),也有具体的实现(如圆形、正方形等),且你希望能够独立扩展每个部分。  

示例:假设我们有不同类型的设备(如电视和收音机)和遥控器(如基本遥控器和高级遥控器)。桥接模式可以将设备的功能实现与遥控器的控制逻辑解耦。

java">// 1. 定义实现部分的接口(设备)
interface Device {
    void powerOn();
    void powerOff();
    void setVolume(int volume);
    int getVolume();
}

// 2. 实现具体设备
class Television implements Device {
    private int volume = 50;
    private boolean isOn = false;

    @Override
    public void powerOn() {
        isOn = true;
        System.out.println("电视已开启");
    }

    @Override
    public void powerOff() {
        isOn = false;
        System.out.println("电视已关闭");
    }

    @Override
    public void setVolume(int volume) {
        this.volume = volume;
        System.out.println("电视音量设置为: " + volume);
    }

    @Override
    public int getVolume() {
        return volume;
    }
}

class Radio implements Device {
    private int volume = 30;
    private boolean isOn = false;

    @Override
    public void powerOn() {
        isOn = true;
        System.out.println("收音机已开启");
    }

    @Override
    public void powerOff() {
        isOn = false;
        System.out.println("收音机已关闭");
    }

    @Override
    public void setVolume(int volume) {
        this.volume = volume;
        System.out.println("收音机音量设置为: " + volume);
    }

    @Override
    public int getVolume() {
        return volume;
    }
}

// 3. 定义抽象部分(遥控器)
abstract class RemoteControl {
    protected Device device;

    public RemoteControl(Device device) {
        this.device = device;
    }

    public abstract void turnOn();
    public abstract void turnOff();
    public abstract void adjustVolume(int volume);
}

// 4. 实现具体遥控器
class BasicRemote extends RemoteControl {
    public BasicRemote(Device device) {
        super(device);
    }

    @Override
    public void turnOn() {
        device.powerOn();
    }

    @Override
    public void turnOff() {
        device.powerOff();
    }

    @Override
    public void adjustVolume(int volume) {
        device.setVolume(volume);
    }
}

class AdvancedRemote extends RemoteControl {
    public AdvancedRemote(Device device) {
        super(device);
    }

    @Override
    public void turnOn() {
        device.powerOn();
    }

    @Override
    public void turnOff() {
        device.powerOff();
    }

    @Override
    public void adjustVolume(int volume) {
        device.setVolume(volume);
    }

    // 高级功能:静音
    public void mute() {
        device.setVolume(0);
        System.out.println("设备已静音");
    }
}

// 5. 测试代码
public class BridgePatternDemo {
    public static void main(String[] args) {
        // 创建设备
        Device tv = new Television();
        Device radio = new Radio();

        // 使用基本遥控器控制电视
        System.out.println("使用基本遥控器控制电视:");
        RemoteControl basicRemote = new BasicRemote(tv);
        basicRemote.turnOn();
        basicRemote.adjustVolume(70);
        basicRemote.turnOff();

        System.out.println();

        // 使用高级遥控器控制收音机
        System.out.println("使用高级遥控器控制收音机:");
        RemoteControl advancedRemote = new AdvancedRemote(radio);
        advancedRemote.turnOn();
        advancedRemote.adjustVolume(40);
        ((AdvancedRemote) advancedRemote).mute();
        advancedRemote.turnOff();
    }
}

桥接模式的优点

解耦:将设备的实现与遥控器的抽象分离,两者可以独立变化。

扩展性:新增设备(如音箱)或遥控器(如智能遥控器)无需修改现有代码。

灵活性:支持设备的多种控制方式组合。

组合模式 (Composite Pattern)  

定义:将对象组合成树形结构,表示部分-整体关系。  

使用场景:用于树形结构的组合对象,例如文件系统中的目录和文件,或GUI组件中的窗体和控件。  

示例:假设有一个文件系统,包含文件和文件夹两种元素。文件夹可以包含文件或其他文件夹,我们希望统一处理这些元素(例如计算总大小)。组合模式可以帮助我们实现这一点。

java">import java.util.ArrayList;
import java.util.List;

// 1. 定义组件接口
interface FileSystemComponent {
    int getSize();           // 获取大小
    void printName();        // 打印名称
}

// 2. 实现叶子节点(文件)
class File implements FileSystemComponent {
    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public void printName() {
        System.out.println("文件: " + name + " (" + size + "字节)");
    }
}

// 3. 实现组合节点(文件夹)
class Folder implements FileSystemComponent {
    private String name;
    private List<FileSystemComponent> components = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    public void add(FileSystemComponent component) {
        components.add(component);
    }

    public void remove(FileSystemComponent component) {
        components.remove(component);
    }

    @Override
    public int getSize() {
        int totalSize = 0;
        for (FileSystemComponent component : components) {
            totalSize += component.getSize();
        }
        return totalSize;
    }

    @Override
    public void printName() {
        System.out.println("文件夹: " + name);
        for (FileSystemComponent component : components) {
            component.printName();
        }
    }
}

// 4. 测试代码
public class CompositePatternDemo {
    public static void main(String[] args) {
        // 创建文件
        File file1 = new File("文档1.txt", 100);
        File file2 = new File("图片1.jpg", 200);
        File file3 = new File("视频1.mp4", 500);

        // 创建文件夹并添加文件
        Folder folder1 = new Folder("我的文档");
        folder1.add(file1);
        folder1.add(file2);

        Folder rootFolder = new Folder("根目录");
        rootFolder.add(folder1);
        rootFolder.add(file3);

        // 测试操作
        System.out.println("文件系统结构:");
        rootFolder.printName();

        System.out.println("\n总大小: " + rootFolder.getSize() + " 字节");

        // 测试单独文件
        System.out.println("\n单个文件大小: " + file1.getSize() + " 字节");
    }
}

组合模式的优点

统一接口:文件和文件夹通过同一接口操作,客户端无需区分。

树形结构:自然支持层次结构,适合表示部分-整体关系。

扩展性:新增组件类型(如符号链接)只需实现 FileSystemComponent 接口。

注意事项

透明性 vs 安全性:  

当前示例采用透明性设计(接口中定义所有操作),叶子节点(如 File)无需实现 add 等方法,但可能导致误用。

若追求安全性,可将 add 和 remove 移到 Folder 类中,但客户端需区分类型。

外观模式 (Facade Pattern)  

定义:为子系统提供统一接口,简化调用。  

使用场景:用于简化复杂系统的使用接口,使客户端只需要通过一个统一的接口访问子系统的功能。例如启动计算机时,隐藏了启动CPU、加载内存等复杂操作。  

示例:假设有一个家庭影院系统,包含多个子系统(如DVD播放器、投影仪、音响)。用户需要执行一系列操作来观看电影,外观模式可以封装这些操作,提供简单接口。

java">// 1. 定义子系统类
class DVDPlayer {
    public void on() {
        System.out.println("DVD播放器已开启");
    }

    public void play(String movie) {
        System.out.println("DVD播放器正在播放: " + movie);
    }

    public void off() {
        System.out.println("DVD播放器已关闭");
    }
}

class Projector {
    public void on() {
        System.out.println("投影仪已开启");
    }

    public void setInput(String input) {
        System.out.println("投影仪输入源设置为: " + input);
    }

    public void off() {
        System.out.println("投影仪已关闭");
    }
}

class SoundSystem {
    public void on() {
        System.out.println("音响系统已开启");
    }

    public void setVolume(int level) {
        System.out.println("音响音量设置为: " + level);
    }

    public void off() {
        System.out.println("音响系统已关闭");
    }
}

// 2. 定义外观类(家庭影院)
class HomeTheaterFacade {
    private DVDPlayer dvdPlayer;
    private Projector projector;
    private SoundSystem soundSystem;

    public HomeTheaterFacade(DVDPlayer dvdPlayer, Projector projector, SoundSystem soundSystem) {
        this.dvdPlayer = dvdPlayer;
        this.projector = projector;
        this.soundSystem = soundSystem;
    }

    // 观看电影的简化接口
    public void watchMovie(String movie) {
        System.out.println("准备观看电影...");
        dvdPlayer.on();
        projector.on();
        projector.setInput("DVD");
        soundSystem.on();
        soundSystem.setVolume(10);
        dvdPlayer.play(movie);
    }

    // 关闭系统的简化接口
    public void endMovie() {
        System.out.println("关闭家庭影院...");
        dvdPlayer.off();
        projector.off();
        soundSystem.off();
    }
}

// 3. 测试代码
public class FacadePatternDemo {
    public static void main(String[] args) {
        // 创建子系统实例
        DVDPlayer dvdPlayer = new DVDPlayer();
        Projector projector = new Projector();
        SoundSystem soundSystem = new SoundSystem();

        // 创建外观对象
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(dvdPlayer, projector, soundSystem);

        // 使用外观接口观看电影
        homeTheater.watchMovie("《星际穿越》");

        System.out.println();

        // 使用外观接口关闭系统
        homeTheater.endMovie();
    }
}

外观模式的优点

简化接口:为复杂的子系统提供统一的、易于使用的接口。

解耦:客户端与子系统解耦,只依赖外观类,不直接操作子系统。

提高可读性:隐藏子系统的复杂性,客户端代码更简洁。

享元模式 (Flyweight Pattern)  

定义:共享对象以减少内存使用。  

使用场景:用于需要大量共享对象的场景,以减少内存消耗。比如文字处理系统中的字符对象、游戏中的图形元素(如树、草等)。  

示例:假设我们要绘制多个圆形,每个圆形有颜色和位置属性,其中颜色是可共享的(内在状态),而位置是变化的(外在状态)。享元模式可以避免为每个圆形创建重复的颜色对象。

java">import java.util.HashMap;
import java.util.Map;

// 1. 定义享元接口
interface Shape {
    void draw(int x, int y); // 绘制方法,位置为外在状态
}

// 2. 实现具体享元类(圆形)
class Circle implements Shape {
    private String color; // 内在状态,可共享

    public Circle(String color) {
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("绘制 " + color + " 圆形,位置: (" + x + ", " + y + ")");
    }
}

// 3. 定义享元工厂
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;
    }
}

// 4. 测试代码
public class FlyweightPatternDemo {
    private static final String[] colors = {"红色", "蓝色", "绿色"};

    public static void main(String[] args) {
        // 绘制多个圆形
        for (int i = 0; i < 10; i++) {
            String color = colors[(int) (Math.random() * colors.length)];
            Shape circle = ShapeFactory.getCircle(color);
            circle.draw(i * 10, i * 20); // 随机位置
        }
    }
}

享元模式的优点

减少内存占用:通过共享对象(如相同颜色的圆形),避免重复创建。

提高效率:适用于大量相似对象的场景,减少资源消耗。

分离状态:内在状态(color)共享,外在状态(位置)动态传入。

注意事项

内在状态与外在状态:享元模式的关键是区分可共享的内在状态和不可共享的外在状态。

线程安全:在多线程环境下,享元工厂需要同步机制(如使用 ConcurrentHashMap 或 synchronized)。

、行为型模式 (Behavioral Patterns)

这些模式关注对象间的通信和职责分配。

责任链模式 (Chain of Responsibility Pattern)  

定义:将请求沿处理链传递,直到被处理。  

使用场景:用于多个对象都有机会处理请求时,避免了请求处理者的硬编码。比如,在日志处理或权限检查中,每个处理器可以根据条件决定是否处理请求。

示例:假设一个员工提交请假请求,需要经过不同级别的管理者审批(小组长、部门经理、总经理)。每个管理者有自己的审批权限,如果无法处理则传递给下一级。

java">// 1. 定义请假请求类
class LeaveRequest {
    private int days;
    private String name;

    public LeaveRequest(String name, int days) {
        this.name = name;
        this.days = days;
    }

    public int getDays() { return days; }
    public String getName() { return name; }
}

// 2. 定义抽象处理者类
abstract class Approver {
    protected Approver nextApprover; // 下一级处理者

    public void setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
    }

    // 处理请假请求的抽象方法
    public abstract void handleRequest(LeaveRequest request);
}

// 3. 实现具体处理者
class TeamLeader extends Approver {
    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getDays() <= 2) {
            System.out.println("小组长批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假请求");
        } else if (nextApprover != null) {
            System.out.println("小组长无权审批,传递给下一级");
            nextApprover.handleRequest(request);
        } else {
            System.out.println("无人能批准 " + request.getName() + " 的请求");
        }
    }
}

class DepartmentManager extends Approver {
    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getDays() <= 5) {
            System.out.println("部门经理批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假请求");
        } else if (nextApprover != null) {
            System.out.println("部门经理无权审批,传递给下一级");
            nextApprover.handleRequest(request);
        } else {
            System.out.println("无人能批准 " + request.getName() + " 的请求");
        }
    }
}

class GeneralManager extends Approver {
    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getDays() <= 15) {
            System.out.println("总经理批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假请求");
        } else {
            System.out.println("总经理也无权批准 " + request.getName() + " 的 " + request.getDays() + " 天请假请求");
        }
    }
}

// 4. 测试代码
public class ChainOfResponsibilityDemo {
    public static void main(String[] args) {
        // 创建审批链
        Approver teamLeader = new TeamLeader();
        Approver deptManager = new DepartmentManager();
        Approver generalManager = new GeneralManager();

        // 设置责任链:小组长 -> 部门经理 -> 总经理
        teamLeader.setNextApprover(deptManager);
        deptManager.setNextApprover(generalManager);

        // 测试不同天数的请假请求
        LeaveRequest request1 = new LeaveRequest("张三", 1);
        LeaveRequest request2 = new LeaveRequest("李四", 4);
        LeaveRequest request3 = new LeaveRequest("王五", 10);
        LeaveRequest request4 = new LeaveRequest("赵六", 20);

        System.out.println("请求1:");
        teamLeader.handleRequest(request1);
        System.out.println("\n请求2:");
        teamLeader.handleRequest(request2);
        System.out.println("\n请求3:");
        teamLeader.handleRequest(request3);
        System.out.println("\n请求4:");
        teamLeader.handleRequest(request4);
    }
}

责任链模式的优点

解耦请求与处理:请求发送者无需知道具体由谁处理。

灵活性:可以动态调整链的顺序或添加新的处理者。

单一职责:每个处理者只关注自己的权限范围。

命令模式 (Command Pattern)  

定义:将请求封装成对象,支持撤销、重做。  

使用场景:用于将请求封装为对象,从而支持请求的参数化、队列管理、撤销操作等。比如遥控器控制家电的场景,或者操作系统中的任务调度。

示例:假设我们有一个遥控器,可以控制电灯和电视(开/关操作)。命令模式允许我们将这些操作封装为命令对象,遥控器只需发送命令,而无需知道具体实现。

java">// 1. 定义接收者(家电设备)
class Light {
    public void turnOn() {
        System.out.println("电灯已打开");
    }

    public void turnOff() {
        System.out.println("电灯已关闭");
    }
}

class TV {
    public void turnOn() {
        System.out.println("电视已打开");
    }

    public void turnOff() {
        System.out.println("电视已关闭");
    }
}

// 2. 定义命令接口
interface Command {
    void execute(); // 执行命令
}

// 3. 实现具体命令
class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOff();
    }
}

class TVOnCommand implements Command {
    private TV tv;

    public TVOnCommand(TV tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.turnOn();
    }
}

class TVOffCommand implements Command {
    private TV tv;

    public TVOffCommand(TV tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.turnOff();
    }
}

// 4. 定义调用者(遥控器)
class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        if (command != null) {
            command.execute();
        } else {
            System.out.println("未设置命令!");
        }
    }
}

// 5. 测试代码
public class CommandPatternDemo {
    public static void main(String[] args) {
        // 创建接收者
        Light light = new Light();
        TV tv = new TV();

        // 创建命令对象
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);
        Command tvOn = new TVOnCommand(tv);
        Command tvOff = new TVOffCommand(tv);

        // 创建遥控器
        RemoteControl remote = new RemoteControl();

        // 测试遥控器控制电灯
        System.out.println("控制电灯:");
        remote.setCommand(lightOn);
        remote.pressButton();
        remote.setCommand(lightOff);
        remote.pressButton();

        // 测试遥控器控制电视
        System.out.println("\n控制电视:");
        remote.setCommand(tvOn);
        remote.pressButton();
        remote.setCommand(tvOff);
        remote.pressButton();

        // 未设置命令
        System.out.println("\n未设置命令:");
        remote.setCommand(null);
        remote.pressButton();
    }
}

命令模式的优点

解耦:调用者(RemoteControl)与接收者(Light、TV)通过命令对象解耦。

扩展性:新增命令(如调节音量)只需实现 Command 接口,不影响现有代码。

支持撤销/重做:通过扩展命令接口(如添加 undo 方法)可以实现更多功能。

解释器模式 (Interpreter Pattern)  

定义:定义语法表示,为语言提供解释器。  

使用场景:用于解释计算机语言或编程语言中的语法,适用于解释某些规则、配置文件的解析、正则表达式的实现等场景。  

示例:假设我们要实现一个解释器,支持加法和减法操作,用户输入一个字符串表达式(如 "3 + 5"),解释器解析并计算结果。

java">// 1. 定义表达式接口
interface Expression {
    int interpret(); // 解释并计算结果
}

// 2. 实现终结符表达式(数字)
class NumberExpression implements Expression {
    private int number;

    public NumberExpression(int number) {
        this.number = number;
    }

    public NumberExpression(String number) {
        this.number = Integer.parseInt(number);
    }

    @Override
    public int interpret() {
        return number;
    }
}

// 3. 实现非终结符表达式(加法)
class AddExpression implements Expression {
    private Expression left;
    private Expression right;

    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 4. 实现非终结符表达式(减法)
class SubtractExpression implements Expression {
    private Expression left;
    private Expression right;

    public SubtractExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() - right.interpret();
    }
}

// 5. 定义解析器(将字符串转为表达式)
class ExpressionParser {
    public Expression parse(String expression) {
        String[] tokens = expression.split(" ");
        if (tokens.length != 3) {
            throw new IllegalArgumentException("表达式格式错误,应为:数字 运算符 数字");
        }

        Expression left = new NumberExpression(tokens[0]);
        Expression right = new NumberExpression(tokens[2]);
        String operator = tokens[1];

        switch (operator) {
            case "+":
                return new AddExpression(left, right);
            case "-":
                return new SubtractExpression(left, right);
            default:
                throw new IllegalArgumentException("不支持的运算符: " + operator);
        }
    }
}

// 6. 测试代码
public class InterpreterPatternDemo {
    public static void main(String[] args) {
        ExpressionParser parser = new ExpressionParser();

        // 测试加法
        String expression1 = "3 + 5";
        Expression exp1 = parser.parse(expression1);
        System.out.println(expression1 + " = " + exp1.interpret());

        // 测试减法
        String expression2 = "10 - 2";
        Expression exp2 = parser.parse(expression2);
        System.out.println(expression2 + " = " + exp2.interpret());

        // 测试复杂表达式(手动组合)
        Expression complexExp = new AddExpression(
            new NumberExpression(5),
            new SubtractExpression(new NumberExpression(10), new NumberExpression(3))
        );
        System.out.println("5 + (10 - 3) = " + complexExp.interpret());
    }
}

解释器模式的优点

扩展性:新增运算符(如乘法、除法)只需添加新的非终结符表达式类。

职责分离:语法规则和解释逻辑分开,易于维护。

适合简单语言:非常适合解析简单的自定义语言或规则。

局限性

复杂性:对于复杂的语法树,解析和管理表达式会变得繁琐。

性能:递归解释可能效率较低,不适合大规模计算。

迭代器模式 (Iterator Pattern)  

定义:提供顺序访问集合元素的方法。  

使用场景:用于访问一个集合对象的元素而不暴露其内部表示。适用于在遍历数据结构时不暴露其内部实现的场景,如数据库查询结果的遍历。

示例:假设有一个书架(集合),包含多本书,我们希望遍历这些书而不直接操作书架的内部数据结构。迭代器模式可以帮助我们实现这一点。

java">import java.util.ArrayList;
import java.util.List;

// 1. 定义迭代器接口
interface Iterator {
    boolean hasNext(); // 是否有下一个元素
    Object next();     // 获取下一个元素
}

// 2. 定义集合接口
interface BookCollection {
    Iterator createIterator(); // 创建迭代器
    void addBook(String book);
}

// 3. 实现具体迭代器
class BookIterator implements Iterator {
    private List<String> books;
    private int index = 0;

    public BookIterator(List<String> books) {
        this.books = books;
    }

    @Override
    public boolean hasNext() {
        return index < books.size();
    }

    @Override
    public Object next() {
        if (hasNext()) {
            return books.get(index++);
        }
        return null;
    }
}

// 4. 实现具体集合(书架)
class Bookshelf implements BookCollection {
    private List<String> books = new ArrayList<>();

    @Override
    public Iterator createIterator() {
        return new BookIterator(books);
    }

    @Override
    public void addBook(String book) {
        books.add(book);
    }
}

// 5. 测试代码
public class IteratorPatternDemo {
    public static void main(String[] args) {
        // 创建书架
        Bookshelf bookshelf = new Bookshelf();

        // 添加书籍
        bookshelf.addBook("《Java编程思想》");
        bookshelf.addBook("《设计模式》");
        bookshelf.addBook("《深入理解JVM》");

        // 创建迭代器并遍历
        Iterator iterator = bookshelf.createIterator();
        System.out.println("书架上的书籍:");
        while (iterator.hasNext()) {
            String book = (String) iterator.next();
            System.out.println(book);
        }
    }
}

迭代器模式的优点

封装性:隐藏集合的内部结构,客户端只需通过迭代器访问元素。

统一接口:为不同集合提供一致的遍历方式。

灵活性:可以轻松实现多种遍历方式(如反向迭代器)。

Java中的内置支持

Java的 java.util.Iterator 接口是迭代器模式的典型实现,许多集合类(如 ArrayList、HashSet)都支持。例如:

java">import java.util.ArrayList;
import java.util.Iterator;

public class JavaIteratorDemo {
    public static void main(String[] args) {
        ArrayList<String> books = new ArrayList<>();
        books.add("《Java编程思想》");
        books.add("《设计模式》");

        Iterator<String> iterator = books.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

中介者模式 (Mediator Pattern)  

定义:通过中介者协调对象间交互。  

使用场景:用于协调对象之间的交互,减少类之间的依赖。常用于多对象交互的场景,如聊天系统中的消息处理、UI控件之间的交互等。  

示例:假设有一个聊天室,用户可以发送消息,所有消息通过聊天室(中介者)进行转发,而用户之间不直接交互。中介者模式可以减少用户之间的耦合。

java">// 1. 定义中介者接口
interface ChatMediator {
    void sendMessage(String message, User user);
    void addUser(User user);
}

// 2. 定义同事类(用户)
abstract class User {
    protected ChatMediator mediator;
    protected String name;

    public User(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }

    public abstract void send(String message);
    public abstract void receive(String message);

    public String getName() {
        return name;
    }
}

// 3. 实现具体中介者(聊天室)
class ChatRoom implements ChatMediator {
    private List<User> users = new ArrayList<>();

    @Override
    public void addUser(User user) {
        users.add(user);
        System.out.println(user.getName() + " 已加入聊天室");
    }

    @Override
    public void sendMessage(String message, User sender) {
        for (User user : users) {
            if (user != sender) { // 不发送给自己
                user.receive(message);
            }
        }
    }
}

// 4. 实现具体用户
class ChatUser extends User {
    public ChatUser(ChatMediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    public void send(String message) {
        System.out.println(name + " 发送消息: " + message);
        mediator.sendMessage(message, this);
    }

    @Override
    public void receive(String message) {
        System.out.println(name + " 接收消息: " + message);
    }
}

// 5. 测试代码
public class MediatorPatternDemo {
    public static void main(String[] args) {
        // 创建聊天室(中介者)
        ChatMediator chatRoom = new ChatRoom();

        // 创建用户
        User alice = new ChatUser(chatRoom, "Alice");
        User bob = new ChatUser(chatRoom, "Bob");
        User charlie = new ChatUser(chatRoom, "Charlie");

        // 将用户加入聊天室
        chatRoom.addUser(alice);
        chatRoom.addUser(bob);
        chatRoom.addUser(charlie);

        // 用户发送消息
        alice.send("大家好!");
        bob.send("你好,Alice!");
        charlie.send("嗨,大家好!");
    }
}

中介者模式的优点

解耦:用户之间不直接交互,所有通信通过中介者完成,降低耦合度。

集中控制:交互逻辑集中在中介者中,便于管理和修改。

简化关系:将多对多的关系简化为多对一。

备忘录模式 (Memento Pattern)  

定义:保存和恢复对象状态。  

使用场景:用于保存和恢复对象的状态,常用于实现撤销操作的场景,比如文本编辑器中的撤销功能。

示例:假设有一个简单的文本编辑器,支持输入文本和撤销操作。备忘录模式可以用来保存编辑器的历史状态,以便在需要时恢复。

java">// 1. 定义备忘录类(保存状态)
class Memento {
    private String text;

    public Memento(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}

// 2. 定义原发器类(文本编辑器)
class TextEditor {
    private String text;

    public TextEditor() {
        this.text = "";
    }

    public void write(String newText) {
        this.text = newText;
        System.out.println("当前文本: " + text);
    }

    // 创建备忘录,保存当前状态
    public Memento save() {
        return new Memento(text);
    }

    // 从备忘录恢复状态
    public void restore(Memento memento) {
        this.text = memento.getText();
        System.out.println("恢复文本: " + text);
    }

    public String getText() {
        return text;
    }
}

// 3. 定义管理者类(负责存储备忘录)
class EditorHistory {
    private Stack<Memento> history = new Stack<>();

    public void saveState(Memento memento) {
        history.push(memento);
    }

    public Memento undo() {
        if (!history.isEmpty()) {
            return history.pop();
        }
        System.out.println("无历史记录可撤销");
        return null;
    }
}

// 4. 测试代码
public class MementoPatternDemo {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        EditorHistory history = new EditorHistory();

        // 编辑文本并保存状态
        editor.write("Hello");
        history.saveState(editor.save());

        editor.write("Hello, World!");
        history.saveState(editor.save());

        editor.write("Hello, World! How are you?");
        System.out.println("当前文本: " + editor.getText());

        // 撤销操作
        System.out.println("\n撤销一次:");
        Memento memento1 = history.undo();
        if (memento1 != null) editor.restore(memento1);

        System.out.println("\n撤销第二次:");
        Memento memento2 = history.undo();
        if (memento2 != null) editor.restore(memento2);

        System.out.println("\n再次撤销(无历史记录):");
        history.undo();
    }
}

备忘录模式的优点

状态隔离:备忘录封装了状态细节,外部无法直接修改。

支持撤销:通过保存历史状态实现撤销功能。

职责分离:原发器专注状态管理,管理者负责存储。

状态模式 (State Pattern)  

定义:根据状态改变对象行为。  

使用场景:用于对象的状态改变时,允许对象在其状态发生改变时改变其行为。常见于游戏角色的状态管理、工作流系统等。

示例:假设有一个订单系统,订单可能处于不同状态(如待支付、已支付、已发货、已完成)。每个状态下,订单的行为(如支付、发货、取消)会有所不同。状态模式可以将这些行为封装到状态类中。

java">// 1. 定义状态接口
interface OrderState {
    void pay(Order order);      // 支付
    void ship(Order order);     // 发货
    void cancel(Order order);   // 取消
}

// 2. 实现具体状态类
class PendingPaymentState implements OrderState {
    @Override
    public void pay(Order order) {
        System.out.println("支付成功,订单状态变更为已支付");
        order.setState(new PaidState());
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单未支付,无法发货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单已取消");
        order.setState(new CancelledState());
    }
}

class PaidState implements OrderState {
    @Override
    public void pay(Order order) {
        System.out.println("订单已支付,无需重复支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("发货成功,订单状态变更为已发货");
        order.setState(new ShippedState());
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单已支付,无法直接取消,请申请退款");
    }
}

class ShippedState implements OrderState {
    @Override
    public void pay(Order order) {
        System.out.println("订单已支付且已发货,无需重复支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单已发货,无需重复发货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单已发货,无法取消");
    }
}

class CancelledState implements OrderState {
    @Override
    public void pay(Order order) {
        System.out.println("订单已取消,无法支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单已取消,无法发货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单已处于取消状态");
    }
}

// 3. 定义上下文类(订单)
class Order {
    private OrderState state;

    public Order() {
        this.state = new PendingPaymentState(); // 初始状态为待支付
    }

    public void setState(OrderState state) {
        this.state = state;
    }

    // 委托给当前状态处理
    public void pay() {
        state.pay(this);
    }

    public void ship() {
        state.ship(this);
    }

    public void cancel() {
        state.cancel(this);
    }
}

// 4. 测试代码
public class StatePatternDemo {
    public static void main(String[] args) {
        Order order = new Order();

        System.out.println("初始状态(待支付):");
        order.pay();    // 支付
        System.out.println("\n支付后状态(已支付):");
        order.ship();   // 发货
        System.out.println("\n发货后状态(已发货):");
        order.cancel(); // 尝试取消

        System.out.println("\n新订单测试取消:");
        Order newOrder = new Order();
        newOrder.cancel(); // 取消待支付订单
    }
}

状态模式的优点

行为局部化:每个状态的行为封装在对应类中,逻辑清晰。

状态切换:通过状态对象动态改变行为,无需复杂的条件判断。

扩展性:新增状态(如“退货中”)只需添加新状态类。

策略模式 (Strategy Pattern)  

定义:定义算法家族,动态选择算法。  

使用场景:用于选择算法的场景,根据不同的情况选择不同的策略。比如支付系统中选择不同的支付方式(如支付宝、微信支付、信用卡支付等),或排序算法的选择。

示例:假设我们有一个支付系统,支持多种支付方式(如支付宝、微信支付和银行卡支付)。策略模式允许我们在运行时动态选择具体的支付方式。

java">// 1. 定义支付策略接口
interface PaymentStrategy {
    void pay(double amount);
}

// 2. 实现具体支付策略
class AlipayPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付 " + amount + " 元");
    }
}

class WechatPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付 " + amount + " 元");
    }
}

class BankCardPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用银行卡支付 " + amount + " 元");
    }
}

// 3. 创建上下文类
class PaymentContext {
    private PaymentStrategy paymentStrategy;

    // 设置策略
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    // 执行支付
    public void executePayment(double amount) {
        if (paymentStrategy == null) {
            System.out.println("请先选择支付方式!");
            return;
        }
        paymentStrategy.pay(amount);
    }
}

// 4. 测试代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        PaymentContext context = new PaymentContext();

        // 使用支付宝支付
        context.setPaymentStrategy(new AlipayPayment());
        context.executePayment(100.50);

        // 使用微信支付
        context.setPaymentStrategy(new WechatPayment());
        context.executePayment(200.75);

        // 使用银行卡支付
        context.setPaymentStrategy(new BankCardPayment());
        context.executePayment(150.00);

        // 未设置策略的情况
        context.setPaymentStrategy(null);
        context.executePayment(50.00);
    }
}

策略模式的优点

灵活性:运行时可以动态切换策略(如从支付宝切换到微信)。

解耦:支付逻辑与上下文分离,客户端只需关心接口,不关心具体实现。

易扩展:新增支付方式(如PayPal)只需实现 PaymentStrategy 接口并添加相应类。

模板方法模式 (Template Method Pattern)  

定义:定义算法骨架,子类实现具体步骤。  

使用场景:用于在子类中实现某些步骤,而将流程的控制权交给父类。比如在游戏中有一些固定流程,具体的游戏逻辑可以由子类来实现(如初始化、开始、结束等步骤),但是流程是统一的。

示例:假设我们要制作不同类型的饮料(如咖啡和茶),每种饮料的制作流程基本相同(烧水、冲泡、添加调料、装杯),但具体步骤有所不同。模板方法模式可以用来定义通用流程。

java">// 1. 定义抽象类,包含模板方法
abstract class BeverageMaker {
    // 模板方法,定义制作饮料的固定流程
    public final void makeBeverage() {
        boilWater();
        brew();
        addCondiments();
        pourInCup();
    }

    // 通用步骤,固定实现
    private void boilWater() {
        System.out.println("烧开水");
    }

    private void pourInCup() {
        System.out.println("将饮料倒入杯子");
    }

    // 抽象步骤,由子类实现
    abstract void brew();         // 冲泡
    abstract void addCondiments(); // 添加调料
}

// 2. 实现具体子类:咖啡
class CoffeeMaker extends BeverageMaker {
    @Override
    void brew() {
        System.out.println("用热水冲泡咖啡粉");
    }

    @Override
    void addCondiments() {
        System.out.println("添加糖和奶");
    }
}

// 3. 实现具体子类:茶
class TeaMaker extends BeverageMaker {
    @Override
    void brew() {
        System.out.println("用热水浸泡茶叶");
    }

    @Override
    void addCondiments() {
        System.out.println("添加柠檬片");
    }
}

// 4. 测试代码
public class TemplateMethodDemo {
    public static void main(String[] args) {
        System.out.println("制作咖啡:");
        BeverageMaker coffee = new CoffeeMaker();
        coffee.makeBeverage();

        System.out.println("\n制作茶:");
        BeverageMaker tea = new TeaMaker();
        tea.makeBeverage();
    }
}

模板方法模式的优点

固定流程:确保所有子类遵循相同的步骤顺序。

代码复用:通用逻辑在父类中实现,避免重复。

灵活性:子类可以定制特定步骤,满足不同需求。

访问者模式 (Visitor Pattern)  

定义:将操作与对象结构分离,动态添加新操作。  

使用场景:用于对不同类型的对象进行操作而不修改这些对象的类结构。比如在编译器中,对不同的语法节点进行处理,或在文件系统中对不同的文件类型(文本文件、图片文件等)执行不同操作。

示例:假设我们有一个文件系统,包含文件和文件夹两种元素。我们希望对这些元素执行不同的操作(如计算大小和打印名称),访问者模式可以让我们动态添加这些操作。

java">// 1. 定义访问者接口
interface FileSystemVisitor {
    void visit(File file);
    void visit(Folder folder);
}

// 2. 定义元素接口
interface FileSystemElement {
    void accept(FileSystemVisitor visitor);
}

// 3. 实现具体元素
class File implements FileSystemElement {
    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String getName() { return name; }
    public int getSize() { return size; }

    @Override
    public void accept(FileSystemVisitor visitor) {
        visitor.visit(this);
    }
}

class Folder implements FileSystemElement {
    private String name;
    private List<FileSystemElement> elements = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    public void addElement(FileSystemElement element) {
        elements.add(element);
    }

    public List<FileSystemElement> getElements() { return elements; }
    public String getName() { return name; }

    @Override
    public void accept(FileSystemVisitor visitor) {
        visitor.visit(this);
    }
}

// 4. 实现具体访问者
class SizeCalculatorVisitor implements FileSystemVisitor {
    private int totalSize = 0;

    @Override
    public void visit(File file) {
        totalSize += file.getSize();
    }

    @Override
    public void visit(Folder folder) {
        for (FileSystemElement element : folder.getElements()) {
            element.accept(this); // 递归访问子元素
        }
    }

    public int getTotalSize() { return totalSize; }
}

class NamePrinterVisitor implements FileSystemVisitor {
    @Override
    public void visit(File file) {
        System.out.println("文件: " + file.getName());
    }

    @Override
    public void visit(Folder folder) {
        System.out.println("文件夹: " + folder.getName());
        for (FileSystemElement element : folder.getElements()) {
            element.accept(this); // 递归访问子元素
        }
    }
}

// 5. 测试代码
public class VisitorPatternDemo {
    public static void main(String[] args) {
        // 构建文件系统结构
        File file1 = new File("文档1.txt", 100);
        File file2 = new File("图片1.jpg", 200);
        Folder folder1 = new Folder("我的文档");
        folder1.addElement(file1);
        folder1.addElement(file2);

        File file3 = new File("视频1.mp4", 500);
        Folder rootFolder = new Folder("根目录");
        rootFolder.addElement(folder1);
        rootFolder.addElement(file3);

        // 使用SizeCalculatorVisitor计算总大小
        SizeCalculatorVisitor sizeVisitor = new SizeCalculatorVisitor();
        rootFolder.accept(sizeVisitor);
        System.out.println("文件系统总大小: " + sizeVisitor.getTotalSize() + " 字节");

        System.out.println("\n打印文件系统名称:");
        // 使用NamePrinterVisitor打印名称
        NamePrinterVisitor nameVisitor = new NamePrinterVisitor();
        rootFolder.accept(nameVisitor);
    }
}

访问者模式的优点

扩展性:新增操作只需添加新的访问者类,无需修改元素类。

分离关注点:元素类专注于数据结构,操作逻辑交给访问者。

适合复杂结构:特别适用于树形或复合对象结构。

局限性与注意事项

增加新元素困难:如果需要添加新的元素类型(如 Link),必须修改 FileSystemVisitor 接口及其所有实现。

访问者需知道元素细节:访问者需要访问元素的内部属性(如 size 和 name),可能破坏封装。

观察者模式 (Observer Pattern)  

定义:观察者模式是一种行为型设计模式,允许一个对象(被观察者)在状态发生变化时自动通知所有依赖于它的对象(观察者)。这种模式也称为“发布-订阅”模式。它解耦了事件的发布者和消费者。  

使用场景

  • 一对多依赖关系:当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知。比如,新闻发布系统、股票市场、游戏中的事件通知系统。
  • 松耦合设计:观察者模式使得观察者和被观察者之间保持松耦合,彼此并不直接依赖。一个被观察者可以有多个观察者,观察者也可以自由注册和注销。

  

示例:假设有一个天气站(主题),负责发布天气数据(如温度和湿度),多个显示设备(观察者)需要根据天气变化更新显示内容。

java">import java.util.ArrayList;
import java.util.List;

// 1. 定义观察者接口
interface Observer {
    void update(float temperature, float humidity); // 更新方法
}

// 2. 定义主题接口
interface Subject {
    void registerObserver(Observer observer); // 注册观察者
    void removeObserver(Observer observer);   // 移除观察者
    void notifyObservers();                  // 通知所有观察者
}

// 3. 实现主题(天气站)
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
    private float humidity;

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity);
        }
    }

    // 设置天气数据并通知观察者
    public void setMeasurements(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        notifyObservers();
    }
}

// 4. 实现具体观察者
class TemperatureDisplay implements Observer {
    private String name;

    public TemperatureDisplay(String name) {
        this.name = name;
    }

    @Override
    public void update(float temperature, float humidity) {
        System.out.println(name + " 显示: 温度 = " + temperature + "°C");
    }
}

class HumidityDisplay implements Observer {
    private String name;

    public HumidityDisplay(String name) {
        this.name = name;
    }

    @Override
    public void update(float temperature, float humidity) {
        System.out.println(name + " 显示: 湿度 = " + humidity + "%");
    }
}

// 5. 测试代码
public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 创建主题
        WeatherStation weatherStation = new WeatherStation();

        // 创建观察者
        TemperatureDisplay tempDisplay = new TemperatureDisplay("客厅显示器");
        HumidityDisplay humidDisplay = new HumidityDisplay("卧室显示器");

        // 注册观察者
        weatherStation.registerObserver(tempDisplay);
        weatherStation.registerObserver(humidDisplay);

        // 模拟天气变化
        System.out.println("第一次天气更新:");
        weatherStation.setMeasurements(25.5f, 65.0f);

        System.out.println("\n第二次天气更新:");
        weatherStation.setMeasurements(28.0f, 70.0f);

        // 移除一个观察者
        weatherStation.removeObserver(tempDisplay);
        System.out.println("\n移除客厅显示器后,第三次天气更新:");
        weatherStation.setMeasurements(30.0f, 60.0f);
    }
}

观察者模式的优点

松耦合:主题和观察者之间通过接口交互,互不依赖具体实现。

动态性:可以在运行时添加或移除观察者。

广播通信:主题状态变化时自动通知所有观察者。

Java中的内置支持

Java提供了内置的观察者模式支持(java.util.Observable 和 java.util.Observer),但在新代码中更推荐使用自定义实现或事件监听机制。以下是使用Java内置类的简例:

java">import java.util.Observable;
import java.util.Observer;

class WeatherData extends Observable {
    private float temperature;

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        setChanged();
        notifyObservers(temperature);
    }
}

class TempDisplay implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("温度更新: " + arg + "°C");
    }
}

public class BuiltInObserverDemo {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        TempDisplay display = new TempDisplay();
        weatherData.addObserver(display);
        weatherData.setTemperature(25.0f);
    }
}

使用场景:

  • 事件通知系统:比如在用户界面中,当某个按钮点击时,多个组件(观察者)可能需要做出反应。例如,点击“保存”按钮时,不仅是保存数据,还可能触发日志记录、用户界面更新等操作。
  • 股票行情更新:证券市场中的股票价格变化,多个投资者(观察者)需要根据新的价格做出反应。
  • 天气监测系统:天气数据发生变化时,多个显示屏(观察者)需要根据新的数据显示不同的天气信息。

总结

创建型:解决对象创建问题(5种)。

结构型:优化类和对象结构(7种)。

行为型:处理对象间交互和职责(11种)。

每种模式都有其独特的应用场景,实际开发中可以根据需求灵活组合使用。

五、使用场景

场景一

场景一:有一个java方法,我希望不同场景情况下都调用同一个方法,会用到哪些设计模式

在Java中,如果你希望在不同场景下都调用同一个方法,同时保持代码的灵活性和可维护性,可以考虑使用一些常见的设计模式。以下是几种可能适用的设计模式,以及它们如何帮助你实现目标:

策略模式 (Strategy Pattern)  

使用场景:如果你需要在不同情况下使用同一个方法,但具体的实现逻辑会因场景而异,策略模式是一个很好的选择。  

实现方式:定义一个接口,包含这个方法签名,然后为不同场景编写不同的实现类。调用时通过上下文类动态选择具体策略。  

优点:可以在运行时灵活切换实现,代码解耦,便于扩展。  

例子

java">interface ProcessStrategy {
    void execute();
}

class StrategyA implements ProcessStrategy {
    public void execute() { System.out.println("场景A逻辑"); }
}

class StrategyB implements ProcessStrategy {
    public void execute() { System.out.println("场景B逻辑"); }
}

class Context {
    private ProcessStrategy strategy;
    public void setStrategy(ProcessStrategy strategy) { this.strategy = strategy; }
    public void process() { strategy.execute(); }
}

模板方法模式 (Template Method Pattern)  

使用场景:如果你的方法有一个固定的流程,但在某些步骤上会有不同场景的差异,模板方法模式非常合适。  

实现方式:在一个抽象类中定义方法的骨架(模板),将可变部分留给子类实现。所有场景都调用这个模板方法。  

优点:保证方法的整体结构一致,同时允许子类定制部分行为。  

例子

java">abstract class AbstractProcess {
    public void process() {
        step1();
        step2();
    }
    abstract void step1();
    abstract void step2();
}

class ProcessA extends AbstractProcess {
    void step1() { System.out.println("A的步骤1"); }
    void step2() { System.out.println("A的步骤2"); }
}

工厂模式 (Factory Pattern)  

使用场景:如果不同场景需要创建不同的对象来调用同一个方法,工厂模式可以帮你管理对象的创建。  

实现方式:通过工厂类根据场景参数创建对应的对象,然后调用统一的方法。  

优点:隐藏对象的创建细节,调用方只需关心方法本身。  

例子:

java">interface Product {
    void use();
}

class ProductA implements Product {
    public void use() { System.out.println("使用A"); }
}

class ProductFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) return new ProductA();
        return null;
    }
}

命令模式 (Command Pattern)  

使用场景:如果你的方法调用需要解耦调用者和执行者,或者需要支持撤销、重做等操作,命令模式是一个选择。  

实现方式:将方法封装成命令对象,调用方通过命令接口执行。  

优点:灵活性高,可以动态调整调用逻辑。  

例子:

java">interface Command {
    void execute();
}

class ConcreteCommand implements Command {
    public void execute() { System.out.println("执行命令"); }
}

class Invoker {
    private Command command;
    public void setCommand(Command command) { this.command = command; }
    public void call() { command.execute(); }
}

适配器模式 (Adapter Pattern)  

使用场景:如果不同场景下已有不同的方法或接口,但你想统一调用同一个方法,可以用适配器模式。  

实现方式:通过适配器将不同接口转换为统一的接口。  

优点:复用现有代码,统一调用方式。  

例子:

java">interface Target {
    void request();
}

class Adaptee {
    public void specificRequest() { System.out.println("特殊请求"); }
}

class Adapter implements Target {
    private Adaptee adaptee = new Adaptee();
    public void request() { adaptee.specificRequest(); }
}

如何选择?

如果逻辑差异大,用策略模式。

如果流程固定但细节不同,用模板方法模式。

如果需要动态创建对象,用工厂模式。

如果需要解耦或支持额外功能(如撤销),用命令模式。

如果整合已有不同接口,用适配器模式。


http://www.niftyadmin.cn/n/5868317.html

相关文章

浏览器深度解析:打造极速、安全、个性化的上网新体验

在数字化时代,浏览器作为我们获取信息、娱乐休闲的重要工具,其性能与功能直接影响着我们的上网体验。今天,我将为大家介绍一款备受好评的浏览器——Yandex浏览器,并深入解析其独特功能与优势,帮助大家更好地了解并选择这款上网神器。 一、知名公司背书,开源项目融合 Yan…

@KafkaListener和KafkaTemplate自动装配原理分析

依赖项和配置信息参见另一篇博文KafkaListener的配置使用&#xff0c;这里主要借助源码分析KafkaListener和KafkaTemplate自动装配原理。 1、KafkaAutoConfiguration 源码分析 KafkaAutoConfiguration类自动装配生成了生产者客户端KafkaTemplate的bean和消费者基础ConsumerFa…

03、Hadoop3.x从入门到放弃,第三章:Windows测试环境搭建

Hadoop3.x从入门到放弃&#xff0c;第三章&#xff1a;Windows测试环境搭建 一、Windows测试环境搭建 预先安装好JDK环境&#xff0c;这里不在赘述。 1、下载Hadoop相关文件 Hadoop各版本安装包&#xff1a;https://archive.apache.org/dist/hadoop/common/ 【我选择的是ha…

上证50期权代码是什么?上证50股指期权数据从哪里可以找到?

说起期权代码&#xff0c;其实期权代码是期权合约的唯一标识&#xff0c;通过代码可以准确地识别不同的期权合约&#xff0c;所以在期权交易中&#xff0c;了解期权代码是至关重要的一环。 上证50期权代码结构 上证50ETF期权代码由17位字符组成&#xff0c;例如“10002500C240…

设计模式 简单汇总

设计模式是软件工程中广泛使用的一套解决方案&#xff0c;用于解决常见问题并提高代码的质量。它们分为创建型、结构型和行为型三类&#xff0c;共23种模式。以下是各类别及其常见模式的详细说明&#xff1a; 目录 创建型模式结构型模式行为型模式 创建型模式 这些模式关注对象…

DeepSeek点燃AI大模型战火:编程语言争霸,谁将问鼎“终极武器”王座?

DeepSeek点燃AI大模型战火&#xff1a;编程语言争霸&#xff0c;谁将问鼎“终极武器”王座&#xff1f; 一、DeepSeek&#xff1a;AI大模型竞赛的“导火索” 2023年&#xff0c;中国AI公司深度求索&#xff08;DeepSeek&#xff09;发布DeepSeek-R1大模型&#xff0c;凭借其超…

第七章:消息管理模块

目录 第一节&#xff1a;代码实现 1-1.消息持久化管理思想 1-2.MessageMapper类 1-3.QueueMessage类 1-4.MessageManager 第二节&#xff1a;单元测试 下期预告&#xff1a; 消息管理模块在mqserver下实现。 第一节&#xff1a;代码实现 消息管理首先需要消息类&#xff0c…

交换机与路由器连接方式

交换机和路由器连接的三种主要方式如下&#xff1a; 一、直连连接 这是最简单直接的连接方式。通过一根网线将交换机的一个端口与路由器的一个LAN端口相连。这种连接方式适用于小型网络&#xff0c;其中交换机负责局域网内部的数据交换&#xff0c;而路由器则负责将内部网络连接…