设计模式 (五) 设计模式实战系列

目录

一、创建型模式

1.单例模式实战

2.建造者模式实战

3.原型模式实战

4.工厂方法模式实战

5.抽象工厂模式实战

二、结构型模式

6.适配器模式实战

7.桥接模式实战

8.装饰器模式实战

9.组合模式实战

10.外观模式实战

11.享元模式实战

12.代理模式实战

三、行为型模式

13.模板方法模式实战

14.命令模式实战

15.访问者模式实战

16.迭代器模式实战

17.观察者模式实战

18.中介者模式实战

19.备忘录模式实战

20.解释器模式实战

21.策略模式实战

22.命令模式实战

23.职责链模式实战


        设计模式实战系列是一系列实际应用设计模式的案例,旨在帮助读者更好地理解和应用设计模式。以下是设计模式实战系列的一些案例,它们涉及到不同的设计模式和应用场景,可以帮助读者更好地理解和应用设计模式。

一、创建型模式

1.单例模式实战

在这个案例中,我们将使用单例模式创建一个全局唯一的配置管理器,以便在整个应用程序中共享配置信息。具体实现如下:

// 配置管理器类
public class ConfigurationManager {
    private static ConfigurationManager instance = new ConfigurationManager();

    private Map<String, String> config = new HashMap<>();

    private ConfigurationManager() {
        // 加载配置信息
        config.put("db.url", "jdbc:mysql://localhost:3306/test");
        config.put("db.username", "root");
        config.put("db.password", "123456");
    }

    public static ConfigurationManager getInstance() {
        return instance;
    }

    public String getConfig(String key) {
        return config.get(key);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ConfigurationManager configManager = ConfigurationManager.getInstance();
        String dbUrl = configManager.getConfig("db.url");
        String dbUsername = configManager.getConfig("db.username");
        String dbPassword = configManager.getConfig("db.password");

        System.out.println("db.url: " + dbUrl);
        System.out.println("db.username: " + dbUsername);
        System.out.println("db.password: " + dbPassword);
    }
}

在这个例子中,我们定义了一个配置管理器类 ConfigurationManager,它使用私有构造函数和静态成员变量来实现单例模式。在构造函数中,我们加载了一些配置信息,并将它们存储在一个 Map 中。然后,我们定义了一个 getInstance 方法,用于获取全局唯一的配置管理器实例。最后,我们编写了一个客户端代码,使用配置管理器获取数据库连接信息,并输出到控制台上。

2.建造者模式实战

在这个案例中,我们将使用建造者模式创建一个复杂的电子商务网站,包括商品展示、购物车、结算等功能。具体实现如下:

// 商品类
public class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

// 购物车类
public class ShoppingCart {
    private List<Product> products = new ArrayList<>();

    public void addProduct(Product product) {
        products.add(product);
    }

    public double getTotalPrice() {
        double totalPrice = 0;
        for (Product product : products) {
            totalPrice += product.getPrice();
        }
        return totalPrice;
    }
}

// 订单类
public class Order {
    private String customerName;
    private String shippingAddress;
    private ShoppingCart shoppingCart;

    public Order(String customerName, String shippingAddress, ShoppingCart shoppingCart) {
        this.customerName = customerName;
        this.shippingAddress = shippingAddress;
        this.shoppingCart = shoppingCart;
    }

    public String getCustomerName() {
        return customerName;
    }

    public String getShippingAddress() {
        return shippingAddress;
    }

    public double getTotalPrice() {
        return shoppingCart.getTotalPrice();
    }
}

// 订单建造者接口
public interface OrderBuilder {
    void buildCustomerName(String customerName);
    void buildShippingAddress(String shippingAddress);
    void buildShoppingCart(ShoppingCart shoppingCart);
    Order getOrder();
}

// 订单建造者实现类
public class OnlineOrderBuilder implements OrderBuilder {
    private Order order = new Order("", "", new ShoppingCart());

    @Override
    public void buildCustomerName(String customerName) {
        order = new Order(customerName, order.getShippingAddress(), order.getShoppingCart());
    }

    @Override
    public void buildShippingAddress(String shippingAddress) {
        order = new Order(order.getCustomerName(), shippingAddress, order.getShoppingCart());
    }

    @Override
    public void buildShoppingCart(ShoppingCart shoppingCart) {
        order = new Order(order.getCustomerName(), order.getShippingAddress(), shoppingCart);
    }

    @Override
    public Order getOrder() {
        return order;
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        OrderBuilder builder = new OnlineOrderBuilder();

        builder.buildCustomerName("Alice");
        builder.buildShippingAddress("123 Main St.");
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.addProduct(new Product("iPhone", 999.99));
        shoppingCart.addProduct(new Product("iPad", 799.99));
        builder.buildShoppingCart(shoppingCart);

        Order order = builder.getOrder();
        System.out.println("Customer Name: " + order.getCustomerName());
        System.out.println("Shipping Address: " + order.getShippingAddress());
        System.out.println("Total Price: " + order.getTotalPrice());
    }
}

在这个例子中,我们定义了一个商品类 Product、一个购物车类 ShoppingCart 和一个订单类 Order。然后,我们定义了一个订单建造者接口 OrderBuilder 和一个具体订单建造者实现类 OnlineOrderBuilder,用于创建订单对象。在客户端代码中,我们使用订单建造者创建一个订单对象,并输出订单的客户名称、配送地址和总价到控制台上。

3.原型模式实战

在这个案例中,我们将使用原型模式创建一个简单的图形编辑器,可以复制和粘贴图形对象。具体实现如下:

// 图形接口
public interface Shape extends Cloneable {
    void draw();
    Shape clone();
}

// 圆形类
public class Circle implements Shape {
    private int x;
    private int y;
    private int radius;

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

    @Override
    public void draw() {
        System.out.println("Drawing a circle at (" + x + ", " + y + ") with radius " + radius);
    }

    @Override
    public Shape clone() {
        return new Circle(x, y, radius);
    }
}

// 矩形类
public class Rectangle implements Shape {
    private int x;
    private int y;
    private int width;
    private int height;

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

    @Override
    public void draw() {
        System.out.println("Drawing a rectangle at (" + x + ", " + y + ") with width " + width + " and height " + height);
    }

    @Override
    public Shape clone() {
        return new Rectangle(x, y, width, height);
    }
}

// 图形编辑器类
public class GraphicsEditor {
    private List<Shape> shapes = new ArrayList<>();

    public void addShape(Shape shape) {
        shapes.add(shape);
    }

    public void copyShape(int index) {
        Shape shape = shapes.get(index).clone();
        shapes.add(shape);
    }

