Java23种设计模式详解

Java23种设计模式详解

Java语言中常用的设计模式包括23种经典设计模式,它们分为三大类:创建型、结构型和行为型。

  1. 创建型模式(Creational Patterns):这类模式关注对象的创建过程,将对象的创建和使用分离,以提高系统的灵活性和可扩展性。包括以下几种:

    • 工厂方法模式(Factory Method)
    • 抽象工厂模式(Abstract Factory)
    • 单例模式(Singleton)
    • 建造者模式(Builder)
    • 原型模式(Prototype)
  2. 结构型模式(Structural Patterns):这类模式关注如何组合类和对象以形成更大的结构,主要用于处理类和对象的组合。包括以下几种:

    • 适配器模式(Adapter)
    • 桥接模式(Bridge)
    • 组合模式(Composite)
    • 装饰器模式(Decorator)
    • 外观模式(Facade)
    • 享元模式(Flyweight)
    • 代理模式(Proxy)
  3. 行为型模式(Behavioral Patterns):这类模式关注对象之间的通信,主要用于描述程序在运行时复杂的控制流程。包括以下几种:

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

创建型模式

工厂方法(Factory Method)

提供了一个接口用于创建对象,但允许子类决定实例化哪种类。这种模式把实例化推迟到了子类中进行,增强了程序的灵活性和扩展性,尤其适用于多态性产品的场景,遵循了开闭原则(Open/Closed Principle),即对扩展开放,对修改关闭。

以下是一个简化的Java工厂方法模式的示例:

// 抽象产品角色
interface Product {
    void doSomething();
}

// 具体产品角色A
class ConcreteProductA implements Product {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductA is doing something...");
    }
}

// 具体产品角色B
class ConcreteProductB implements Product {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductB is doing something...");
    }
}

// 抽象工厂角色
abstract class AbstractFactory {
    abstract Product createProduct();
}

// 具体工厂角色A
class ConcreteFactoryA extends AbstractFactory {
    @Override
    Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂角色B
class ConcreteFactoryB extends AbstractFactory {
    @Override
    Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        // 创建不同的工厂
        AbstractFactory factoryA = new ConcreteFactoryA();
        AbstractFactory factoryB = new ConcreteFactoryB();

        // 通过工厂创建产品
        Product productA = factoryA.createProduct();
        Product productB = factoryB.createProduct();

        // 使用产品
        productA.doSomething();
        productB.doSomething();
    }
}

在这个示例中:

  • Product 是抽象产品角色,定义了产品的公共接口。
  • ConcreteProductAConcreteProductB 是具体产品角色,实现了产品接口的具体功能。
  • AbstractFactory 是抽象工厂角色,声明了一个创建产品对象的接口方法 createProduct()
  • ConcreteFactoryAConcreteFactoryB 是具体工厂角色,分别实现了 createProduct() 方法,返回不同类型的产品实例。
  • 在客户端代码中,根据需求创建不同的工厂,然后通过工厂来获取所需的产品实例,这样就不需要知道如何创建具体产品的细节,只需关心产品接口即可。如果要新增一种产品,只需新增一个产品类和对应的工厂类,而无需修改已有的代码。

抽象工厂模式(Abstract Factory Pattern)

提供了一种方式来封装一组具有相关联的或相互依赖的对象的创建。一个抽象工厂定义了一个接口,用于创建相关或依赖对象的家族,而实际的具体工厂则负责生成具体的对象。

下面是一个使用Java实现的抽象工厂模式的简单示例:

假设我们有一个图形应用程序,需要绘制不同类型的形状(如圆形、矩形等)和颜色填充策略(如红色、蓝色等)。每种形状都可以有不同的颜色填充,这就构成了两个相关的对象家族。

// 抽象产品接口:形状
interface Shape {
    void draw();
}

// 具体产品:圆形
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

// 具体产品:矩形
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
}

// 抽象产品接口:颜色
interface Color {
    String fill();
}

// 具体产品:红色
class Red implements Color {
    @Override
    public String fill() {
        return "Filled with red color";
    }
}

// 具体产品:蓝色
class Blue implements Color {
    @Override
    public String fill() {
        return "Filled with blue color";
    }
}

// 抽象工厂接口
interface Factory {
    Shape getShape();
    Color getColor();
}

// 具体工厂:红色图形工厂
class RedShapeFactory implements Factory {
    @Override
    public Shape getShape() {
        return new Circle(); // 或者 new Rectangle()
    }

    @Override
    public Color getColor() {
        return new Red();
    }
}

// 具体工厂:蓝色图形工厂
class BlueShapeFactory implements Factory {
    @Override
    public Shape getShape() {
        return new Rectangle(); // 或者 new Circle()
    }

    @Override
    public Color getColor() {
        return new Blue();
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        Factory redFactory = new RedShapeFactory();
        Shape redShape = redFactory.getShape();
        Color redColor = redFactory.getColor();
        redShape.draw();
        System.out.println(redColor.fill());

        Factory blueFactory = new BlueShapeFactory();
        Shape blueShape = blueFactory.getShape();
        Color blueColor = blueFactory.getColor();
        blueShape.draw();
        System.out.println(blueColor.fill());
    }
}

在这个示例中:

  • ShapeColor 是抽象产品接口。
  • Circle, Rectangle, Red, Blue 是具体的产品类,实现了对应的产品接口。
  • Factory 是抽象工厂接口,定义了创建形状和颜色的方法。
  • RedShapeFactoryBlueShapeFactory 是具体工厂类,实现了 Factory 接口,创建并返回特定的颜色和形状组合。
  • 客户端可以根据需求选择创建哪种具体工厂,然后通过该工厂获取形状和颜色对象,而无需关注具体的创建过程。

单例模式(Singleton Pattern)

目的是保证一个类仅有一个实例,并提供一个全局访问点。这种模式常用来控制共享资源的访问,例如数据库连接、线程池、缓存等。

以下是使用 Java 实现单例模式的一种常见方法——“懒汉式”单例(线程安全版本,采用双重检查锁定):

public class Singleton {
    // 创建 Singleton 类的一个对象
    private volatile static Singleton singleton;

    // 让构造函数为 private,这样该类就不会被实例化
    private Singleton() {}

