• 面向对象设计模式——策略模式


    策略设计模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。该模式定义了一系列算法,将每个算法封装到一个独立的类中,使它们可以相互替换。策略模式使算法独立于客户端而变化,客户端可以根据需要选择不同的算法。

    主要组成部分:

    1. 策略接口(Strategy Interface):定义了一组算法的通用接口,所有具体策略类都要实现这个接口。

    2. 具体策略类(Concrete Strategies):实现策略接口,提供不同的算法实现。

    3. 上下文(Context):维护一个对策略接口的引用,允许客户端在运行时选择算法。上下文通常会将客户端的请求委派给具体策略对象。

    应用场景:

    1. 动态选择算法策略模式适用于需要在运行时根据不同情况切换算法的情况。例如,排序算法,日志记录级别,数据校验等。

    2. 消除大量的条件语句:当一个类有很多条件语句来选择不同的行为时,策略模式可以减少这些条件语句,使代码更具可读性和可维护性。

    3. 复用性:策略模式可以促进算法的复用,不同的上下文可以共享相同的策略对象,减少重复编码。

    4. 解耦合:策略模式将算法的实现与调用代码解耦,这意味着对算法的更改不会影响调用它的代码。

    示例:

    考虑一个电商平台的购物车系统。不同用户可能有不同的折扣策略,例如普通用户、VIP用户、员工用户可以享受不同的折扣。使用策略模式可以创建一个折扣策略接口,然后为每个用户类型创建具体的策略类。购物车上下文对象可以接收不同用户类型的策略,并在结算时应用相应的折扣策略。

    这里是一个伪代码示例:

    // 策略接口
    interface DiscountStrategy {
        double applyDiscount(double totalAmount);
    }
    
    // 具体策略类
    class RegularCustomerDiscount implements DiscountStrategy {
        public double applyDiscount(double totalAmount) {
            return totalAmount;
        }
    }
    
    class VIPCustomerDiscount implements DiscountStrategy {
        public double applyDiscount(double totalAmount) {
            return totalAmount * 0.9; // 10% off
        }
    }
    
    class EmployeeDiscount implements DiscountStrategy {
        public double applyDiscount(double totalAmount) {
            return totalAmount * 0.8; // 20% off
        }
    }
    
    // 上下文
    class ShoppingCart {
        private DiscountStrategy discountStrategy;
    
        public ShoppingCart(DiscountStrategy strategy) {
            this.discountStrategy = strategy;
        }
    
        public double checkout(double totalAmount) {
            return discountStrategy.applyDiscount(totalAmount);
        }
    }
    
    • 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

    在这个示例中,不同用户类型对应于不同的具体策略类。购物车上下文可以根据用户类型选择不同的策略,而不需要改变购物车的代码。这使得系统更加灵活,并且可以轻松应对不同的折扣需求。

    策略模式是如何消除条件语句的?

    策略模式消除条件语句的关键在于将不同的行为封装到各个具体策略类中,而不再需要在上下文类(调用者)中使用大量的条件语句来选择不同的行为。这通过以下方式实现:

    1. 抽象策略接口:首先,策略模式定义了一个抽象策略接口,该接口声明了一组通用的方法,这些方法将被不同的具体策略类实现。这些方法代表不同的行为或算法。

    2. 具体策略类:每个具体策略类都实现了策略接口中的方法,提供了特定的行为或算法实现。每个具体策略类代表了一种行为的变体。

    3. 上下文类:上下文类包含一个策略接口的引用,客户端可以将不同的策略对象传递给上下文类。上下文类使用策略对象执行特定的行为,而不需要了解具体策略的细节。

    通过上述步骤,策略模式将条件语句的选择逻辑从客户端移到了上下文类中,客户端只需要选择合适的策略对象传递给上下文,而不再需要编写大量的if-else语句来决定采用哪种行为。

    以下是示例代码,演示如何通过策略模式消除条件语句:

    // 抽象策略接口
    interface PaymentStrategy {
        void pay(int amount);
    }
    
    // 具体策略类
    class CreditCardPayment implements PaymentStrategy {
        public void pay(int amount) {
            // 实现信用卡支付逻辑
        }
    }
    
    class PayPalPayment implements PaymentStrategy {
        public void pay(int amount) {
            // 实现PayPal支付逻辑
        }
    }
    
    // 上下文类
    class ShoppingCart {
        private PaymentStrategy paymentStrategy;
    
        public void setPaymentStrategy(PaymentStrategy strategy) {
            this.paymentStrategy = strategy;
        }
    
        public void checkout(int amount) {
            paymentStrategy.pay(amount); // 执行支付,不需要条件语句
        }
    }
    
    • 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

    在上述示例中,ShoppingCart 上下文类可以使用不同的 PaymentStrategy 对象,无需在 checkout 方法中包含条件语句。策略模式将不同的支付逻辑封装在具体策略类中,使代码更加可维护和可读。

    为什么说算法可以相互替换?

    是的,不同的行为在策略模式中通常对应不同的算法。策略模式的目标之一是将不同的算法封装到各个独立的策略类中,以使它们可以相互替换,这是因为这些算法执行的是相同的任务,但它们可以使用不同的方法来完成。

    策略模式的关键在于实现了开闭原则,即对扩展开放,对修改关闭。这意味着可以轻松地添加新的策略(算法),而无需修改已有的代码。这种灵活性使不同的算法可以相互替换,而不会影响上下文类或客户端的代码。

    举例来说,考虑一个排序算法的上下文。在这个上下文中,可以有多个策略(算法)来执行不同的排序任务,如冒泡排序、快速排序、归并排序等。每个排序算法都被封装在一个具体的策略类中。如果要更改排序算法,只需创建一个新的策略类并将其传递给上下文类,而不需要修改已有的排序上下文的代码。

    策略模式的目的是提供一种简单的方式来交换算法,以满足不同的需求,同时保持代码的可维护性和可扩展性。这种灵活性使算法可以相互替换,而不会对系统的其他部分产生负面影响。

    策略模式在应用场景下会和哪些其他设计模式一起使用?

    策略模式通常可以与以下设计模式一起使用:

    1. 工厂模式:用于创建具体策略对象的工厂方法,以避免直接实例化具体策略类。

    2. 单例模式:可以用来确保策略对象是唯一的,尤其是在多个地方需要使用相同的策略时。

    3. 装饰器模式:允许你在不修改策略对象的情况下动态地添加额外的行为或功能。

    4. 观察者模式:可以通过观察者模式通知其他对象有关策略的变化,以便它们可以适应新的策略。

    策略模式通常用于解耦算法的定义和使用,使系统更具弹性和可维护性。
    让我们以一个示例来说明如何将策略模式与其他设计模式一起使用。

    场景:假设我们有一个电商平台,我们需要实现一个促销策略,用户可以根据促销策略来获得不同的折扣。这里,我们使用策略模式来处理促销策略的不同算法,而工厂模式用于创建策略对象,单例模式确保策略对象的唯一性,装饰器模式用于动态添加额外的促销信息,观察者模式用于通知用户有关促销策略的变化。

    首先,我们定义策略接口:

    // 策略接口
    interface PromotionStrategy {
        double applyDiscount(double amount);
    }
    
    • 1
    • 2
    • 3
    • 4

    然后,实现具体的促销策略:

    // 具体策略类
    class BlackFridayPromotion implements PromotionStrategy {
        public double applyDiscount(double amount) {
            // 实现 Black Friday 促销算法
        }
    }
    
    class ChristmasPromotion implements PromotionStrategy {
        public double applyDiscount(double amount) {
            // 实现圣诞促销算法
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    接下来,使用工厂模式创建策略对象:

    // 策略工厂
    class PromotionStrategyFactory {
        private static PromotionStrategy blackFriday = new BlackFridayPromotion();
        private static PromotionStrategy christmas = new ChristmasPromotion();
    
        public static PromotionStrategy getPromotionStrategy(String promotionType) {
            if ("BlackFriday".equals(promotionType)) {
                return blackFriday;
            } else if ("Christmas".equals(promotionType)) {
                return christmas;
            }
            // 其他策略
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用单例模式来确保策略对象的唯一性:

    // 单例模式
    class PromotionStrategySingleton {
        private static PromotionStrategy instance;
    
        private PromotionStrategySingleton() {
            // 私有构造函数
        }
    
        public static PromotionStrategy getInstance() {
            if (instance == null) {
                instance = PromotionStrategyFactory.getPromotionStrategy("Default"); // 默认策略
            }
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用装饰器模式来添加额外的促销信息:

    // 装饰器模式
    class PromotionDecorator implements PromotionStrategy {
        private PromotionStrategy strategy;
        private String additionalInfo;
    
        public PromotionDecorator(PromotionStrategy strategy, String additionalInfo) {
            this.strategy = strategy;
            this.additionalInfo = additionalInfo;
        }
    
        public double applyDiscount(double amount) {
            // 添加额外信息的处理
            return strategy.applyDiscount(amount);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    最后,使用观察者模式通知用户有关促销策略的变化:

    // 观察者模式
    interface PromotionObserver {
        void updatePromotion(String promotionInfo);
    }
    
    class User implements PromotionObserver {
        private String username;
    
        public User(String username) {
            this.username = username;
        }
    
        public void updatePromotion(String promotionInfo) {
            System.out.println(username + " received promotion info: " + promotionInfo);
        }
    }
    
    class PromotionSubject {
        private List<PromotionObserver> observers = new ArrayList<>();
    
        public void addObserver(PromotionObserver observer) {
            observers.add(observer);
        }
    
        public void notifyObservers(String promotionInfo) {
            for (PromotionObserver observer : observers) {
                observer.updatePromotion(promotionInfo);
            }
        }
    }
    
    • 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

    这个示例展示了如何将策略模式与工厂模式、单例模式、装饰器模式和观察者模式一起使用,以处理促销策略的不同算法,确保策略对象的唯一性,动态添加额外信息,并通知用户有关促销策略的变化。

  • 相关阅读:
    【Seata】05 - Seata Saga 模式简单整理、Docker 部署 Nacos 单机(基于 Jpom)相关配置
    兔起鹘落全端涵盖,Go lang1.18入门精炼教程,由白丁入鸿儒,全平台(Sublime 4)Go lang开发环境搭建EP00
    【国漫逆袭】火灵儿重返第一巅峰,云曦排名飙升,不良人陷入颓势
    知识图谱1(实体抽取)
    阿里云acp云计算认证考试科目有哪些?
    金融数据库的战场,太平洋保险和OceanBase打了场胜仗
    VM虚拟机下载与安装
    【C】自定义类型(二)位段,枚举,联合
    解决小程序中textarea ios端样式不兼容的方法
    解决跨域问题
  • 原文地址:https://blog.csdn.net/weixin_63958646/article/details/134045601