    public void pasteShape(int index) {
        Shape shape = shapes.get(shapes.size() - 1).clone();
        shapes.add(index, shape);
    }

    public void drawShapes() {
        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        GraphicsEditor editor = new GraphicsEditor();

        Circle circle = new Circle(100, 100, 50);
        editor.addShape(circle);

        Rectangle rectangle = new Rectangle(200, 200, 100, 50);
        editor.addShape(rectangle);

        editor.copyShape(0);
        editor.pasteShape(2);

        editor.drawShapes();
    }
}

在这个例子中,我们定义了一个图形接口 Shape 和两个具体图形类 Circle 和 Rectangle。然后,我们定义了一个图形编辑器类 GraphicsEditor,它可以添加、复制、粘贴和绘制图形对象。在客户端代码中,我们使用图形编辑器创建两个图形对象,并复制和粘贴第一个图形对象,最后绘制所有图形对象。

4.工厂方法模式实战

在实践中,工厂方法模式常用于创建对象的场景,例如在一个电商网站中,需要创建不同类型的商品对象,可以使用工厂方法模式来实现。

具体实现如下:

// 商品接口
public interface Product {
    void showInfo();
}

// 电视类
public class TV implements Product {
    @Override
    public void showInfo() {
        System.out.println("This is a TV");
    }
}

// 手机类
public class Phone implements Product {
    @Override
    public void showInfo() {
        System.out.println("This is a phone");
    }
}

// 商品工厂接口
public interface ProductFactory {
    Product createProduct();
}

// 电视工厂类
public class TVFactory implements ProductFactory {
    @Override
    public Product createProduct() {
        return new TV();
    }
}

// 手机工厂类
public class PhoneFactory implements ProductFactory {
    @Override
    public Product createProduct() {
        return new Phone();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ProductFactory tvFactory = new TVFactory();
        Product tv = tvFactory.createProduct();
        tv.showInfo();

        ProductFactory phoneFactory = new PhoneFactory();
        Product phone = phoneFactory.createProduct();
        phone.showInfo();
    }
}

在这个例子中,我们定义了一个商品接口 Product 和两个具体商品类 TV 和 Phone,它们分别实现了商品的展示方法。然后,我们定义了一个商品工厂接口 ProductFactory 和两个具体商品工厂类 TVFactory 和 PhoneFactory,它们分别实现了创建商品的方法。在客户端代码中,我们创建了一个电视工厂对象和一个手机工厂对象,并分别使用它们来创建电视和手机对象,最后调用它们的展示方法。由于工厂方法模式是将对象的创建延迟到子类中,从而使得客户端代码不需要直接依赖具体的产品类,所以我们可以通过它来实现程序的灵活性和可扩展性。

5.抽象工厂模式实战

在实际应用中,抽象工厂模式可以用于创建一系列相关的对象,例如在一个游戏中,需要创建不同类型的角色和装备对象,可以使用抽象工厂模式来实现。

具体实现如下:

// 角色接口
public interface Role {
    void showInfo();
}

// 战士类
public class Warrior implements Role {
    @Override
    public void showInfo() {
        System.out.println("This is a warrior");
    }
}

// 法师类
public class Mage implements Role {
    @Override
    public void showInfo() {
        System.out.println("This is a mage");
    }
}

// 装备接口
public interface Equipment {
    void showInfo();
}

// 武器类
public class Weapon implements Equipment {
    @Override
    public void showInfo() {
        System.out.println("This is a weapon");
    }
}

// 盾牌类
public class Shield implements Equipment {
    @Override
    public void showInfo() {
        System.out.println("This is a shield");
    }
}

// 抽象工厂接口
public interface AbstractFactory {
    Role createRole();
    Equipment createEquipment();
}

// 战士工厂类
public class WarriorFactory implements AbstractFactory {
    @Override
    public Role createRole() {
        return new Warrior();
    }

    @Override
    public Equipment createEquipment() {
        return new Weapon();
    }
}

// 法师工厂类
public class MageFactory implements AbstractFactory {
    @Override
    public Role createRole() {
        return new Mage();
    }

    @Override
    public Equipment createEquipment() {
        return new Shield();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        AbstractFactory warriorFactory = new WarriorFactory();
        Role warrior = warriorFactory.createRole();
        Equipment weapon = warriorFactory.createEquipment();
        warrior.showInfo();
        weapon.showInfo();

        AbstractFactory mageFactory = new MageFactory();
        Role mage = mageFactory.createRole();
        Equipment shield = mageFactory.createEquipment();
        mage.showInfo();
        shield.showInfo();
    }
}

在这个例子中,我们定义了一个角色接口 Role 和两个具体角色类 Warrior 和 Mage,它们分别实现了角色的展示方法。同时,我们定义了一个装备接口 Equipment 和两个具体装备类 Weapon 和 Shield,它们分别实现了装备的展示方法。然后,我们定义了一个抽象工厂接口 AbstractFactory 和两个具体工厂类 WarriorFactory 和 MageFactory,它们分别实现了创建角色和装备的方法。在客户端代码中,我们创建了一个战士工厂对象和一个法师工厂对象,并分别使用它们来创建战士和法师对象以及对应的装备对象,最后调用它们的展示方法。由于抽象工厂模式是将对象的创建延迟到子类中,从而使得客户端代码不需要直接依赖具体的产品类,所以我们可以通过它来实现程序的灵活性和可扩展性。

二、结构型模式

6.适配器模式实战

在这个案例中,我们将使用适配器模式将一个老的音频播放器适配成一个新的多媒体播放器,以便支持不同的音频格式。具体实现如下:

// 老的音频播放器接口
public interface AudioPlayer {
    void playMp3(String fileName);
    void playWav(String fileName);
}

// 老的音频播放器实现类
public class LegacyAudioPlayer implements AudioPlayer {
    @Override
    public void playMp3(String fileName) {
        System.out.println("Playing MP3 file: " + fileName);
    }

    @Override
    public void playWav(String fileName) {
        System.out.println("Playing WAV file: " + fileName);
    }
}

// 新的多媒体播放器接口
public interface MediaPlayer {
    void play(String fileName);
}