    // 获取唯一可用的对象
    public static Singleton getInstance() {
        if (singleton == null) { 
            synchronized (Singleton.class) {
                // 只有当 singleton 为 null 时才进入同步代码块
                if (singleton == null) {
                    // 这里才真正创建对象
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

    // 示例方法
    public void someMethod() {
        System.out.println("Singleton method called.");
    }
}

// 客户端代码调用
public class Client {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        instance1.someMethod();

        Singleton instance2 = Singleton.getInstance();
        // 因为是单例,所以 instance1 和 instance2 指向的是同一对象
    }
}

在上述代码中:

  • Singleton 类包含一个私有的静态变量 singleton 作为单例对象。
  • 构造函数为 private 确保外部无法直接实例化。
  • getInstance() 方法负责创建单例对象,第一次调用时会初始化单例,后续调用则直接返回已存在的单例。
  • 使用双重检查锁定 (double-checked locking) 的机制来确保多线程环境下的线程安全性,同时兼顾性能,避免每次调用都进行加锁操作。

建造者模式(Builder Pattern)

分步骤创建复杂对象,而且可以通过设置不同的可选参数,“建造”出不同表现形式(属性)的对象。这种模式主要是为了将构造过程与表示分离,使得相同的构造过程可以创建不同的表示。

以下是一个使用Java实现的建造者模式的简单示例,假设我们要构建一个复杂的汉堡订单:

// 抽象汉堡类
public abstract class Burger {
    protected String bread;
    protected String meat;
    protected boolean cheese;
    protected boolean lettuce;
    protected boolean tomato;

    public String getBread() {
        return bread;
    }

    public String getMeat() {
        return meat;
    }

    public boolean hasCheese() {
        return cheese;
    }

    public boolean hasLettuce() {
        return lettuce;
    }

    public boolean hasTomato() {
        return tomato;
    }

    // 抽象建造方法
    public abstract void prepare();
}

// 具体汉堡类
public class CheeseBurger extends Burger {
    public CheeseBurger(BurgerBuilder builder) {
        this.bread = builder.getBread();
        this.meat = builder.getMeat();
        this.cheese = builder.isCheese();
        this.lettuce = builder.isLettuce();
        this.tomato = builder.isTomato();
        this.prepare();
    }

    @Override
    public void prepare() {
        System.out.println("Preparing a burger with: ");
        System.out.println("- Bread: " + getBread());
        System.out.println("- Meat: " + getMeat());
        System.out.println("- Cheese: " + hasCheese());
        System.out.println("- Lettuce: " + hasLettuce());
        System.out.println("- Tomato: " + hasTomato());
    }
}

// 汉堡建造者接口
public interface BurgerBuilder {
    void setBread(String bread);
    void setMeat(String meat);
    void addCheese();
    void addLettuce();
    void addTomato();
    Burger build();
}

// 具体的汉堡建造者
public class BurgerBuilderImpl implements BurgerBuilder {
    private String bread;
    private String meat;
    private boolean cheese = false;
    private boolean lettuce = false;
    private boolean tomato = false;

    @Override
    public void setBread(String bread) {
        this.bread = bread;
    }

    @Override
    public void setMeat(String meat) {
        this.meat = meat;
    }

    @Override
    public void addCheese() {
        this.cheese = true;
    }

    @Override
    public void addLettuce() {
        this.lettuce = true;
    }

    @Override
    public void addTomato() {
        this.tomato = true;
    }

    @Override
    public Burger build() {
        return new CheeseBurger(this);
    }

    // 获取构建汉堡的各项原料
    String getBread() {
        return bread;
    }

    String getMeat() {
        return meat;
    }

    boolean isCheese() {
        return cheese;
    }

    boolean isLettuce() {
        return lettuce;
    }

    boolean isTomato() {
        return tomato;
    }
}

// 客户端代码调用
public class Client {
    public static void main(String[] args) {
        BurgerBuilder burgerBuilder = new BurgerBuilderImpl();
        burgerBuilder.setBread("Whole Wheat");
        burgerBuilder.setMeat("Beef Patty");
        burgerBuilder.addCheese();
        burgerBuilder.addLettuce();
        burgerBuilder.addTomato();

        Burger burger = burgerBuilder.build();
        burger.prepare();
    }
}

在这个示例中:

  • Burger 是抽象产品类,定义了产品的基本属性和构造方法。
  • CheeseBurger 是具体产品类,继承自 Burger 并实现其构造过程。
  • BurgerBuilder 是抽象建造者接口,定义了建造汉堡的所有步骤。
  • BurgerBuilderImpl 是具体建造者类,实现了 BurgerBuilder 接口,提供了逐步构造汉堡的方法。
  • 客户端通过调用建造者的方法,按需定制汉堡,最后通过 build() 方法获得最终的汉堡对象。

原型模式(Prototype Pattern)

用于复制已有对象,而不是新建对象。这种模式在系统的性能要求较高的场合特别有用,因为它可以避免重复初始化过程或者节省内存占用。

以下是一个使用Java实现的原型模式的简单示例,假设我们有一个员工类(Employee),并且我们需要快速克隆出一份一模一样的员工信息:

import java.io.Serializable;

public class Employee implements Cloneable, Serializable {
    private String name;
    private int age;
    private String department;

    public Employee(String name, int age, String department) {
        this.name = name;
        this.age = age;
        this.department = department;
    }

    // Getter and Setter methods

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    // 重写 clone 方法以实现深拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Employee clonedEmployee = (Employee) super.clone();
        return clonedEmployee;
    }

    // 客户端代码调用
    public static void main(String[] args) {
        try {
            // 创建原始员工对象
            Employee originalEmployee = new Employee("John Doe", 30, "HR");

            // 使用原型模式克隆员工对象
            Employee clonedEmployee = (Employee) originalEmployee.clone();

            // 修改克隆后的员工信息
            clonedEmployee.setName("Jane Doe");
            clonedEmployee.setAge(35);

            System.out.println("Original Employee: " + originalEmployee.getName() + ", " + originalEmployee.getAge());
            System.out.println("Cloned Employee: " + clonedEmployee.getName() + ", " + clonedEmployee.getAge());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中:

  • Employee 类实现了 Cloneable 接口,表明它可以被复制。
  • 重写了 clone() 方法以实现深拷贝(注意:此处的 clone() 实现了浅拷贝,若类中有引用类型成员变量,应手动实现深拷贝)。
  • 在客户端代码中,我们首先创建了一个原始的员工对象,然后通过调用 clone() 方法创建了一个克隆的员工对象。修改克隆对象的属性不会影响原始对象的属性值,这体现了原型模式的特点。

结构型模式

适配器模式(Adapter Pattern)

将一个接口转换为客户期望的另一个接口,主要目的是使原本因接口不兼容而不能在一起工作的类可以协同工作。

以下是一个使用Java实现的适配器模式的简单示例,假设我们有一个老式的音频播放器接口,但我们的系统只支持新的媒体播放器接口,这时我们可以创建一个适配器来衔接两者:

// 老式音频播放器接口
public interface OldMediaPlayer {
    void playCassette(String cassetteTitle);
}

// 新式媒体播放器接口
public interface NewMediaPlayer {
    void play(String format, String title);
}

// 老式音频播放器实现
public class OldAudioPlayer implements OldMediaPlayer {
    @Override
    public void playCassette(String cassetteTitle) {
        System.out.println("Playing cassette: " + cassetteTitle);
    }
}

// 适配器类,将老式音频播放器接口转换为新式媒体播放器接口
public class CassetteMediaPlayerAdapter implements NewMediaPlayer {
    private OldMediaPlayer oldPlayer;

    public CassetteMediaPlayerAdapter(OldMediaPlayer oldPlayer) {
        this.oldPlayer = oldPlayer;
    }

    @Override
    public void play(String format, String title) {
        // 检查格式是否为磁带
        if ("cassette".equalsIgnoreCase(format)) {
            oldPlayer.playCassette(title);
        } else {
            System.out.println("Unsupported media format!");
        }
    }
}

// 客户端代码调用
public class Client {
    public static void main(String[] args) {
        // 创建一个老式音频播放器对象
        OldMediaPlayer oldPlayer = new OldAudioPlayer();

        // 创建适配器对象,并传入老式播放器对象
        NewMediaPlayer adapter = new CassetteMediaPlayerAdapter(oldPlayer);

        // 使用适配器播放磁带
        adapter.play("cassette", "Classic Rock Mixtape");
    }
}

在上述代码中:

  • OldMediaPlayer 是老式的音频播放器接口,只能播放磁带。
  • NewMediaPlayer 是新式的媒体播放器接口,支持多种媒体格式。
  • OldAudioPlayerOldMediaPlayer 接口的实现类。
  • CassetteMediaPlayerAdapter 是适配器类,它实现了 NewMediaPlayer 接口,并持有一个 OldMediaPlayer 对象。在 play() 方法中,适配器将新接口的参数转换为老接口能够接受的形式,并调用老式播放器的 playCassette() 方法。
  • 客户端代码通过创建适配器对象,间接实现了使用新接口调用老式音频播放器的功能。

桥接模式(Bridge Pattern)

将抽象部分与它的实现部分分离,使它们都可以独立地变化。这种模式有助于降低类之间的耦合度,让类可以独立地改变实现和抽象部分。

以下是一个使用Java实现的桥接模式的简单示例,假设我们有一个图形界面库,其中图形对象可以有不同的形状(如圆形、矩形)和不同的颜色填充策略(如实色填充、渐变填充):

// 抽象接口:形状
public abstract class Shape {
    protected DrawAPI drawAPI;

    public Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }

    public abstract void draw();
}

// 具体实现:圆形
public class Circle extends Shape {
    private int x, y, radius;

    public Circle(DrawAPI drawAPI, int x, int y, int radius) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawAPI.drawCircle(x, y, radius);
    }
}

// 具体实现:矩形
public class Rectangle extends Shape {
    private int x, y, width, height;

    public Rectangle(DrawAPI drawAPI, int x, int y, int width, int height) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    @Override
    public void draw() {
        drawAPI.drawRect(x, y, width, height);
    }
}

// 抽象接口:绘制API
public interface DrawAPI {
    void drawCircle(int x, int y, int radius);
    void drawRect(int x, int y, int width, int height);
}

// 具体实现:实色填充API
public class SolidDrawAPI implements DrawAPI {
    @Override
    public void drawCircle(int x, int y, int radius) {
        System.out.println("Drawing solid circle at (" + x + "," + y + ") radius=" + radius);
    }

    @Override
    public void drawRect(int x, int y, int width, int height) {
        System.out.println("Drawing solid rectangle at (" + x + "," + y + ") dimensions=" + width + "x" + height);
    }
}

// 具体实现:渐变填充API
public class GradientDrawAPI implements DrawAPI {
    @Override
    public void drawCircle(int x, int y, int radius) {
        System.out.println("Drawing gradient circle at (" + x + "," + y + ") radius=" + radius);
    }

    @Override
    public void drawRect(int x, int y, int width, int height) {
        System.out.println("Drawing gradient rectangle at (" + x + "," + y + ") dimensions=" + width + "x" + height);
    }
}

// 客户端代码调用
public class BridgePatternDemo {
    public static void main(String[] args) {
        Shape shape1 = new Circle(new SolidDrawAPI(), 10, 20, 5);
        Shape shape2 = new Rectangle(new GradientDrawAPI(), 10, 40, 10, 20);

        shape1.draw();
        shape2.draw();
    }
}

在这个示例中:

  • Shape 是抽象部分,定义了图形的基本操作(draw() 方法)。
  • CircleRectangleShape 的具体实现。
  • DrawAPI 是实现部分的抽象接口,定义了绘制图形的方法。
  • SolidDrawAPIGradientDrawAPIDrawAPI 的具体实现,提供了不同的绘制风格。
  • 客户端代码可以选择不同的形状和绘制风格,组合成各种图形效果,而无需更改任何类的内部结构。这就是桥接模式的核心思想:将抽象部分与实现部分解耦,使得它们可以独立地变化和扩展。

组合模式(Composite Pattern)

允许将对象组合成树形结构来表现“整体-部分”的层次结构,并且用户可以一致地处理单个对象和对象组合。在组合模式中,组合对象和叶子对象都有相同的接口,这样客户端就可以统一地对待他们。

下面是一个使用Java实现的组合模式示例,模拟了一个文件系统结构,其中文件夹(Folder)可以包含子文件夹和文件(File):

// 抽象组件
public abstract class FileSystemComponent {
    private String name;

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

    // 所有组件都有的方法
    public abstract void print();

    // 添加子组件(对于文件无效)
    public abstract void add(FileSystemComponent component);

    // 删除子组件(对于文件无效)
    public abstract void remove(FileSystemComponent component);

    // 获取子组件(对于文件无效)
    public abstract FileSystemComponent getChild(int index);

    // 获取组件的名字
    public String getName() {
        return name;
    }
}

// 叶子节点:具体组件 - 文件
public class File extends FileSystemComponent {
    public File(String name) {
        super(name);
    }

    @Override
    public void print() {
        System.out.println("File: " + name);
    }

    // 文件不能添加、删除或获取子组件
    @Override
    public void add(FileSystemComponent component) {
        throw new UnsupportedOperationException("Files cannot have children.");
    }

    @Override
    public void remove(FileSystemComponent component) {
        throw new UnsupportedOperationException("Files cannot have children.");
    }

    @Override
    public FileSystemComponent getChild(int index) {
        throw new UnsupportedOperationException("Files cannot have children.");
    }
}

// 组合节点:具体组件 - 文件夹
public class Folder extends FileSystemComponent {
    private List<FileSystemComponent> children = new ArrayList<>();

    public Folder(String name) {
        super(name);
    }

    @Override
    public void print() {
        System.out.println("Folder: " + name);
        for (FileSystemComponent child : children) {
            child.print();
        }
    }

    @Override
    public void add(FileSystemComponent component) {
        children.add(component);
    }

    @Override
    public void remove(FileSystemComponent component) {
        children.remove(component);
    }

    @Override
    public FileSystemComponent getChild(int index) {
        return children.get(index);
    }
}

// 客户端代码调用
public class CompositePatternDemo {
    public static void main(String[] args) {
        Folder root = new Folder("root");
        Folder documents = new Folder("documents");
        Folder pictures = new Folder("pictures");
        File textFile = new File("readme.txt");

        root.add(documents);
        root.add(pictures);
        documents.add(textFile);

        root.print();
    }
}

在这个示例中:

  • FileSystemComponent 是抽象组件,定义了所有组件共有的行为(打印、添加、删除子组件等)。
  • File 是叶子组件,实现了抽象组件的行为但没有子组件。
  • Folder 是组合组件,不仅实现了抽象组件的行为,还包含了对子组件的管理方法。
  • 客户端代码可以一致地处理 FolderFile 对象,无论它是单独的文件还是包含多个子文件/文件夹的目录。

装饰器模式(Decorator Pattern)

允许在运行时为对象动态地添加新的功能。装饰器是在不影响其他对象的情况下,以透明的方式给单个对象添加职责。

以下是一个使用Java实现的装饰器模式示例,模拟了一个咖啡店的饮料系统,其中饮料(Coffee)可以添加不同的调料(如糖、牛奶等):

// 抽象组件:饮料接口
public interface Coffee {
    double getCost();
    String getDescription();
}

// 具体组件:基础咖啡
public class SimpleCoffee implements Coffee {
    @Override
    public double getCost() {
        return 1.0;
    }

    @Override
    public String getDescription() {
        return "Simple Coffee";
    }
}

// 装饰器抽象类
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

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

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

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

// 具体装饰器:糖调料
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.1; // 加糖增加的成本
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", with sugar";
    }
}

// 具体装饰器:牛奶调料
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.2; // 加牛奶增加的成本
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", with milk";
    }
}

