【设计模式】行为型模式(二):策略模式、命令模式

设计模式之行为型模式》系列,共包含以下文章:

😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!

3.策略模式(Strategy)

策略模式Strategy)是一种行为设计模式,它使你能在运行时改变对象的行为。下面是策略模式的几个关键点:

  • 定义一组算法:策略模式定义了一组可互换的算法(或行为)。这些算法封装在独立的类中,每个类实现一个特定的算法。
  • 封装变化:将变化的部分从不变的部分中分离出来,封装成独立的类,这样可以更容易地扩展和维护。
  • 运行时选择算法:客户端可以根据需要在运行时选择不同的算法(策略)来执行特定任务。

3.1 示例

假设你正在开发一个电商系统,需要根据不同的促销策略计算订单的最终价格。你可以定义一个 PromotionStrategy 接口,然后为不同的促销策略实现该接口,例如:

  • FixedDiscountStrategy:固定金额折扣
  • PercentageDiscountStrategy:百分比折扣
  • NoDiscountStrategy:无折扣

在订单类中,你可以使用 PromotionStrategy 接口来计算最终价格,并在运行时根据需要选择不同的策略。

3.1.1 定义策略接口

首先,定义一个策略接口 PromotionStrategy,该接口声明了一个计算折扣价格的方法 calculateDiscount

public interface PromotionStrategy {
    double calculateDiscount(double originalPrice);
}

3.1.2 实现具体策略

接下来,实现不同的促销策略,例如 固定金额折扣百分比折扣无折扣

public class FixedDiscountStrategy implements PromotionStrategy {
    private double discountAmount;

    public FixedDiscountStrategy(double discountAmount) {
        this.discountAmount = discountAmount;
    }

    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice - discountAmount;
    }
}

public class PercentageDiscountStrategy implements PromotionStrategy {
    private double discountRate;

    public PercentageDiscountStrategy(double discountRate) {
        this.discountRate = discountRate;
    }

    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice * (1 - discountRate);
    }
}

public class NoDiscountStrategy implements PromotionStrategy {
    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice;
    }
}

FixedDiscountStrategyPercentageDiscountStrategyNoDiscountStrategy 实现了 PromotionStrategy 接口,分别实现了固定金额折扣、百分比折扣和无折扣。

3.1.3 定义上下文类

上下文类 Order 使用 PromotionStrategy 接口来计算最终价格。上下文类可以在运行时选择不同的策略。

public class Order {
    private double originalPrice;
    private PromotionStrategy promotionStrategy;

    public Order(double originalPrice, PromotionStrategy promotionStrategy) {
        this.originalPrice = originalPrice;
        this.promotionStrategy = promotionStrategy;
    }

    public double getFinalPrice() {
        return promotionStrategy.calculateDiscount(originalPrice);
    }

    public void setPromotionStrategy(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }
}

3.1.4 客户端代码

客户端代码可以根据需要选择不同的促销策略,并计算订单的最终价格。

public class Client {
    public static void main(String[] args) {
        double originalPrice = 100.0;

        // 固定金额折扣
        PromotionStrategy fixedDiscountStrategy = new FixedDiscountStrategy(10.0);
        Order order1 = new Order(originalPrice, fixedDiscountStrategy);
        System.out.println("Fixed Discount: " + order1.getFinalPrice());

        // 百分比折扣
        PromotionStrategy percentageDiscountStrategy = new PercentageDiscountStrategy(0.2);
        Order order2 = new Order(originalPrice, percentageDiscountStrategy);
        System.out.println("Percentage Discount: " + order2.getFinalPrice());

        // 无折扣
        PromotionStrategy noDiscountStrategy = new NoDiscountStrategy();
        Order order3 = new Order(originalPrice, noDiscountStrategy);
        System.out.println("No Discount: " + order3.getFinalPrice());

        // 动态更改策略
        order1.setPromotionStrategy(percentageDiscountStrategy);
        System.out.println("Changed to Percentage Discount: " + order1.getFinalPrice());
    }
}

客户端代码创建不同的策略对象,并将它们传递给 Order 对象,计算最终价格。还可以在运行时动态更改策略。

3.1.5 输出结果

Fixed Discount: 90.0
Percentage Discount: 80.0
No Discount: 100.0
Changed to Percentage Discount: 80.0

3.2 总结