// 新的多媒体播放器实现类
public class MultimediaPlayer implements MediaPlayer {
    @Override
    public void play(String fileName) {
        if (fileName.endsWith(".mp3")) {
            AudioPlayer audioPlayer = new LegacyAudioPlayer();
            audioPlayer.playMp3(fileName);
        } else if (fileName.endsWith(".wav")) {
            AudioPlayer audioPlayer = new LegacyAudioPlayer();
            audioPlayer.playWav(fileName);
        } else {
            throw new IllegalArgumentException("Unsupported media type: " + fileName);
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        MediaPlayer mediaPlayer = new MultimediaPlayer();
        mediaPlayer.play("song.mp3");
        mediaPlayer.play("sound.wav");
        mediaPlayer.play("movie.mp4");
    }
}

在这个例子中,我们定义了一个老的音频播放器接口 AudioPlayer 和一个具体实现类 LegacyAudioPlayer,它可以播放 MP3 和 WAV 格式的音频文件。然后,我们定义了一个新的多媒体播放器接口 MediaPlayer 和一个具体实现类 MultimediaPlayer,它可以适配老的音频播放器,以便支持不同的音频格式。在客户端代码中,我们使用新的多媒体播放器播放 MP3、WAV 和不支持的文件,最后输出一个异常信息。

7.桥接模式实战

在这个案例中,我们将使用桥接模式将一个抽象的图形类和一个具体的颜色类分离,以便支持不同的图形和颜色组合。具体实现如下:

// 颜色接口
public interface Color {
    void applyColor();
}

// 红色实现类
public class Red implements Color {
    @Override
    public void applyColor() {
        System.out.println("Applying red color");
    }
}

// 绿色实现类
public class Green implements Color {
    @Override
    public void applyColor() {
        System.out.println("Applying green color");
    }
}

// 图形抽象类
public abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

// 圆形实现类
public class Circle extends Shape {
    private int x;
    private int y;
    private int radius;

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

    @Override
    public void draw() {
        System.out.print("Drawing a circle at (" + x + ", " + y + ") with radius " + radius + " ");
        color.applyColor();
    }
}

// 矩形实现类
public class Rectangle extends Shape {
    private int x;
    private int y;
    private int width;
    private int height;

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

    @Override
    public void draw() {
        System.out.print("Drawing a rectangle at (" + x + ", " + y + ") with width " + width + " and height " + height + " ");
        color.applyColor();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Shape circle = new Circle(100, 100, 50, new Red());
        Shape rectangle = new Rectangle(200, 200, 100, 50, new Green());

        circle.draw();
        rectangle.draw();
    }
}

在这个例子中,我们定义了一个颜色接口 Color 和两个具体颜色实现类 Red 和 Green。然后,我们定义了一个图形抽象类 Shape,它包含一个颜色成员变量和一个抽象的 draw 方法。最后,我们定义了两个具体图形实现类 Circle 和 Rectangle,它们继承自 Shape 类,并实现了 draw 方法。在客户端代码中,我们创建了一个红色的圆形和一个绿色的矩形,并分别调用它们的 draw 方法。

8.装饰器模式实战

在这个案例中,我们将使用装饰器模式来扩展一个简单的咖啡店,以支持添加不同的配料。具体实现如下:

// 咖啡接口
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 MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.5;
    }

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

// 糖浆装饰器实现类
public class SyrupDecorator extends CoffeeDecorator {
    public SyrupDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.3;
    }

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

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        coffee = new MilkDecorator(coffee);
        coffee = new SyrupDecorator(coffee);

        System.out.println("Cost: " + coffee.getCost());
        System.out.println("Description: " + coffee.getDescription());
    }
}

在这个例子中,我们定义了一个咖啡接口 Coffee 和一个具体实现类 SimpleCoffee,它表示一杯简单的咖啡。然后,我们定义了一个装饰器抽象类 CoffeeDecorator,它包含一个咖啡成员变量,并实现了咖啡接口的方法。最后,我们定义了两个具体装饰器实现类 MilkDecorator 和 SyrupDecorator,它们分别表示加牛奶和加糖浆的咖啡。在客户端代码中,我们创建了一杯简单的咖啡,并使用装饰器分别加上牛奶和糖浆,最后输出咖啡的价格和描述。

9.组合模式实战

在这个案例中,我们将使用组合模式创建一个简单的组织结构图,包括部门和员工两种节点类型。具体实现如下:

// 组织结构图节点接口
public interface Node {
    String getName();
    void print();
}

// 部门节点实现类
public class Department implements Node {
    private String name;
    private List<Node> children = new ArrayList<>();

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

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

    public void add(Node node) {
        children.add(node);
    }

    public void remove(Node node) {
        children.remove(node);
    }

    @Override
    public void print() {
        System.out.println("Department: " + name);
        for (Node node : children) {
            node.print();
        }
    }
}

// 员工节点实现类
public class Employee implements Node {
    private String name;

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

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

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

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Department engineering = new Department("Engineering");
        Department sales = new Department("Sales");

        Employee alice = new Employee("Alice");
        Employee bob = new Employee("Bob");
        Employee charlie = new Employee("Charlie");
        Employee dave = new Employee("Dave");

        engineering.add(alice);
        engineering.add(bob);
        sales.add(charlie);
        sales.add(dave);

        Department company = new Department("Company");
        company.add(engineering);
        company.add(sales);

        company.print();
    }
}

在这个例子中,我们定义了一个组织结构图节点接口 Node 和两个具体实现类 Department 和 Employee,分别表示部门和员工节点。部门节点包含一个名称和一个子节点列表,可以添加、删除和打印子节点。员工节点只包含一个名称,可以打印自己。在客户端代码中,我们创建了一个公司节点,并添加了两个部门节点和四个员工节点,最后打印整个组织结构图。

10.外观模式实战

在这个案例中,我们将使用外观模式创建一个简单的家庭影院系统,包括投影仪、音响和 DVD 播放器三个子系统。具体实现如下:

// 投影仪子系统
public class Projector {
    public void on() {
        System.out.println("Projector is on");
    }

    public void off() {
        System.out.println("Projector is off");
    }

    public void setInput(String input) {
        System.out.println("Setting input to " + input);
    }
}

// 音响子系统
public class Amplifier {
    public void on() {
        System.out.println("Amplifier is on");
    }

    public void off() {
        System.out.println("Amplifier is off");
    }

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

// DVD 播放器子系统
public class DvdPlayer {
    public void on() {
        System.out.println("DVD player is on");
    }

    public void off() {
        System.out.println("DVD player is off");
    }

    public void play(String movie) {
        System.out.println("Playing movie " + movie);
    }
}

// 家庭影院外观类
public class HomeTheaterFacade {
    private Projector projector;
    private Amplifier amplifier;
    private DvdPlayer dvdPlayer;

    public HomeTheaterFacade(Projector projector, Amplifier amplifier, DvdPlayer dvdPlayer) {
        this.projector = projector;
        this.amplifier = amplifier;
        this.dvdPlayer = dvdPlayer;
    }

    public void watchMovie(String movie) {
        System.out.println("Get ready to watch a movie...");
        projector.on();
        amplifier.on();
        dvdPlayer.on();
        dvdPlayer.play(movie);
    }