// 客户端代码调用
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Coffee simpleCoffee = new SimpleCoffee();
        System.out.println(simpleCoffee.getDescription() + " $" + simpleCoffee.getCost());

        Coffee coffeeWithSugar = new SugarDecorator(simpleCoffee);
        System.out.println(coffeeWithSugar.getDescription() + " $" + coffeeWithSugar.getCost());

        Coffee coffeeWithMilkAndSugar = new MilkDecorator(coffeeWithSugar);
        System.out.println(coffeeWithMilkAndSugar.getDescription() + " $" + coffeeWithMilkAndSugar.getCost());
    }
}

在这个示例中:

  • Coffee 是抽象组件,定义了饮料的基本行为(获取成本和描述)。
  • SimpleCoffee 是具体组件,实现了饮料的基础功能。
  • CoffeeDecorator 是装饰器抽象类,继承了 Coffee 接口,并持有对原饮料对象的引用。
  • SugarDecoratorMilkDecorator 是具体的装饰器类,它们在装饰器抽象类的基础上增加了新的功能(添加糖或牛奶)。
  • 客户端代码可以根据需求动态地装饰咖啡,既可以选择基础咖啡,也可以选择添加了调料的咖啡,而无需更改原有咖啡类的代码。

外观模式(Facade Pattern)

