• 设计模式——12. 策略模式


    1. 说明

    策略模式(Strategy Pattern)是一种行为型设计模式,它允许你定义一系列算法,将每个算法封装成一个独立的类,并使它们可以互相替换,使得客户端代码可以根据需要在不修改原有代码的情况下选择不同的算法来执行某个任务。策略模式将算法的选择和使用与算法的实现分离开来,提高了代码的可维护性和扩展性。

    策略模式通常包括以下角色:

    1. Context(上下文):它是策略模式的主要类,负责维护一个对策略对象的引用,可以在运行时切换不同的策略。
    2. Strategy(策略):它是策略模式的接口或抽象类,定义了具体策略类必须实现的方法。
    3. ConcreteStrategy(具体策略):它是策略模式的具体实现类,实现了策略接口定义的方法,即具体的算法逻辑。

    通过策略模式,你可以根据需要动态地选择不同的具体策略,而不需要改变上下文类的代码。这使得策略模式在需要在运行时根据不同条件选择不同算法的情况下特别有用。例如,在一个电商网站中,可以使用策略模式来实现不同的促销策略,根据不同的季节或用户类型选择不同的促销算法。

    策略模式的优点包括:

    • 提高代码的可维护性和可扩展性,因为每个具体策略都可以独立开发和测试,易于新增或修改策略。
    • 避免了大量的条件分支语句,使代码更加清晰和可读。
    • 允许在运行时动态地切换策略,提供了更大的灵活性。

    总之,策略模式是一种有助于降低耦合度、提高代码可维护性的设计模式,适用于需要根据不同情况选择不同算法的场景。

    2. 使用的场景

    策略模式适用于以下场景:

    1. 多种算法可选:当一个任务可以使用多种不同的算法或策略来完成时,策略模式是一种常见的选择。例如,排序算法可以根据不同情况使用冒泡排序、快速排序等不同的策略。
    2. 条件分支过多:当一个类有很多条件分支语句,根据不同的条件执行不同的逻辑时,可以考虑使用策略模式来替代这些条件分支,使代码更加清晰和可维护。
    3. 需要在运行时动态切换算法:如果需要在运行时根据不同的条件或用户输入动态地选择合适的算法,策略模式是一种有效的解决方案。例如,根据不同的用户类型应用不同的定价策略。
    4. 算法的实现变化频繁:如果算法的实现经常发生变化,但接口保持不变,策略模式可以帮助将不同的算法实现隔离开,使得变更不会影响到其他部分的代码。
    5. 需要提供算法的多种变体:策略模式可以用来定义一个算法的多种不同变体,客户端可以根据需要选择其中一种或多种。
    6. 需要避免使用条件语句的情况:在一些情况下,使用大量的条件语句会导致代码变得复杂和难以维护。策略模式可以帮助简化代码结构。
    7. 需要将算法实现与上下文分离:策略模式可以帮助将算法的实现与使用算法的上下文分离,使得它们可以独立变化,提高了代码的可维护性和可测试性。

    总之,策略模式在需要根据不同情况选择不同算法、需要降低条件分支复杂度、需要支持动态切换算法或需要将算法实现与上下文分离的情况下都非常有用。

    3. 应用例子

    以下是使用 Python 实现的策略模式的示例,模拟了一个简单的支付系统,其中不同的支付方法被视为不同的支付策略:

    # 定义支付策略接口
    class PaymentStrategy:
        def pay(self, amount):
            pass
    
    # 具体支付策略:信用卡支付
    class CreditCardPayment(PaymentStrategy):
        def __init__(self, card_number, card_holder):
            self.card_number = card_number
            self.card_holder = card_holder
    
        def pay(self, amount):
            print(f"支付 {amount} 元,使用信用卡 {self.card_number}(持卡人:{self.card_holder})")
    
    # 具体支付策略:支付宝支付
    class AlipayPayment(PaymentStrategy):
        def __init__(self, alipay_account):
            self.alipay_account = alipay_account
    
        def pay(self, amount):
            print(f"支付 {amount} 元,使用支付宝(账号:{self.alipay_account})")
    
    # 上下文类,负责管理和切换支付策略
    class PaymentContext:
        def __init__(self, payment_strategy):
            self.payment_strategy = payment_strategy
    
        def set_payment_strategy(self, payment_strategy):
            self.payment_strategy = payment_strategy
    
        def execute_payment(self, amount):
            self.payment_strategy.pay(amount)
    
    # 客户端代码
    if __name__ == "__main__":
        # 创建不同的支付策略对象
        credit_card_strategy = CreditCardPayment("1234-5678-1234-5678", "John Doe")
        alipay_strategy = AlipayPayment("johndoe@example.com")
    
        # 创建上下文对象,初始使用信用卡支付
        payment_context = PaymentContext(credit_card_strategy)
    
        # 进行支付
        payment_context.execute_payment(100)
    
        # 切换支付策略为支付宝支付
        payment_context.set_payment_strategy(alipay_strategy)
        payment_context.execute_payment(50)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    在这个示例中:

    • PaymentStrategy 是支付策略接口,定义了 pay 方法,具体的支付策略类需要实现这个方法。
    • CreditCardPayment 和 AlipayPayment 是具体的支付策略类,它们分别实现了信用卡支付和支付宝支付的具体逻辑。
    • PaymentContext 是上下文类,负责管理和切换支付策略。客户端可以通过 set_payment_strategy 方法切换不同的支付策略。
    • 在客户端代码中,我们创建了不同的支付策略对象(信用卡支付和支付宝支付),然后使用上下文对象进行支付,可以动态地切换支付策略。

    这个示例演示了策略模式在 Python 中的实现,通过它可以根据不同的情况选择不同的支付策略,而不需要改变上下文类的代码。

    4. 实现要素

    1. 上下文(Context):上下文类包含一个对策略对象的引用,它通常具有一个用于执行某个任务的方法。上下文类将任务的执行委托给策略对象,但并不关心具体的策略是哪一个。
    2. 策略接口(Strategy):策略接口是一个抽象的接口或抽象类,定义了具体策略类必须实现的方法。这些方法通常包括了算法或策略的执行逻辑。
    3. 具体策略类(Concrete Strategy):具体策略类实现了策略接口,提供了具体的算法或策略实现。每个具体策略类都可以代表一种不同的算法或策略。

    5. UML图

                        +------------------+
                        |     Context      |
                        +------------------+
                        | - strategy: Strategy |
                        +------------------+
                                 |
                                 |
                                 v
                        +------------------+
                        |     Strategy     |
                        +------------------+
                        | + execute(): void |
                        +------------------+
                                 ^
                                 |
                                 |
                 +----------------------------+
                 |                            |
                 v                            v
    +------------------+        +------------------+
    | ConcreteStrategyA |        | ConcreteStrategyB |
    +------------------+        +------------------+
    | + execute(): void |        | + execute(): void |
    +------------------+        +------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • Context 类维护了一个对 Strategy 接口的引用,可以在运行时切换不同的具体策略。
    • Strategy 接口定义了策略类必须实现的 execute 方法,这个方法包含了具体的算法或策略逻辑。
    • ConcreteStrategyA 和 ConcreteStrategyB 是具体策略类,它们分别实现了 Strategy 接口,并提供了不同的算法实现。

    通过策略模式,客户端可以在运行时选择不同的策略,而不需要改变上下文类的代码。

    6. Java/golang/javascrip/C++ 等语言实现方式

    6.1 Java实现

    上述例子用Java语言实现示例如下:

    // 定义支付策略接口
    interface PaymentStrategy {
        void pay(int amount);
    }
    
    // 具体支付策略:信用卡支付
    class CreditCardPayment implements PaymentStrategy {
        private String cardNumber;
        private String cardHolder;
    
        public CreditCardPayment(String cardNumber, String cardHolder) {
            this.cardNumber = cardNumber;
            this.cardHolder = cardHolder;
        }
    
        @Override
        public void pay(int amount) {
            System.out.println("支付 " + amount + " 元,使用信用卡 " + cardNumber + "(持卡人:" + cardHolder + ")");
        }
    }
    
    // 具体支付策略:支付宝支付
    class AlipayPayment implements PaymentStrategy {
        private String alipayAccount;
    
        public AlipayPayment(String alipayAccount) {
            this.alipayAccount = alipayAccount;
        }
    
        @Override
        public void pay(int amount) {
            System.out.println("支付 " + amount + " 元,使用支付宝(账号:" + alipayAccount + ")");
        }
    }
    
    // 上下文类,负责管理和切换支付策略
    class PaymentContext {
        private PaymentStrategy paymentStrategy;
    
        public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
            this.paymentStrategy = paymentStrategy;
        }
    
        public void executePayment(int amount) {
            paymentStrategy.pay(amount);
        }
    }
    
    // 客户端代码
    public class PaymentApp {
        public static void main(String[] args) {
            // 创建不同的支付策略对象
            PaymentStrategy creditCardStrategy = new CreditCardPayment("1234-5678-1234-5678", "John Doe");
            PaymentStrategy alipayStrategy = new AlipayPayment("johndoe@example.com");
    
            // 创建上下文对象,初始使用信用卡支付
            PaymentContext paymentContext = new PaymentContext();
    
            // 进行支付
            paymentContext.setPaymentStrategy(creditCardStrategy);
            paymentContext.executePayment(100);
    
            // 切换支付策略为支付宝支付
            paymentContext.setPaymentStrategy(alipayStrategy);
            paymentContext.executePayment(50);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    6.2 Golang实现

    上述例子用golang实现示例如下:

    package main
    
    import "fmt"
    
    // 定义支付策略接口
    type PaymentStrategy interface {
            Pay(amount int)
    }
    
    // 具体支付策略:信用卡支付
    type CreditCardPayment struct {
            cardNumber string
            cardHolder string
    }
    
    func NewCreditCardPayment(cardNumber, cardHolder string) *CreditCardPayment {
            return &CreditCardPayment{cardNumber, cardHolder}
    }
    
    func (c *CreditCardPayment) Pay(amount int) {
            fmt.Printf("支付 %d 元,使用信用卡 %s(持卡人:%s)\n", amount, c.cardNumber, c.cardHolder)
    }
    
    // 具体支付策略:支付宝支付
    type AlipayPayment struct {
            alipayAccount string
    }
    
    func NewAlipayPayment(alipayAccount string) *AlipayPayment {
            return &AlipayPayment{alipayAccount}
    }
    
    func (a *AlipayPayment) Pay(amount int) {
            fmt.Printf("支付 %d 元,使用支付宝(账号:%s)\n", amount, a.alipayAccount)
    }
    
    // 上下文类,负责管理和切换支付策略
    type PaymentContext struct {
            paymentStrategy PaymentStrategy
    }
    
    func (pc *PaymentContext) SetPaymentStrategy(paymentStrategy PaymentStrategy) {
            pc.paymentStrategy = paymentStrategy
    }
    
    func (pc *PaymentContext) ExecutePayment(amount int) {
            pc.paymentStrategy.Pay(amount)
    }
    
    // 客户端代码
    func main() {
            // 创建不同的支付策略对象
            creditCardStrategy := NewCreditCardPayment("1234-5678-1234-5678", "John Doe")
            alipayStrategy := NewAlipayPayment("johndoe@example.com")
    
            // 创建上下文对象,初始使用信用卡支付
            paymentContext := PaymentContext{}
    
            // 进行支付
            paymentContext.SetPaymentStrategy(creditCardStrategy)
            paymentContext.ExecutePayment(100)
    
            // 切换支付策略为支付宝支付
            paymentContext.SetPaymentStrategy(alipayStrategy)
            paymentContext.ExecutePayment(50)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    6.3 Javascript实现

    上述例子用javascript实现示例如下:

    // 定义支付策略接口
    class PaymentStrategy {
      pay(amount) {}
    }
    
    // 具体支付策略:信用卡支付
    class CreditCardPayment extends PaymentStrategy {
      constructor(cardNumber, cardHolder) {
        super();
        this.cardNumber = cardNumber;
        this.cardHolder = cardHolder;
      }
    
      pay(amount) {
        console.log(`支付 ${amount} 元,使用信用卡 ${this.cardNumber}(持卡人:${this.cardHolder})`);
      }
    }
    
    // 具体支付策略:支付宝支付
    class AlipayPayment extends PaymentStrategy {
      constructor(alipayAccount) {
        super();
        this.alipayAccount = alipayAccount;
      }
    
      pay(amount) {
        console.log(`支付 ${amount} 元,使用支付宝(账号:${this.alipayAccount})`);
      }
    }
    
    // 上下文类,负责管理和切换支付策略
    class PaymentContext {
      constructor() {
        this.paymentStrategy = null;
      }
    
      setPaymentStrategy(paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
      }
    
      executePayment(amount) {
        if (this.paymentStrategy) {
          this.paymentStrategy.pay(amount);
        } else {
          console.log("请选择支付策略。");
        }
      }
    }
    
    // 客户端代码
    const creditCardStrategy = new CreditCardPayment("1234-5678-1234-5678", "John Doe");
    const alipayStrategy = new AlipayPayment("johndoe@example.com");
    
    const paymentContext = new PaymentContext();
    
    // 进行支付
    paymentContext.setPaymentStrategy(creditCardStrategy);
    paymentContext.executePayment(100);
    
    // 切换支付策略为支付宝支付
    paymentContext.setPaymentStrategy(alipayStrategy);
    paymentContext.executePayment(50);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    6.4 C++实现

    上述例子用C++实现如下:

    #include 
    #include 
    
    // 定义支付策略接口
    class PaymentStrategy {
    public:
        virtual void pay(int amount) = 0;
    };
    
    // 具体支付策略:信用卡支付
    class CreditCardPayment : public PaymentStrategy {
    private:
        std::string cardNumber;
        std::string cardHolder;
    
    public:
        CreditCardPayment(const std::string& cardNumber, const std::string& cardHolder)
            : cardNumber(cardNumber), cardHolder(cardHolder) {}
    
        void pay(int amount) override {
            std::cout << "支付 " << amount << " 元,使用信用卡 " << cardNumber << "(持卡人:" << cardHolder << ")" << std::endl;
        }
    };
    
    // 具体支付策略:支付宝支付
    class AlipayPayment : public PaymentStrategy {
    private:
        std::string alipayAccount;
    
    public:
        AlipayPayment(const std::string& alipayAccount) : alipayAccount(alipayAccount) {}
    
        void pay(int amount) override {
            std::cout << "支付 " << amount << " 元,使用支付宝(账号:" << alipayAccount << ")" << std::endl;
        }
    };
    
    // 上下文类,负责管理和切换支付策略
    class PaymentContext {
    private:
        PaymentStrategy* paymentStrategy;
    
    public:
        PaymentContext() : paymentStrategy(nullptr) {}
    
        void setPaymentStrategy(PaymentStrategy* strategy) {
            paymentStrategy = strategy;
        }
    
        void executePayment(int amount) {
            if (paymentStrategy) {
                paymentStrategy->pay(amount);
            } else {
                std::cout << "请选择支付策略。" << std::endl;
            }
        }
    };
    
    int main() {
        // 创建不同的支付策略对象
        CreditCardPayment creditCardStrategy("1234-5678-1234-5678", "John Doe");
        AlipayPayment alipayStrategy("johndoe@example.com");
    
        // 创建上下文对象,初始使用信用卡支付
        PaymentContext paymentContext;
    
        // 进行支付
        paymentContext.setPaymentStrategy(&creditCardStrategy);
        paymentContext.executePayment(100);
    
        // 切换支付策略为支付宝支付
        paymentContext.setPaymentStrategy(&alipayStrategy);
        paymentContext.executePayment(50);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    7. 练习题

    假设您正在设计一个电商系统,其中不同的促销策略可以根据购物车中的商品数量来应用。您需要使用策略模式来实现这个功能。

    要求:

    1. 定义一个接口 DiscountStrategy,该接口包含一个方法 applyDiscount,该方法接受购物车总金额作为参数,并返回应用了促销策略后的最终金额。
    2. 创建三种具体的促销策略类:
    • NoDiscount:不应用任何折扣,直接返回购物车总金额。
    • TenPercentDiscount:应用 10% 的折扣。
    • FiftyPercentDiscount:应用 50% 的折扣。
    1. 创建一个购物车类 ShoppingCart,该类包含一个属性 totalAmount 表示购物车中商品的总金额,以及一个属性 discountStrategy 表示当前应用的促销策略。
    2. 购物车类应该有一个方法 checkout,该方法接受一个购物车总金额,并使用当前的促销策略来计算最终支付金额。
    3. 在客户端代码中,创建一个购物车对象,设置不同的促销策略,并模拟购物车中商品的总金额。然后使用购物车的 checkout 方法来计算最终支付金额。

    你可以使用 C++、Java、Python 或任何其他编程语言来实现这个练习。
    你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~

  • 相关阅读:
    287.寻找重复数
    解密长短时记忆网络(LSTM):从理论到PyTorch实战演示
    二种方法轻松提取音频中的钢琴声音
    Cross decomposition交叉分解大比拼:性能、应用场景和可视化对比总结
    Python函数和模块
    Nginx+php+mysql+wordpress搭建自己的博客站点
    IP应用场景API的反欺诈潜力:保护在线市场不受欺诈行为侵害
    pip 指定源
    Ubuntu安装配置PostgreSQL(18.04)
    PHP 智能物业管理系统mysql数据库web结构apache计算机软件工程网页wamp
  • 原文地址:https://blog.csdn.net/guohuang/article/details/133606827