    public void endMovie() {
        System.out.println("Shutting down the movie theater...");
        projector.off();
        amplifier.off();
        dvdPlayer.off();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Projector projector = new Projector();
        Amplifier amplifier = new Amplifier();
        DvdPlayer dvdPlayer = new DvdPlayer();

        HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(projector, amplifier, dvdPlayer);
        homeTheaterFacade.watchMovie("The Shawshank Redemption");
        homeTheaterFacade.endMovie();
    }
}

在这个例子中,我们定义了三个子系统类 Projector、Amplifier 和 DvdPlayer,分别表示投影仪、音响和 DVD 播放器。然后,我们定义了一个家庭影院外观类 HomeTheaterFacade,它包含三个子系统成员变量,并提供了两个方法 watchMovie 和 endMovie,分别表示开始和结束观看电影。在客户端代码中,我们创建了三个子系统对象和一个家庭影院外观对象,并使用外观对象观看了一部电影,最后结束观影。

11.享元模式实战

在这个案例中,我们将使用享元模式创建一个简单的棋盘游戏,包括黑白两种棋子和一个棋盘。具体实现如下:

// 棋子接口
public interface ChessPiece {
    void setColor(String color);
    String getColor();
    void setPosition(int x, int y);
    int[] getPosition();
    void move(int x, int y);
}

// 棋子实现类
public class ChessPieceImpl implements ChessPiece {
    private String color;
    private int x;
    private int y;

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

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

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

    @Override
    public void setPosition(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int[] getPosition() {
        return new int[] {x, y};
    }

    @Override
    public void move(int x, int y) {
        System.out.println("Moving " + color + " chess piece to (" + x + ", " + y + ")");
        setPosition(x, y);
    }
}

// 棋盘类
public class ChessBoard {
    private Map<String, ChessPiece> pieces = new HashMap<>();

    public ChessBoard() {
        pieces.put("black", new ChessPieceImpl("black"));
        pieces.put("white", new ChessPieceImpl("white"));
    }

    public void move(String color, int x, int y) {
        pieces.get(color).move(x, y);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ChessBoard chessBoard = new ChessBoard();
        chessBoard.move("black", 1, 1);
        chessBoard.move("white", 2, 2);
        chessBoard.move("black", 3, 3);
        chessBoard.move("white", 4, 4);
    }
}

在这个例子中,我们定义了一个棋子接口 ChessPiece 和一个具体实现类 ChessPieceImpl,它包含颜色、位置和移动方法。然后,我们定义了一个棋盘类 ChessBoard,它包含一个棋子映射 pieces,并提供了一个移动棋子的方法 move。在客户端代码中,我们创建了一个棋盘对象,并使用它移动了四个棋子。由于棋子是享元模式的应用,所以我们只需要创建两个棋子对象,即可在棋盘上任意移动。

12.代理模式实战

在这个案例中,我们将使用代理模式创建一个简单的图片浏览器,包括图片和代理两种对象。具体实现如下:

// 图片接口
public interface Image {
    void display();
}

// 真实图片类
public class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk();
    }

    @Override
    public void display() {
        System.out.println("Displaying " + fileName);
    }

    private void loadFromDisk() {
        System.out.println("Loading " + fileName + " from disk");
    }
}

// 图片代理类
public class ImageProxy implements Image {
    private String fileName;
    private RealImage realImage;

    public ImageProxy(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(fileName);
        }
        realImage.display();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Image image = new ImageProxy("test.jpg");
        image.display();
    }
}

在这个例子中,我们定义了一个图片接口 Image 和一个真实图片类 RealImage,它包含了图片的文件名和加载图片的方法,并实现了显示图片的方法。然后,我们定义了一个图片代理类 ImageProxy,它包含了图片的文件名和真实图片对象 realImage,并实现了显示图片的方法。在客户端代码中,我们创建了一个图片代理对象,并调用了它的显示方法。由于图片代理是代理模式的应用,所以我们可以通过它来控制真实图片的访问,并在需要时才加载真实图片,从而提高程序的性能。

三、行为型模式

13.模板方法模式实战

在实际应用中,模板方法模式可以用于定义一系列算法的骨架,让子类实现具体的算法细节,例如在一个游戏中,需要实现不同类型的角色升级算法,可以使用模板方法模式来实现。

具体实现如下:

// 角色抽象类
public abstract class Role {
    // 定义升级算法的骨架
    public final void levelUp() {
        System.out.println("Current level: " + getLevel());
        System.out.println("Experience: " + getExperience());
        addExperience();
        System.out.println("Experience after adding: " + getExperience());
        if (isLevelUp()) {
            levelUpMessage();
            levelUpAction();
        } else {
            System.out.println("Not enough experience to level up");
        }
    }

    // 获取角色等级
    protected abstract int getLevel();

    // 获取角色经验值
    protected abstract int getExperience();

    // 添加经验值
    protected abstract void addExperience();

    // 判断是否可以升级
    protected abstract boolean isLevelUp();

    // 显示升级信息
    protected void levelUpMessage() {
        System.out.println("Congratulations! Level up!");
    }

    // 升级后的动作
    protected abstract void levelUpAction();
}

// 战士类
public class Warrior extends Role {
    private int level = 1;
    private int experience = 0;

    @Override
    protected int getLevel() {
        return level;
    }

    @Override
    protected int getExperience() {
        return experience;
    }

    @Override
    protected void addExperience() {
        experience += 10;
    }

    @Override
    protected boolean isLevelUp() {
        return experience >= level * 100;
    }

    @Override
    protected void levelUpAction() {
        System.out.println("Warrior learned a new skill!");
    }
}

// 法师类
public class Mage extends Role {
    private int level = 1;
    private int experience = 0;

    @Override
    protected int getLevel() {
        return level;
    }

    @Override
    protected int getExperience() {
        return experience;
    }

    @Override
    protected void addExperience() {
        experience += 20;
    }

    @Override
    protected boolean isLevelUp() {
        return experience >= level * 200;
    }

    @Override
    protected void levelUpAction() {
        System.out.println("Mage learned a new spell!");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role warrior = new Warrior();
        warrior.levelUp();

        Role mage = new Mage();
        mage.levelUp();
    }
}

在这个例子中,我们定义了一个角色抽象类 Role,它定义了升级算法的骨架,包括获取角色等级和经验值、添加经验值、判断是否可以升级、显示升级信息和升级后的动作。然后,我们定义了两个具体角色类 Warrior 和 Mage,它们分别实现了角色的具体算法细节。在客户端代码中,我们创建了一个战士对象和一个法师对象,并分别调用它们的升级方法,输出升级信息。由于模板方法模式是将算法的骨架定义在抽象类中,具体算法细节由子类实现,所以我们可以通过它来实现程序的灵活性和可扩展性。