为子系统中的一组接口提供了一个统一的高层接口,使得子系统更易于使用。这种模式通过定义一个新的接口来隐藏系统的复杂性,并向客户端提供了一个更简洁的接口。

以下是一个使用Java实现的外观模式示例,模拟了一个家电控制系统,其中包含空调、电视和音响等设备,而家电控制系统提供了统一的接口来控制这些设备:

// 子系统类:空调
public class AirConditioner {
    public void turnOn() {
        System.out.println("Air conditioner is turned on.");
    }

    public void turnOff() {
        System.out.println("Air conditioner is turned off.");
    }

    public void setTemperature(int temperature) {
        System.out.println("Setting air conditioner temperature to " + temperature + " degrees.");
    }
}

// 子系统类:电视
public class Television {
    public void turnOn() {
        System.out.println("Television is turned on.");
    }

    public void turnOff() {
        System.out.println("Television is turned off.");
    }

    public void setChannel(int channel) {
        System.out.println("Switching television to channel " + channel + ".");
    }
}

// 子系统类:音响
public class Stereo {
    public void turnOn() {
        System.out.println("Stereo is turned on.");
    }

    public void turnOff() {
        System.out.println("Stereo is turned off.");
    }

    public void setVolume(int volume) {
        System.out.println("Setting stereo volume to " + volume + ".");
    }
}

// 外观类:家电控制系统
public class HomeTheaterFacade {
    private AirConditioner airConditioner;
    private Television television;
    private Stereo stereo;

    public HomeTheaterFacade(AirConditioner airConditioner, Television television, Stereo stereo) {
        this.airConditioner = airConditioner;
        this.television = television;
        this.stereo = stereo;
    }

    // 提供统一接口来控制所有设备
    public void turnOn() {
        airConditioner.turnOn();
        television.turnOn();
        stereo.turnOn();
    }

    public void turnOff() {
        airConditioner.turnOff();
        television.turnOff();
        stereo.turnOff();
    }

    public void watchMovie() {
        turnOn();
        airConditioner.setTemperature(20); // 设置适宜观影的温度
        television.setChannel(5); // 转到电影频道
        stereo.setVolume(10); // 设置适当的音量
        System.out.println("Enjoy the movie!");
    }

    // 其他可能的操作...
}

// 客户端代码调用
public class FacadePatternDemo {
    public static void main(String[] args) {
        AirConditioner airConditioner = new AirConditioner();
        Television television = new Television();
        Stereo stereo = new Stereo();

        HomeTheaterFacade homeTheater = new HomeTheaterFacade(airConditioner, television, stereo);

        homeTheater.watchMovie();
    }
}

在这个示例中:

  • AirConditionerTelevisionStereo 是子系统类,代表家电控制系统中的不同设备。
  • HomeTheaterFacade 是外观类,它包含了各个子系统的引用,并提供了诸如 watchMovie() 这样的高层次操作,使得客户端可以更方便地控制整个家庭影院系统,而不必关心各个设备的具体操作细节。

享元模式(Flyweight Pattern)

主要用于减少对象的数量,以减少内存消耗。这种模式通过共享内部状态相同的对象来支持大量的细粒度对象。在享元模式中,享元对象存储在享元池中,当客户端请求创建新对象时,首先检查享元池中是否存在可复用的对象,如果存在,则直接返回;否则,创建新对象并放入享元池中。

以下是一个使用Java实现的享元模式示例,模拟了一个字符画系统,其中字符画由颜色和形状组成,颜色是可以共享的享元对象:

// 内部状态不可共享的实体类:形状
public class Shape {
    private char symbol;
    private FlyweightColor color;

    public Shape(char symbol, FlyweightColor color) {
        this.symbol = symbol;
        this.color = color;
    }

    public void draw() {
        System.out.println("Drawing shape with symbol " + symbol + " and color " + color.getColor());
    }
}

// 享元类:颜色
public class FlyweightColor {
    private static Map<String, FlyweightColor> flyweights = new HashMap<>();
    private final String color;

    private FlyweightColor(String color) {
        this.color = color;
    }

    public static FlyweightColor getInstance(String color) {
        FlyweightColor flyweight = flyweights.get(color);
        if (flyweight == null) {
            flyweight = new FlyweightColor(color);
            flyweights.put(color, flyweight);
        }
        return flyweight;
    }

    public String getColor() {
        return color;
    }
}

// 客户端代码调用
public class FlyweightPatternDemo {
    public static void main(String[] args) {
        Shape circle1 = new Shape('O', FlyweightColor.getInstance("Red"));
        Shape circle2 = new Shape('O', FlyweightColor.getInstance("Red"));

        Shape square1 = new Shape('#', FlyweightColor.getInstance("Green"));
        Shape square2 = new Shape('#', FlyweightColor.getInstance("Green"));

        circle1.draw();
        circle2.draw();
        square1.draw();
        square2.draw();

        // 输出:
        // Drawing shape with symbol O and color Red
        // Drawing shape with symbol O and color Red
        // Drawing shape with symbol # and color Green
        // Drawing shape with symbol # and color Green
    }
}

在这个示例中:

  • Shape 是非享元对象,它包含了一个不可共享的内部状态(符号)和一个享元对象(颜色)。
  • FlyweightColor 是享元类,它通过静态工厂方法 getInstance() 来创建或获取已存在的颜色对象。当请求相同颜色的对象时,会从享元池(Map)中获取已存在的对象,避免了重复创建。
  • 客户端代码创建了四个形状对象,但只有两种颜色对象被创建。这意味着即使有大量的形状共享相同的颜色,也只会创建有限数量的颜色对象,从而减少了内存消耗。