3.2.1 优点

  • 灵活性:可以在运行时动态选择算法。
  • 扩展性:新增策略时,只需实现新的策略类,无需修改现有代码。
  • 代码复用:不同的上下文可以共享相同的策略。

3.2.2 缺点

  • 类的数量增加:每增加一个策略,就需要增加一个类。
  • 客户端需要知道所有策略:客户端需要了解所有可用的策略,并选择合适的策略。

4.命令模式(Command)

命令模式Command)是一种行为设计模式,它将请求封装成一个对象,从而使你能够用不同的请求、队列或者请求日志来参数化其他对象。命令模式也支持可撤销的操作。

在这里插入图片描述

4.1 组成部分

  • 命令对象:封装了一个请求,包括执行该请求所需的所有信息(例如,接收者、方法、参数等)。
  • 接收者:实际执行命令的对象。
  • 调用者:请求的发起者,它将命令对象传递给接收者。
  • 客户端:创建命令对象并将其设置到调用者中。

4.2 示例

假设我们正在开发一个智能家居系统,用户可以通过 遥控器 控制不同的设备(如 风扇 等)。我们可以使用命令模式来实现这个功能。

4.2.1 命令接口

首先,定义一个命令接口 Command,声明一个执行命令的方法 execute

public interface Command {
    void execute();
}

4.2.2 具体命令实现

接下来,实现不同的命令,例如控制灯的开关和控制风扇的开关。

// 开灯
public class LightOnCommand implements Command {
    private Light light;

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

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

// 关灯
public class LightOffCommand implements Command {
    private Light light;

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

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

// 开风扇
public class FanOnCommand implements Command {
    private Fan fan;

    public FanOnCommand(Fan fan) {
        this.fan = fan;
    }

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

// 关闭风扇
public class FanOffCommand implements Command {
    private Fan fan;

    public FanOffCommand(Fan fan) {
        this.fan = fan;
    }

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

LightOnCommandLightOffCommandFanOnCommandFanOffCommand 实现了 Command 接口,分别控制灯和风扇的开关。

4.2.3 接收者

接收者是 实际执行命令的对象,例如灯和风扇。

public class Light {
    public void turnOn() {
        System.out.println("Light is on");
    }

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

public class Fan {
    public void turnOn() {
        System.out.println("Fan is on");
    }

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

LightFan 是实际执行命令的对象。

4.2.4 调用者

调用者是 请求的发起者,它将命令对象传递给接收者。

public class RemoteControl {
    private Command onCommand;
    private Command offCommand;

    public RemoteControl(Command onCommand, Command offCommand) {
        this.onCommand = onCommand;
        this.offCommand = offCommand;
    }

    public void pressOnButton() {
        onCommand.execute();
    }

    public void pressOffButton() {
        offCommand.execute();
    }
}

RemoteControl 是请求的发起者,它将命令对象传递给接收者并执行命令。

4.2.5 客户端

客户端代码 创建不同的命令对象,并将它们设置到 RemoteControl 中,通过调用 RemoteControl 的方法来执行命令。

public class CommandPatternDemo {
    public static void main(String[] args) {
        Light light = new Light();
        Fan fan = new Fan();

        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);
        Command fanOn = new FanOnCommand(fan);
        Command fanOff = new FanOffCommand(fan);

        RemoteControl remoteControl = new RemoteControl(lightOn, lightOff);
        remoteControl.pressOnButton(); // 输出: Light is on
        remoteControl.pressOffButton(); // 输出: Light is off

        remoteControl = new RemoteControl(fanOn, fanOff);
        remoteControl.pressOnButton(); // 输出: Fan is on
        remoteControl.pressOffButton(); // 输出: Fan is off
    }
}

4.2.6 输出结果

Light is on
Light is off
Fan is on
Fan is off

通过这个例子,你可以看到命令模式如何将请求的发送者和接收者解耦,使代码更加灵活和可扩展。

4.3 总结

4.3.1 优点

  • 解耦:命令模式将请求的发送者和接收者解耦,使两者不直接依赖。
  • 扩展性:可以很容易地增加新的命令,而不需要修改现有的代码。
  • 支持撤销操作:命令对象可以存储执行前的状态,从而支持撤销操作。

4.3.2 缺点

  • 类的数量增加:每个命令都需要一个具体的命令类。
  • 复杂性增加:引入了多个对象和接口,可能会使系统变得更复杂。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据与AI实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值