14.命令模式实战

在实际应用中,命令模式可以用于将请求封装成对象,从而使得可以将请求的发送者和接收者解耦,例如在一个游戏中,需要实现不同类型的角色使用不同的技能,可以使用命令模式来实现。

具体实现如下:

// 技能接口
public interface Skill {
    void use();
}

// 战士技能类
public class WarriorSkill implements Skill {
    @Override
    public void use() {
        System.out.println("Warrior uses skill: Charge!");
    }
}

// 法师技能类
public class MageSkill implements Skill {
    @Override
    public void use() {
        System.out.println("Mage uses skill: Fireball!");
    }
}

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

// 使用技能命令类
public class UseSkillCommand implements Command {
    private Skill skill;

    public UseSkillCommand(Skill skill) {
        this.skill = skill;
    }

    @Override
    public void execute() {
        skill.use();
    }
}

// 角色类
public class Role {
    private Command command;

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

    public void useSkill() {
        command.execute();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role warrior = new Role();
        Skill warriorSkill = new WarriorSkill();
        Command warriorCommand = new UseSkillCommand(warriorSkill);
        warrior.setCommand(warriorCommand);
        warrior.useSkill();

        Role mage = new Role();
        Skill mageSkill = new MageSkill();
        Command mageCommand = new UseSkillCommand(mageSkill);
        mage.setCommand(mageCommand);
        mage.useSkill();
    }
}

在这个例子中,我们定义了一个技能接口 Skill 和两个具体技能类 WarriorSkill 和 MageSkill,它们分别实现了使用技能的方法。然后,我们定义了一个命令接口 Command 和一个具体命令类 UseSkillCommand,它们分别定义了执行命令的方法。在角色类 Role 中,我们定义了一个命令对象,并提供了设置命令和使用技能的方法。在客户端代码中,我们创建了一个战士对象和一个法师对象,并分别创建了对应的技能对象和命令对象,最后将命令对象设置给角色对象,并调用使用技能的方法。由于命令模式是将请求封装成对象,从而使得可以将请求的发送者和接收者解耦,所以我们可以通过它来实现程序的灵活性和可扩展性。

15.访问者模式实战

在实际应用中,访问者模式可以用于对一组对象进行操作,而不需要修改这些对象的类定义,例如在一个游戏中,需要实现不同类型的角色进行不同的操作,可以使用访问者模式来实现。

具体实现如下:

// 角色接口
public interface Role {
    void accept(Visitor visitor);
}

// 战士类
public class Warrior implements Role {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public void attack() {
        System.out.println("Warrior attacks!");
    }
}

// 法师类
public class Mage implements Role {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public void castSpell() {
        System.out.println("Mage casts spell!");
    }
}

// 访问者接口
public interface Visitor {
    void visit(Warrior warrior);
    void visit(Mage mage);
}

// 攻击访问者类
public class AttackVisitor implements Visitor {
    @Override
    public void visit(Warrior warrior) {
        warrior.attack();
    }

    @Override
    public void visit(Mage mage) {
        System.out.println("Mage cannot attack!");
    }
}

// 施法访问者类
public class CastSpellVisitor implements Visitor {
    @Override
    public void visit(Warrior warrior) {
        System.out.println("Warrior cannot cast spell!");
    }

    @Override
    public void visit(Mage mage) {
        mage.castSpell();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role warrior = new Warrior();
        Role mage = new Mage();

        Visitor attackVisitor = new AttackVisitor();
        Visitor castSpellVisitor = new CastSpellVisitor();

        warrior.accept(attackVisitor);
        warrior.accept(castSpellVisitor);

        mage.accept(attackVisitor);
        mage.accept(castSpellVisitor);
    }
}

在这个例子中,我们定义了一个角色接口 Role 和两个具体角色类 Warrior 和 Mage,它们分别实现了接受访问者的方法。同时,我们定义了一个访问者接口 Visitor 和两个具体访问者类 AttackVisitor 和 CastSpellVisitor,它们分别实现了对不同类型角色的不同操作。在客户端代码中,我们创建了一个战士对象和一个法师对象,并创建了对应的攻击访问者和施法访问者对象,最后将访问者对象传递给角色对象,调用接受访问者的方法。由于访问者模式是对一组对象进行操作,而不需要修改这些对象的类定义,所以我们可以通过它来实现程序的灵活性和可扩展性。

16.迭代器模式实战

在实际应用中,迭代器模式可以用于遍历一个集合对象,而不需要暴露其内部结构,例如在一个游戏中,需要实现遍历不同类型的角色,可以使用迭代器模式来实现。

具体实现如下:

// 角色类
public class Role {
    private String name;

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

    public String getName() {
        return name;
    }
}

// 角色集合类
public class RoleCollection implements Iterable<Role> {
    private List<Role> roles = new ArrayList<>();

    public void addRole(Role role) {
        roles.add(role);
    }

    public void removeRole(Role role) {
        roles.remove(role);
    }

    @Override
    public Iterator<Role> iterator() {
        return new RoleIterator();
    }

    // 角色迭代器类
    private class RoleIterator implements Iterator<Role> {
        private int index = 0;

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

        @Override
        public Role next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            Role role = roles.get(index);
            index++;
            return role;
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        RoleCollection roleCollection = new RoleCollection();
        roleCollection.addRole(new Role("Warrior"));
        roleCollection.addRole(new Role("Mage"));

        for (Role role : roleCollection) {
            System.out.println("Role: " + role.getName());
        }
    }
}

在这个例子中,我们定义了一个角色类 Role 和一个角色集合类 RoleCollection,它实现了 Iterable 接口,从而可以使用 foreach 循环遍历。在角色集合类中,我们定义了一个角色迭代器类 RoleIterator,它实现了 Iterator 接口,从而可以使用 hasNext 和 next 方法遍历角色集合。在客户端代码中,我们创建了一个角色集合对象,并添加了两个角色对象,最后使用 foreach 循环遍历角色集合,输出角色名字。由于迭代器模式可以遍历一个集合对象,而不需要暴露其内部结构,所以我们可以通过它来实现程序的灵活性和可扩展性。

17.观察者模式实战

观察者模式实战:

在实际应用中,观察者模式可以用于实现对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新,例如在一个游戏中,需要实现角色受到攻击时,其他角色也能收到通知,可以使用观察者模式来实现。

具体实现如下:

// 观察者接口
public interface Observer {
    void update(String message);
}