代理模式(Proxy Pattern)

为另一个对象提供一个代理以控制对这个对象的访问。代理模式可以用来添加额外的功能或者责任,比如日志、安全控制、延迟加载等,而不会影响原始对象。

下面是一个简单的 Java 示例,展示如何使用代理模式来实现代理一个真实主题(RealSubject)的行为——图书借阅系统中的图书管理。在这里,我们将创建一个图书接口(Book),一个真实的图书实现(RealBook),以及一个图书代理(BookProxy),该代理在借书时添加了权限验证的功能:

// 真实主题接口
interface Book {
    void borrowBook();
    void returnBook();
}

// 真实主题实现
class RealBook implements Book {
    private boolean isAvailable;

    public RealBook() {
        this.isAvailable = true;
    }

    @Override
    public void borrowBook() {
        if (isAvailable) {
            isAvailable = false;
            System.out.println("Book has been borrowed.");
        } else {
            System.out.println("Sorry, the book is not available.");
        }
    }

    @Override
    public void returnBook() {
        if (!isAvailable) {
            isAvailable = true;
            System.out.println("Book has been returned.");
        } else {
            System.out.println("The book was not borrowed to return.");
        }
    }
}

// 代理类
class BookProxy implements Book {
    private RealBook realBook;
    private User user;

    public BookProxy(User user) {
        this.user = user;
        this.realBook = new RealBook(); // 创建真实主题实例
    }

    @Override
    public void borrowBook() {
        if (user.hasBorrowingRights()) {
            realBook.borrowBook();
        } else {
            System.out.println("User does not have borrowing rights.");
        }
    }

    @Override
    public void returnBook() {
        if (user.hasBorrowedBook()) {
            realBook.returnBook();
        } else {
            System.out.println("User has not borrowed the book to return.");
        }
    }
}

// 用户类
class User {
    // 假设有一些方法用于验证用户是否有借阅权限和是否已经借过书
    public boolean hasBorrowingRights() {
        // 实现具体的逻辑判断,这里简化为总是返回true
        return true;
    }

    public boolean hasBorrowedBook() {
        // 在实际应用中,这可能需要查询数据库或其他数据源
        return true; // 这里简化为总是返回true
    }
}

// 客户端代码
public class ProxyPatternDemo {
    public static void main(String[] args) {
        User user = new User();
        BookProxy proxy = new BookProxy(user);

        proxy.borrowBook();
        proxy.returnBook();
    }
}

在这个示例中:

  • RealBook 类实现了 Book 接口,代表真正的图书实体。
  • BookProxy 类同样实现了 Book 接口,作为 RealBook 的代理,它在 borrowBook() 方法中增加了用户权限验证的功能。
  • 客户端代码通过 BookProxy 对象操作图书,而不是直接操作 RealBook 对象。这样就能够在不修改 RealBook 类的基础上,增加额外的控制行为。

行为模式

责任链模式(Chain of Responsibility)

通过将请求的发送者和接收者解耦,使得多个对象都有机会处理这个请求。这些对象连接成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

下面是一个简单的责任链模式的示例:

// 抽象处理者类
abstract class Handler {
    protected Handler successor;
    
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    
    public abstract void handleRequest(int request);
}

// 具体处理者类A
class ConcreteHandlerA extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 0 && request < 10) {
            System.out.println("ConcreteHandlerA 处理请求 " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 具体处理者类B
class ConcreteHandlerB extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 10 && request < 20) {
            System.out.println("ConcreteHandlerB 处理请求 " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        handlerA.setSuccessor(handlerB);
        
        int[] requests = {2, 5, 14, 22, 18, 3, 27, 20};
        
        for (int request : requests) {
            handlerA.handleRequest(request);
        }
    }
}

在这个示例中,我们定义了一个抽象的处理者类Handler,它包含一个指向下一个处理者的引用successor。具体的处理者类ConcreteHandlerAConcreteHandlerB继承自Handler,并实现了handleRequest方法来处理特定范围内的请求。如果当前处理者无法处理请求,它会将请求传递给下一个处理者。

在客户端代码中,我们创建了两个具体处理者对象handlerAhandlerB,并将它们连接成一个链。然后,我们遍历一系列请求,并将每个请求传递给第一个处理者handlerA。根据请求的范围,handlerAhandlerB会处理该请求,或者将请求传递给下一个处理者。

运行上述代码,输出结果如下:

ConcreteHandlerA 处理请求 2
ConcreteHandlerA 处理请求 5
ConcreteHandlerB 处理请求 14
ConcreteHandlerA 处理请求 18
ConcreteHandlerA 处理请求 3
ConcreteHandlerA 处理请求 27
ConcreteHandlerB 处理请求 20

可以看到,每个请求都被正确地处理,而且处理者之间的耦合度很低,可以灵活地添加或修改处理者。

命令模式(Command Pattern)

将请求封装为一个对象,使得可以用不同的请求、队列请求或日志请求,来参数化其他对象。命令模式还可以支持撤销操作。

以下是一个使用Java实现的命令模式示例,模拟一个简单的遥控器系统,其中遥控器可以接收并执行不同的按钮命令:

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

// 具体命令类:打开电视
class TurnOnTVCommand implements Command {
    private TV tv;

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

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

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

// 具体命令类:关闭电视
class TurnOffTVCommand implements Command {
    private TV tv;

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

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

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

// 设备类:电视
class TV {
    public void turnOn() {
        System.out.println("TV is turned on.");
    }

    public void turnOff() {
        System.out.println("TV is turned off.");
    }
}

// 遥控器类:持有命令列表并执行命令
class RemoteControl {
    private Command currentCommand;

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

    public void pressButton() {
        currentCommand.execute();
    }

    public void undoLastCommand() {
        currentCommand.undo();
    }
}

// 客户端代码调用
public class CommandPatternDemo {
    public static void main(String[] args) {
        TV tv = new TV();
        RemoteControl remote = new RemoteControl();

        Command turnOnCommand = new TurnOnTVCommand(tv);
        Command turnOffCommand = new TurnOffTVCommand(tv);

        remote.setCommand(turnOnCommand);
        remote.pressButton(); // 输出:TV is turned on.

        remote.setCommand(turnOffCommand);
        remote.pressButton(); // 输出:TV is turned off.

        remote.undoLastCommand(); // 输出:TV is turned on.
    }
}

在这个示例中:

  • Command 是命令接口,定义了所有命令必须实现的 execute()undo() 方法。
  • TurnOnTVCommandTurnOffTVCommand 是具体命令类,它们实现了 Command 接口,并针对具体的操作(打开或关闭电视)进行了实现。
  • TV 类是接收命令的对象,即执行命令的目标对象。
  • RemoteControl 类是请求者角色,它持有一个命令对象,并通过 pressButton() 方法触发命令的执行,通过 undoLastCommand() 方法撤销上一次执行的命令。

解释器模式(Interpreter Pattern)

定义了一种语言的语法表示,并提供了该语言的解释器。这种模式让程序设计语言中的语法规则可以直接映射到面向对象的表示中,从而使客户端能够在运行时解析特定的语言结构。

以下是一个使用Java实现的解释器模式示例,模拟了一个简单的数学表达式解析器,它可以解析和计算包含加法和乘法的算术表达式:

// 抽象表达式接口
interface Expression {
    int interpret();
}

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

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

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

// 终结符表达式(加法运算符)
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();
    }
}

// 终结符表达式(乘法运算符)
class MultiplyExpression implements Expression {
    private Expression left;
    private Expression right;

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

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

// 客户端代码调用
public class InterpreterPatternDemo {
    public static void main(String[] args) {
        Expression expression = new MultiplyExpression(
                new NumberExpression(5),
                new AddExpression(
                        new NumberExpression(2),
                        new NumberExpression(3)
                )
        );

        System.out.println("The result of the expression is: " + expression.interpret()); // 输出:25,因为计算结果是 (5 * (2 + 3))
    }
}

在这个示例中:

  • Expression 是抽象表达式接口,所有的具体表达式类都要实现这个接口的 interpret() 方法。
  • NumberExpressionAddExpressionMultiplyExpression 是终结符表达式类,它们分别代表数值、加法运算和乘法运算。
  • 客户端代码根据需求创建相应的表达式对象,并通过调用 interpret() 方法来解释和计算表达式的结果。本例中,我们构建了一个表达式 (5 * (2 + 3)),并计算出了结果 25

迭代器模式(Iterator Pattern)

提供了一种方法顺序访问聚合对象的元素,而又不需要暴露其底层表示。迭代器模式将游标移动、元素获取等相关操作封装起来,使得遍历集合对象时更加方便且不受集合内部结构的影响。

以下是一个使用Java实现的迭代器模式示例,模拟了一个简单的数组列表和对应的迭代器:

// 聚合接口
interface Aggregate {
    Iterator createIterator();
}

// 具体聚合类:ArrayList
class ArrayListAggregate implements Aggregate {
    private Object[] items;
    private int size;

    public ArrayListAggregate(int capacity) {
        items = new Object[capacity];
    }

    public void add(Object item) {
        if (size < items.length) {
            items[size++] = item;
        }
    }

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

    private class ArrayListIterator implements Iterator {
        private int position = 0;

        @Override
        public boolean hasNext() {
            return position < size;
        }

        @Override
        public Object next() {
            if (!hasNext()) {
                throw new IllegalStateException("No more elements");
            }
            return items[position++];
        }
    }
}

// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 客户端代码调用
public class IteratorPatternDemo {
    public static void main(String[] args) {
        Aggregate aggregate = new ArrayListAggregate(5);
        aggregate.add("Apple");
        aggregate.add("Banana");
        aggregate.add("Cherry");

        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

在这个示例中:

  • Aggregate 是聚合接口,声明了一个创建迭代器的方法 createIterator()
  • ArrayListAggregate 是一个具体的聚合类,它实现了 Aggregate 接口,并包含一个内部类 ArrayListIterator,实现了 Iterator 接口。
  • Iterator 是迭代器接口,定义了遍历元素所需的 hasNext()next() 方法。
  • 客户端代码通过聚合类创建一个迭代器,然后使用迭代器遍历并输出集合中的元素。本例中,输出将会是:“Apple”, “Banana”, “Cherry”。

中介者模式(Mediator Pattern)

定义了一个中介对象来封装一系列的对象交互,中介者使各个对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

以下是一个使用Java实现的中介者模式示例,模拟了一个简单的聊天室系统,其中每个用户都是一个同事类(Colleague),聊天室则是中介者(Mediator),负责协调用户间的通信:

// 同事接口:用户
public interface User {
    void sendMessage(String message);
    void receiveMessage(String message);
    void setMediator(ChatRoomMediator mediator);
}

// 具体同事类:ChatUser
public class ChatUser implements User {
    private String name;
    private ChatRoomMediator mediator;

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

    @Override
    public void sendMessage(String message) {
        mediator.sendMessage(this, message);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println(name + " received: " + message);
    }

    @Override
    public void setMediator(ChatRoomMediator mediator) {
        this.mediator = mediator;
    }

    @Override
    public String toString() {
        return name;
    }
}

// 中介者类:ChatRoomMediator
public class ChatRoomMediator {
    private List<User> users;

    public ChatRoomMediator() {
        users = new ArrayList<>();
    }

    public void addUser(User user) {
        users.add(user);
        user.setMediator(this);
    }

    public void sendMessage(User from, String message) {
        for (User to : users) {
            if (to != from) { // 不给自己发送消息
                to.receiveMessage(from + ": " + message);
            }
        }
    }
}

// 客户端代码调用
public class MediatorPatternDemo {
    public static void main(String[] args) {
        ChatRoomMediator mediator = new ChatRoomMediator();
        User alice = new ChatUser("Alice");
        User bob = new ChatUser("Bob");

        mediator.addUser(alice);
        mediator.addUser(bob);

        alice.sendMessage("Hello, Bob!");
        bob.sendMessage("Hi, Alice!");
    }
}

在这个示例中:

  • User 是同事接口,定义了发送和接收消息的方法,以及设置中介者的方法。
  • ChatUser 是具体同事类,实现了 User 接口,并通过中介者发送消息。
  • ChatRoomMediator 是中介者类,它维护了一个用户列表,并提供了发送消息的方法,该方法会把消息转发给除了发送者之外的所有用户。
  • 客户端代码创建了一个聊天室(中介者)和两个用户,并让他们加入聊天室。当一个用户发送消息时,消息会通过中介者传递给另一个用户。

备忘录模式(Memento Pattern)

提供了一种在不破坏封装的前提下保存和恢复对象内部状态的方法。备忘录模式包括三个角色:发起人(Originator)、备忘录(Memento)和负责人(Caretaker)。发起人创建并维护自己的状态,备忘录用于存储发起人的内部状态,而负责人负责保存和恢复备忘录。

以下是一个使用Java实现的备忘录模式示例,模拟了一个文本编辑器,其中文档对象(Originator)可以保存和恢复其内容状态:

// 发起人接口:文档
public interface Document {
    void type(String words);
    Memento saveToMemento();
    void restoreFromMemento(Memento memento);
}

// 具体发起人:TextDocument
public class TextDocument implements Document {
    private StringBuilder content;

    public TextDocument() {
        this.content = new StringBuilder();
    }

    @Override
    public void type(String words) {
        content.append(words).append("\n");
        System.out.println("Typing: " + words);
    }

    @Override
    public Memento saveToMemento() {
        return new DocumentMemento(content.toString());
    }

    @Override
    public void restoreFromMemento(Memento memento) {
        this.content = new StringBuilder(((DocumentMemento)memento).getContent());
        System.out.println("Restored document content:");
        printContent();
    }

    private void printContent() {
        System.out.println(content);
    }
}

// 备忘录接口
public interface Memento {
    String getContent();
}

// 具体备忘录:DocumentMemento
public class DocumentMemento implements Memento {
    private String content;

    public DocumentMemento(String content) {
        this.content = content;
    }

    @Override
    public String getContent() {
        return content;
    }
}

// 负责人:Editor
public class Editor {
    private Document document;
    private Stack<Memento> undoStack = new Stack<>();

    public Editor(Document document) {
        this.document = document;
    }

    public void type(String words) {
        document.type(words);
        undoStack.push(document.saveToMemento());
    }

    public void undo() {
        if (!undoStack.isEmpty()) {
            Memento memento = undoStack.pop();
            document.restoreFromMemento(memento);
        } else {
            System.out.println("Undo stack is empty.");
        }
    }
}

// 客户端代码调用
public class MementoPatternDemo {
    public static void main(String[] args) {
        Document document = new TextDocument();
        Editor editor = new Editor(document);

        editor.type("First line...");
        editor.type("Second line...");

        editor.undo(); // 撤销上次输入
    }
}

在这个示例中:

  • Document 是发起人接口,定义了类型、保存到备忘录和从备忘录恢复的方法。
  • TextDocument 是具体发起人,实现了 Document 接口,并具有内容状态。
  • Memento 是备忘录接口,定义了获取发起人状态的方法。
  • DocumentMemento 是具体备忘录,实现了 Memento 接口,并存储了发起人的状态。
  • Editor 是负责人,它维护了一个栈来保存备忘录,并提供了撤销操作。
  • 客户端代码创建了一个文档对象和编辑器对象,进行一些操作后,可以通过撤销方法恢复到之前的状态。

观察者模式(Observer Pattern)

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

以下是一个使用Java实现的观察者模式示例,模拟了一个天气预报系统,其中气象站是被观察者(Subject),订阅者(Observer)是关注天气变化的人们:

import java.util.ArrayList;
import java.util.List;

// 被观察者接口:气象站
public interface WeatherStation {
    void registerObserver(WeatherObserver observer);
    void removeObserver(WeatherObserver observer);
    void notifyObservers();
    float getTemperature();
    float getHumidity();
}

// 具体被观察者:气象站实现
public class WeatherStationImpl implements WeatherStation {
    private List<WeatherObserver> observers;
    private float temperature;
    private float humidity;

    public WeatherStationImpl() {
        observers = new ArrayList<>();
    }

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

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

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

    @Override
    public float getTemperature() {
        return temperature;
    }

    @Override
    public float getHumidity() {
        return humidity;
    }

    public void setMeasurements(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        notifyObservers();
    }
}

// 观察者接口:订阅者
public interface WeatherObserver {
    void update(float temperature, float humidity);
}

// 具体观察者:订阅者实现
public class WeatherSubscriber implements WeatherObserver {
    private String name;

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

    @Override
    public void update(float temperature, float humidity) {
        System.out.println(name + " got updated! New weather data: Temperature: " + temperature + ", Humidity: " + humidity);
    }
}

// 客户端代码调用
public class ObserverPatternDemo {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStationImpl();
        WeatherObserver subscriber1 = new WeatherSubscriber("Alice");
        WeatherObserver subscriber2 = new WeatherSubscriber("Bob");

        station.registerObserver(subscriber1);
        station.registerObserver(subscriber2);

        station.setMeasurements(20.0f, 60.0f); // 新的天气数据

        // 输出:
        // Alice got updated! New weather data: Temperature: 20.0, Humidity: 60.0
        // Bob got updated! New weather data: Temperature: 20.0, Humidity: 60.0
    }
}

在这个示例中:

  • WeatherStation 是被观察者接口,定义了注册、移除观察者、通知观察者以及获取测量值的方法。
  • WeatherStationImpl 是具体被观察者,实现了 WeatherStation 接口,并维护了一个观察者列表,在测量值发生变化时通知所有观察者。
  • WeatherObserver 是观察者接口,定义了当被观察者状态变化时需要更新的方法。
  • WeatherSubscriber 是具体观察者,实现了 WeatherObserver 接口,当收到更新时会打印新的天气信息。
  • 客户端代码创建了一个气象站对象和两个订阅者对象,并将订阅者注册到气象站。当气象站更新测量值时,所有订阅者都会收到通知并打印新的天气信息。
状态模式(State Pattern)

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。状态模式将与特定状态相关的行为局部化,并且将每一个状态封装进一个独立的类中。

以下是一个使用Java实现的状态模式示例,模拟了一个ATM机取款的过程,其中ATM机包含多种状态(例如正常、余额不足、超出每日取款限额等):

// 抽象状态接口
public interface State {
    void insertCard();
    void ejectCard();
    void requestCash(int amount);
    void dispenseCash(int amount);
    void setState(State state);
}

// 具体状态类:正常状态
public class NormalState implements State {
    private ATM atm;

    public NormalState(ATM atm) {
        this.atm = atm;
    }

    @Override
    public void insertCard() {
        System.out.println("Card inserted in normal state.");
        atm.setState(atm.getHasCardState());
    }

    // 其他方法处理不符合当前状态的行为...

    @Override
    public void requestCash(int amount) {
        if (atm.getBalance() >= amount) {
            atm.setState(atm.getDispensingState(amount));
        } else {
            atm.setState(atm.getInsufficientFundsState());
        }
    }
}

// 其他具体状态类:余额不足状态、超出每日取款限额状态...

// ATM机类,包含状态对象
public class ATM {
    private State currentState;
    private int balance;
    private int dailyWithdrawalLimit;
    private int requestedAmount;

    public ATM(int balance, int dailyWithdrawalLimit) {
        this.currentState = new NoCardState(this);
        this.balance = balance;
        this.dailyWithdrawalLimit = dailyWithdrawalLimit;
    }

    public void insertCard() {
        currentState.insertCard();
    }

    public void ejectCard() {
        currentState.ejectCard();
    }

    public void requestCash(int amount) {
        requestedAmount = amount;
        currentState.requestCash(amount);
    }

    public void dispenseCash(int amount) {
        currentState.dispenseCash(amount);
        balance -= amount;
    }

    // 获取各种状态的方法...
    
    private State getNormalState() {...}
    private State getHasCardState() {...}
    private State getInsufficientFundsState() {...}
    private State getExceedsDailyLimitState() {...}
    private State getDispensingState(int amount) {...}
}

// 客户端代码调用
public class StatePatternDemo {
    public static void main(String[] args) {
        ATM atm = new ATM(1000, 500);
        atm.insertCard();
        atm.requestCash(200); // 正常取款
        atm.requestCash(900); // 余额不足
    }
}

在这个示例中:

  • State 是抽象状态接口,定义了ATM机在不同状态下应有的行为方法。
  • NormalStateInsufficientFundsState 等是具体状态类,它们实现了 State 接口,并根据当前状态的不同实现了相应的行为。
  • ATM 类是环境类,它包含一个状态对象(currentState),并在状态改变时切换到对应的具体状态类。
  • 客户端代码创建了一个ATM对象,并模拟了插入卡片和请求取款的过程,根据请求的金额,ATM机会在不同状态间切换并执行相应的行为。

策略模式(Strategy Pattern)

能在运行时改变对象的行为。在策略模式中,一个类的行为或其算法可以在运行时更改。

下面是一个简单的Java策略模式示例,模拟一个电商平台根据不同的会员等级计算折扣的价格策略:

// 抽象策略接口
public interface DiscountStrategy {
    double getDiscount(double price, Member member);
}

// 具体策略类:普通会员折扣策略
public class NormalMemberDiscountStrategy implements DiscountStrategy {
    @Override
    public double getDiscount(double price, Member member) {
        return price * 0.95; // 普通会员享受95折
    }
}

// 其他具体策略类:黄金会员折扣策略
public class GoldMemberDiscountStrategy implements DiscountStrategy {
    @Override
    public double getDiscount(double price, Member member) {
        return price * 0.9; // 黄金会员享受9折
    }
}

// 会员类,包含了具体的折扣策略
public class Member {
    private DiscountStrategy discountStrategy;