// 观察者实现类
public class Player implements Observer {
    private String name;

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

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

// 被观察者接口
public interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers(String message);
}

// 被观察者实现类
public class Game implements Subject {
    private List<Observer> observers = new ArrayList<>();

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

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

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void attack() {
        System.out.println("Player is attacking!");
        notifyObservers("Player is attacking!");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Game game = new Game();

        Player player1 = new Player("Player 1");
        Player player2 = new Player("Player 2");
        Player player3 = new Player("Player 3");

        game.attach(player1);
        game.attach(player2);
        game.attach(player3);

        game.attack();

        game.detach(player2);

        game.attack();
    }
}

在这个例子中,我们定义了一个观察者接口 Observer 和一个观察者实现类 Player,它实现了更新方法。同时,我们定义了一个被观察者接口 Subject 和一个被观察者实现类 Game,它实现了添加、删除和通知观察者的方法。在客户端代码中,我们创建了一个游戏对象和三个玩家对象,并将玩家对象注册为游戏对象的观察者,然后调用游戏对象的攻击方法,观察者们都会收到通知。最后,我们将一个玩家对象从观察者列表中删除,再次调用攻击方法,只有两个观察者会收到通知。由于观察者模式可以实现对象之间的一对多依赖关系,所以我们可以通过它来实现程序的灵活性和可扩展性。

18.中介者模式实战

在实际应用中,中介者模式可以用于减少对象之间的直接耦合,将对象之间的交互转移到中介者对象中,例如在一个游戏中,需要实现不同类型的角色之间的交互,可以使用中介者模式来实现。

具体实现如下:

// 中介者接口
public interface Mediator {
    void send(String message, Role role);
}

// 具体中介者类
public class GameMediator implements Mediator {
    private List<Role> roles = new ArrayList<>();

    @Override
    public void send(String message, Role role) {
        for (Role r : roles) {
            if (r != role) {
                r.receive(message);
            }
        }
    }

    public void addRole(Role role) {
        roles.add(role);
    }
}

// 角色类
public abstract class Role {
    protected Mediator mediator;

    public Role(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void send(String message);

    public abstract void receive(String message);
}

// 具体角色类
public class Warrior extends Role {
    public Warrior(Mediator mediator) {
        super(mediator);
    }

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

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

public class Mage extends Role {
    public Mage(Mediator mediator) {
        super(mediator);
    }

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

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

// 客户端代码
public class Client {
    public static void main(String[] args) {
        GameMediator mediator = new GameMediator();

        Role warrior = new Warrior(mediator);
        Role mage = new Mage(mediator);

        mediator.addRole(warrior);
        mediator.addRole(mage);

        warrior.send("Attack!");
        mage.send("Cast spell!");
    }
}

在这个例子中,我们定义了一个中介者接口 Mediator 和一个具体中介者类 GameMediator,它实现了发送消息的方法,并维护了一个角色列表。同时,我们定义了一个角色类 Role 和两个具体角色类 Warrior 和 Mage,它们实现了发送和接收消息的方法。在客户端代码中,我们创建了一个中介者对象和两个角色对象,并将角色对象注册到中介者对象中,然后调用角色对象的发送消息方法,中介者对象会将消息发送给其他角色对象。由于中介者模式可以减少对象之间的直接耦合,所以我们可以通过它来实现程序的灵活性和可扩展性。

19.备忘录模式实战

在实际应用中,备忘录模式可以用于保存和恢复对象的状态,例如在一个游戏中,需要实现保存和恢复角色的状态,可以使用备忘录模式来实现。

具体实现如下:

// 备忘录类
public class Memento {
    private int level;

    public Memento(int level) {
        this.level = level;
    }

    public int getLevel() {
        return level;
    }
}

// 角色类
public class Role {
    private int level;

    public Role(int level) {
        this.level = level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public Memento save() {
        return new Memento(level);
    }

    public void restore(Memento memento) {
        level = memento.getLevel();
    }

    public void display() {
        System.out.println("Level: " + level);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role role = new Role(1);
        role.display();

        Memento memento = role.save();

        role.setLevel(2);
        role.display();

        role.restore(memento);
        role.display();
    }
}

在这个例子中,我们定义了一个备忘录类 Memento 和一个角色类 Role,它实现了保存和恢复状态的方法。在客户端代码中,我们创建了一个角色对象,并调用 display 方法显示当前等级。然后,我们保存当前状态到备忘录对象中,将等级设置为 2,并再次调用 display 方法显示当前等级。最后,我们将备忘录对象传递给角色对象的恢复方法,将等级恢复到之前保存的状态,并再次调用 display 方法显示当前等级。由于备忘录模式可以保存和恢复对象的状态,所以我们可以通过它来实现程序的灵活性和可扩展性。

20.解释器模式实战

在实际应用中,解释器模式可以用于解析和执行一些特定的语法规则,例如在一个游戏中,需要实现解析和执行一些特定的指令,可以使用解释器模式来实现。

具体实现如下:

// 抽象表达式类
public interface Expression {
    int interpret();
}

// 数字表达式类
public class NumberExpression implements Expression {
    private int number;

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

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

// 加法表达式类
public 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();
    }
}

// 减法表达式类
public class SubExpression implements Expression {
    private Expression left;
    private Expression right;

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

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

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Expression expression = new SubExpression(
                new AddExpression(new NumberExpression(10), new NumberExpression(5)),
                new NumberExpression(3)
        );
        System.out.println(expression.interpret());
    }
}

在这个例子中,我们定义了一个抽象表达式类 Expression 和三个具体表达式类 NumberExpression、AddExpression 和 SubExpression,它们实现了解释和执行表达式的方法。在客户端代码中,我们创建了一个表达式对象,并使用加法和减法表达式组合成一个复杂的表达式,最后调用 interpret 方法执行表达式并输出结果。由于解释器模式可以解析和执行一些特定的语法规则,所以我们可以通过它来实现程序的灵活性和可扩展性。

21.策略模式实战

在实际应用中,策略模式可以用于实现不同的算法或行为,使得它们可以相互替换,例如在一个游戏中,需要实现不同类型的攻击方式,可以使用策略模式来实现。

具体实现如下:

// 攻击策略接口
public interface AttackStrategy {
    void attack();
}

// 近战攻击策略类
public class MeleeAttackStrategy implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("Melee attack!");
    }
}

// 远程攻击策略类
public class RangedAttackStrategy implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("Ranged attack!");
    }
}

// 角色类
public class Role {
    private AttackStrategy attackStrategy;

    public void setAttackStrategy(AttackStrategy attackStrategy) {
        this.attackStrategy = attackStrategy;
    }

    public void attack() {
        attackStrategy.attack();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role warrior = new Role();
        warrior.setAttackStrategy(new MeleeAttackStrategy());
        warrior.attack();
        Role mage = new Role();
        mage.setAttackStrategy(new RangedAttackStrategy());
        mage.attack();
    }
}
在这个例子中,我们定义了一个攻击策略接口 AttackStrategy 和两个具体攻击策略类 MeleeAttackStrategy 和 RangedAttackStrategy,它们实现了不同的攻击方式。同时,我们定义了一个角色类 Role,它包含一个攻击策略对象,并实现了攻击方法。在客户端代码中,我们创建了两个角色对象,并分别设置不同的攻击策略,最后调用攻击方法执行攻击。由于策略模式可以实现不同的算法或行为,使得它们可以相互替换,所以我们可以通过它来实现程序的灵活性和可扩展性。

命令模式实战:

在实际应用中,命令模式可以用于将请求封装成对象,使得可以将请求的发送者和接收者解耦,例如在一个游戏中,需要实现将不同类型的指令封装成对象,可以使用命令模式来实现。

具体实现如下:

```java
// 命令接口
public interface Command {
    void execute();
}

// 具体命令类
public class AttackCommand implements Command {
    private Role role;

    public AttackCommand(Role role) {
        this.role = role;
    }

    @Override
    public void execute() {
        role.attack();
    }
}

// 角色类
public class Role {
    public void attack() {
        System.out.println("Attack!");
    }
}

// 命令调用者类
public class Invoker {
    private Command command;

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

    public void executeCommand() {
        command.execute();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role role = new Role();
        Command command = new AttackCommand(role);
        Invoker invoker = new Invoker();
        invoker.setCommand(command);
        invoker.executeCommand();
    }
}

在这个例子中,我们定义了一个攻击策略接口 AttackStrategy 和两个具体攻击策略类 MeleeAttackStrategy 和 RangedAttackStrategy,它们实现了不同的攻击方式。同时,我们定义了一个角色类 Role,它包含一个攻击策略对象,并实现了攻击方法。在客户端代码中,我们创建了两个角色对象,并分别设置不同的攻击策略,最后调用攻击方法执行攻击。由于策略模式可以实现不同的算法或行为,使得它们可以相互替换,所以我们可以通过它来实现程序的灵活性和可扩展性。 

22.命令模式实战

在实际应用中,命令模式可以用于将请求封装成对象,使得可以将请求的发送者和接收者解耦,例如在一个游戏中,需要实现将不同类型的指令封装成对象,可以使用命令模式来实现。

具体实现如下:

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

// 具体命令类
public class AttackCommand implements Command {
    private Role role;

    public AttackCommand(Role role) {
        this.role = role;
    }

    @Override
    public void execute() {
        role.attack();
    }
}

// 角色类
public class Role {
    public void attack() {
        System.out.println("Attack!");
    }
}

// 命令调用者类
public class Invoker {
    private Command command;

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

    public void executeCommand() {
        command.execute();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Role role = new Role();
        Command command = new AttackCommand(role);
        Invoker invoker = new Invoker();
        invoker.setCommand(command);
        invoker.executeCommand();
    }
}

在这个例子中,我们定义了一个命令接口 Command 和一个具体命令类 AttackCommand,它实现了执行攻击的方法。同时,我们定义了一个角色类 Role,它包含了攻击方法。在命令调用者类 Invoker 中,我们设置了一个命令对象,并实现了执行命令的方法。在客户端代码中,我们创建了一个角色对象和一个命令对象,并将命令对象设置到命令调用者对象中,最后调用命令调用者对象的执行命令方法。由于命令模式可以将请求封装成对象,使得可以将请求的发送者和接收者解耦,所以我们可以通过它来实现程序的灵活性和可扩展性。

23.职责链模式实战

在这个案例中,我们将使用职责链模式创建一个简单的请假审批流程,包括请假申请和审批人两种对象。具体实现如下:

// 请假申请类
public class LeaveRequest {
    private String name;
    private int days;

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

    public String getName() {
        return name;
    }

    public int getDays() {
        return days;
    }
}

// 审批人抽象类
public abstract class Approver {
    protected Approver successor;

    public void setSuccessor(Approver successor) {
        this.successor = successor;
    }

    public abstract void processRequest(LeaveRequest request);
}

// 经理类
public class Manager extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getDays() <= 3) {
            System.out.println("Manager approves the leave request of " + request.getName() + " for " + request.getDays() + " days");
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

// 总监类
public class Director extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getDays() <= 5) {
            System.out.println("Director approves the leave request of " + request.getName() + " for " + request.getDays() + " days");
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

// CEO 类
public class CEO extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getDays() <= 7) {
            System.out.println("CEO approves the leave request of " + request.getName() + " for " + request.getDays() + " days");
        } else {
            System.out.println("Leave request of " + request.getName() + " for " + request.getDays() + " days is rejected");
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Approver manager = new Manager();
        Approver director = new Director();
        Approver ceo = new CEO();

        manager.setSuccessor(director);
        director.setSuccessor(ceo);

        LeaveRequest request1 = new LeaveRequest("Alice", 2);
        manager.processRequest(request1);

        LeaveRequest request2 = new LeaveRequest("Bob", 5);
        manager.processRequest(request2);

        LeaveRequest request3 = new LeaveRequest("Charlie", 10);
        manager.processRequest(request3);
    }
}

在这个例子中,我们定义了一个请假申请类 LeaveRequest 和一个审批人抽象类 Approver,它包含了后继审批人 successor 和处理请假申请的方法 processRequest。然后,我们定义了三个具体审批人类 Manager、Director 和 CEO,并实现了它们各自的处理方法。在客户端代码中,我们创建了三个审批人对象,并将它们串成一条审批链,然后创建了三个请假申请对象,并依次提交给经理进行处理。由于审批人是职责链模式的应用,所以我们可以通过它来实现请求的传递和处理,从而简化程序的设计和维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/24180.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【十字绣】传统手艺-微信小程序开发流程详解

还记得小时候看过母亲的十字绣吗&#xff0c;易学易懂&#xff0c;就是用专用的绣线和十字格布&#xff0c;通过平面坐标计找出位置&#xff0c;对照专用的图案进行刺绣&#xff0c;可作出心中所想的画&#xff0c;奈何所需材料成本不小&#xff0c;这里用小程序简单模拟十字绣…

使用object.defineProperty来更新数据示例

Object.defineProperty() 方法会直接在一个对象上定义一个新属性&#xff0c;或者修改一个对象的现有属性&#xff0c;并返回此对象。 Object.defineProperty&#xff08;&#xff09;可以为对象的属性添加特性&#xff0c;每一个被添加过的属性&#xff0c;都会拥有属于自己的…

【C++初阶】C++——模板初阶与泛型编程

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 1. 泛型编程2. 函数模板…

C Primer Plus第四章编程练习答案

学完C语言之后&#xff0c;我就去阅读《C Primer Plus》这本经典的C语言书籍&#xff0c;对每一章的编程练习题都做了相关的解答&#xff0c;仅仅代表着我个人的解答思路&#xff0c;如有错误&#xff0c;请各位大佬帮忙点出&#xff01; 1.编写一个程序&#xff0c;提示用户输…

自学网络安全最细规划(建议收藏)

01 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

自古以来,反射也是兵家必争之地

成文耗时1小时&#xff0c;阅读5min&#xff0c;有用指数5颗星。 这几天收到一个战术性需求&#xff0c;将一大坨字段序列化为特定格式的字符串。 大概是下表&#xff1a; 序号字段名描述是否必填0logVersion日志版本是1productName产品是2serviceName服务是.........25extend3…

8项seo的日常工作

SEO的日常工作涵盖了一系列任务和活动&#xff0c;旨在优化网站以提高在搜索引擎中的排名和可见性。 以下是SEO的日常工作内容&#xff1a; 关键词研究和优化&#xff1a;定期进行关键词研究&#xff0c;寻找与目标受众和业务相关的热门关键词。优化网站内容、标题、元描述和链…

这些脑洞大开的论文标题,也太有创意了O(∩_∩)O

microRNAs啊microRNAs&#xff0c;谁是世界上最致命的髓母细胞瘤microRNAs&#xff1f; 这个标题很容易让人联想到白雪公主后妈说的那句话&#xff1a;Mirror mirror on the wall, who is the fairest of them all? 02 一氧化碳&#xff1a;勇踏NO未至之境 NO 指 nitric oxide…

合并两个有序链表(java)

leetcode 21题&#xff1a;合并两个有序链表 题目描述解题思路&#xff1a;链表的其它题型。 题目描述 leetcode21题&#xff1a;合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例&#xff1a; 输入&…

MySQL 数值函数

文章目录 数值函数1. abs(num)2. ceil(num)3. floor(num)4. mod(num1,num2)5. rand()6. round(num,n)7. truncate(num,n)8. sqrt(num) 数值函数 数值函数用来处理数值方面的运算&#xff0c;能够提高用户的工作效率。常用的数值函数如下表所示&#xff0c;函数括号内为输入的参…

四足机器人A1目标跟踪

四足机器人A1目标跟踪 前期准备工作1.安装TeamViewer2.将四足机器人所有线连接好3.将四足机器人调至运动模式 运行流程1.开机阶段2.运行阶段 效果展示代码配置 前期准备工作 1.安装TeamViewer 由于外接屏幕损坏&#xff0c;故四足机器人内部配置了TeamViewer&#xff0c;因此…

【Linux】线程同步

文章目录 条件变量相关函数初始化条件变量-pthread_cond_init销毁条件变量-pthread_cond_destroy等待条件变量-pthread_cond_wait唤醒等待条件变量pthread_cond_broadcastpthread_cond_signal 小例子关于等待函数的补充条件变量使用规范 条件变量相关函数 初始化条件变量-pthr…

如何让自动化测试框架更自动化?

一、引言 ​对于大厂的同学来说&#xff0c;接口自动化是个老生常谈的话题了&#xff0c;毕竟每年的MTSC大会议题都已经能佐证了&#xff0c;不是大数据测试&#xff0c;就是AI测试等等&#xff08;越来越高大上了&#xff09;。不可否认这些专项的方向是质量智能化发展的方向&…

IMX6ULL裸机篇之IIC协议

一. IIC实验简介 I2C 是最常用的通信接口&#xff0c;众多的传感器都会提供 I2C 接口来和主控相连。 比如摄像头、 加速度计、触摸屏等。 I.MX6U-ALPHA开发板 使用 I2C1 接口连接了一个距离传感器 AP3216C &#xff0c;本章我们就来学习如何使用 I.MX6U 的 I2C 接口…

【JavaSE】Java基础语法(十):构造方法

文章目录 ⛄1. 构造方法的格式和执行时机⛄2. 构造方法的作用⛄3. 构造方法的特点⛄4. 构造方法的注意事项⛄5. 构造方法为什么不能被重写 在面向对象编程的思想中&#xff0c;构造方法&#xff08;Constructor&#xff09;是一个特殊的函数&#xff0c;用于创建和初始化类的对…

华为OD机试之模拟商场优惠打折(Java源码)

模拟商场优惠打折 题目描述 模拟商场优惠打折&#xff0c;有三种优惠券可以用&#xff0c;满减券、打折券和无门槛券。 满减券&#xff1a;满100减10&#xff0c;满200减20&#xff0c;满300减30&#xff0c;满400减40&#xff0c;以此类推不限制使用&#xff1b; 打折券&…

GoWeb -- gin框架的入门和使用

认识gin go流行的web框架 go从诞生之初就带有浓重的开源属性&#xff0c;其原生库已经很强大&#xff0c;即使不依赖框架&#xff0c;也能进行高性能开发&#xff0c;又因为其语言并没有一定的设计标准&#xff0c;所以较为灵活&#xff0c;也就诞生了众多的框架&#xff0c;各…

视频怎么加水印?如何录制带水印的视频?

案例&#xff1a;如何给视频添加水印&#xff1f; 【我发布在短视频平台的视频&#xff0c;总是被别人盗用&#xff0c;我想给自己的视频添加水印。有没有视频添加水印的方法&#xff1f;在线等&#xff01;】 很多视频制作者或者爱好者&#xff0c;都希望自己的视频作品得到…

腾讯云轻量服务器镜像安装宝塔Linux面板怎么使用?

腾讯云轻量应用服务器宝塔面板怎么用&#xff1f;轻量应用服务器如何安装宝塔面板&#xff1f;在镜像中选择宝塔Linux面板腾讯云专享版&#xff0c;在轻量服务器防火墙中开启8888端口号&#xff0c;然后远程连接到轻量服务器执行宝塔面板账号密码查询命令&#xff0c;最后登录和…

【P31】JMeter 循环控制器(Loop Controller)

这文章目录 一、循环控制器&#xff08;Loop Controller&#xff09;参数说明二、测试计划设计2.1、设置循环次数2.2、勾选永远2.3、设置线程组的持续时间 一、循环控制器&#xff08;Loop Controller&#xff09;参数说明 可以对部分逻辑按常量进行循环迭代 选择线程组右键 …
最新文章