    public Member(DiscountStrategy strategy) {
        this.discountStrategy = strategy;
    }

    public void setDiscountStrategy(DiscountStrategy strategy) {
        this.discountStrategy = strategy;
    }

    public double getDiscountedPrice(double price) {
        return discountStrategy.getDiscount(price, this);
    }
}

// 客户端代码调用
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Member normalMember = new Member(new NormalMemberDiscountStrategy());
        System.out.println("普通会员购买价格:" + normalMember.getDiscountedPrice(100));

        Member goldMember = new Member(new GoldMemberDiscountStrategy());
        System.out.println("黄金会员购买价格:" + goldMember.getDiscountedPrice(100));

        // 运行时更改策略
        goldMember.setDiscountStrategy(new NormalMemberDiscountStrategy());
        System.out.println("黄金会员变更为普通会员后购买价格:" + goldMember.getDiscountedPrice(100));
    }
}

// 输出可能为:
// 普通会员购买价格:95.0
// 黄金会员购买价格:90.0
// 黄金会员变更为普通会员后购买价格:95.0

在这个示例中:

  • DiscountStrategy 是抽象策略接口,定义了一个计算折扣的方法。
  • NormalMemberDiscountStrategyGoldMemberDiscountStrategy 是具体策略类,实现了 DiscountStrategy 接口,提供了不同的折扣算法。
  • Member 类是上下文,它持有一个 DiscountStrategy 对象,并通过调用该对象的方法来计算折扣后的价格。
  • 客户端可以根据会员等级创建相应的策略对象,并将其注入到会员实例中,也可以在运行时动态地更换会员的折扣策略。

模板方法模式(Template Method Pattern)

在一个抽象类中定义了一个算法的骨架,允许子类在不改变结构的情况下重写算法的某些步骤。这种模式创建了一个模板,定义了算法的框架,而由子类去填充算法的一些特定步骤。

以下是一个使用Java实现的模板方法模式示例,模拟了一个烹饪食谱模板,其中抽象类定义了制作披萨的基本流程,而具体子类定义了特定披萨的制作步骤:

// 抽象类:披萨制作模板
abstract class Pizza {
    // 模板方法
    public void makePizza() {
        prepareIngredients();
        bake();
        cut();
        box();
    }

    // 基本步骤由子类实现
    abstract void prepareIngredients();

    abstract void bake();

    abstract void cut();

    void box() {
        System.out.println("Boxing the pizza...");
    }

    // 其他辅助方法...
}

// 具体子类:芝士披萨
class CheesePizza extends Pizza {
    @Override
    void prepareIngredients() {
        System.out.println("Preparing cheese...");
    }

    @Override
    void bake() {
        System.out.println("Baking cheese pizza...");
    }

    @Override
    void cut() {
        System.out.println("Cutting cheese pizza...");
    }
}

// 其他具体子类:海鲜披萨等...

// 客户端代码调用
public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        Pizza cheesePizza = new CheesePizza();
        cheesePizza.makePizza();
    }
}

// 输出可能为:
// Preparing cheese...
// Baking cheese pizza...
// Cutting cheese pizza...
// Boxing the pizza...

在这个示例中:

  • Pizza 是抽象类,定义了一个制作披萨的模板方法 makePizza(),并在其中调用了几个基本步骤的抽象方法。
  • CheesePizza 是具体子类,它继承自 Pizza 并实现了那些抽象方法,定义了制作芝士披萨的具体步骤。
  • 客户端代码创建了一个 CheesePizza 对象,并调用其 makePizza() 方法,按照预定义的模板流程完成披萨的制作。

访问者模式(Visitor Pattern)

主要作用于数据结构较为复杂的场景,能够使你在不改变现有数据结构的前提下,对数据结构中的元素进行操作。访问者模式将数据结构和作用于结构上的操作解耦,使得操作可以独立于结构变化而变化。

以下是一个使用Java实现的访问者模式示例,模拟了一个动物园系统,其中动物是元素,访问者是对动物进行不同类型操作(如喂食、参观等)的角色:

// 抽象动物类
public abstract class Animal {
    public abstract void accept(AnimalOperation operation);
}

// 具体动物类
public class Monkey extends Animal {
    @Override
    public void accept(AnimalOperation operation) {
        operation.visitMonkey(this);
    }
}

public class Lion extends Animal {
    @Override
    public void accept(AnimalOperation operation) {
        operation.visitLion(this);
    }
}

// 其他具体动物类...

// 抽象访问者类
public abstract class AnimalOperation {
    public abstract void visitMonkey(Monkey monkey);
    public abstract void visitLion(Lion lion);
}

// 具体访问者类:喂食操作
public class FeedAnimal implements AnimalOperation {
    @Override
    public void visitMonkey(Monkey monkey) {
        System.out.println("Feeding monkey...");
    }

    @Override
    public void visitLion(Lion lion) {
        System.out.println("Feeding lion...");
    }
}

// 其他具体访问者类:参观操作等...

// 客户端代码调用
public class VisitorPatternDemo {
    public static void main(String[] args) {
        Animal monkey = new Monkey();
        Animal lion = new Lion();

        AnimalOperation feedOperation = new FeedAnimal();
        
        monkey.accept(feedOperation);
        lion.accept(feedOperation);
    }
}

// 输出可能为:
// Feeding monkey...
// Feeding lion...

在这个示例中:

  • Animal 是抽象元素类,定义了接受访问者的方法 accept()
  • MonkeyLion 是具体元素类,它们继承自 Animal 并在 accept() 方法中调用访问者的相应方法。
  • AnimalOperation 是抽象访问者类,定义了对每一种动物进行操作的方法。
  • FeedAnimal 是具体访问者类,它实现了 AnimalOperation 并定义了对每种动物进行喂食的具体操作。
  • 客户端代码创建了动物对象和访问者对象,然后让动物接受访问者提供的操作。
  • 26
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式是一套对代码设计经验的总结,被人们反复利用,并且很多人都熟知的代码设计方式。其中,单例模式是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这种模式有几个好处,比如可以节约系统资源,提高程序效率,以及提供一个全局访问点等。在实现单例模式时,可以采用饿汉式单例模式,即在类加载时创建一个对象,并通过私有构造器和静态方法来保证对象的唯一性。另外,工厂方法模式也是Java中常用的设计模式之一。在工厂方法模式中,可以定义一个工厂类,该类负责创建对象的实例,并将其封装在一个工厂方法中。通过这种方式,可以实现对象的创建与使用的分离,提高代码的灵活性和可维护性。总的来说,Java设计模式是一种用于解决特定问题的通用解决方案,可以提高代码的重用性、可读性和可扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java常用设计模式](https://blog.csdn.net/qq_33327680/article/details/123815614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [JAVA23种设计模式](https://blog.csdn.net/qw_0214/article/details/78878531)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值