美文网首页
行为型模式——策略模式

行为型模式——策略模式

作者: Doooook | 来源:发表于2020-09-02 22:40 被阅读0次

一、什么是策略模式

策略模式定义了一系列算法,封装了每个算法,并使它们可以互换。
怎么理解?比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。

UML图如下:

image.png
  • Strategy(抽象策略):特定策略的抽象。
  • ConcreteStrategy(具体策略):实现抽象策略的类。
  • Context(环境):运行特定策略的类,维护一个对Strategy对象的引用,用于定义所有支持算法的公共接口。

二、应用实例

以商场促销为例使用策略模式实现商场促销算法。

  1. CashSuper现金收费接口,抽象出收费的方法供实现类实现
/**
 * @author: Jay Mitter
 * @date: 2020-09-02 22:03
 * @description: 现金收费接口,抽象出收费的方法供实现类实现
 */
public interface CashSuper {

    /**
     * 抽象的收费方式,供实现
     * @param money
     * @return
     */
    double acceptCash(double money);

}
  1. 上下文类CashContext
/**
 * @author: Jay Mitter
 * @date: 2020-09-02 22:03
 * @description: 首先声明一个CashSuper对象,通过构造方法,传入具体的收费策略,getResult()方法的功能为根据收费策略的不同获得计算结果
 */
public class CashContext {

    private CashSuper cashSuper;

    public CashContext(CashSuper cashSuper) {
        this.cashSuper = cashSuper;
    }

    public double getResult(double money) {
        return cashSuper.acceptCash(money);
    }
}
  1. 正常收费实现类
/**
 * @author: Jay Mitter
 * @date: 2020-09-02 22:06
 * @description: 正常收费实现类
 */
public class CashNormal implements CashSuper {
    @Override
    public double acceptCash(double money) {
        return money;
    }
}
  1. 打折收费子类
/**
 * @author: Jay Mitter
 * @date: 2020-09-02 22:07
 * @description: 打折收费实现类
 */
public class CashRebate implements CashSuper {

    /**
     * 折扣,默认是1
     */
    private double moneyRebate = 1;

    public CashRebate(double moneyRebate) {
        this.moneyRebate = moneyRebate;
    }

    @Override
    public double acceptCash(double money) {
        return money * moneyRebate;
    }
}
  1. 返利收费子类
/**
 * @author: Jay Mitter
 * @date: 2020-09-02 22:09
 * @description: 返利收费子类,返利活动,输入返利条件和返利值,比如满300返100,moneyCondition为300,moneyReturn为100
 */
public class CashReturn implements CashSuper {

    /**
     * 返利条件
     */
    private double moneyCondition = 0.0d;
    /**
     * 返利值
     */
    private double moneyReturn = 0.0d;

    public CashReturn(double moneyCondition, double moneyReturn) {
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    @Override
    public double acceptCash(double money) {
        double result = money;
        if (money >= moneyCondition) {
            result = money - Math.floor(money / moneyCondition) * moneyReturn;
        }
        return result;
    }
}
  1. 测试类
/**
 * @author: Jay Mitter
 * @date: 2020-09-02 22:23
 * @description:
 */
public class StrategyTest {

    public static void main(String[] args) {
        CashContext cashContext = null;
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入打折方式(1/2/3):");
        int in = scanner.nextInt();
        String type = "";

        switch (in) {
            case 1:
                cashContext = new CashContext(new CashNormal());
                type += "正常收费";
                break;
            case 2:
                cashContext = new CashContext(new CashReturn(300, 100));
                type += "满300返100";
                break;
            case 3:
                cashContext = new CashContext(new CashRebate(0.8));
                type += "打8折";
                break;
            default:
                System.out.println("请输入1/2/3");
                break;
        }

        double totalPrice = 0;
        System.out.print("请输入单价:");
        double price = scanner.nextDouble();
        System.out.println("请输入数量:");
        double num = scanner.nextDouble();
        assert cashContext != null;
        totalPrice = cashContext.getResult(price * num);
        System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrice);
        scanner.close();
    }
}

三、策略模式的应用

  1. 何时使用
    一个系统有许多类,而区分它们的只是他们直接的行为时
  2. 方法
    将这些算法封装成一个一个的类,任意的替换
  3. 优点
    算法可以自由切换
    避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
    扩展性良好,增加一个策略只需实现接口即可
  4. 缺点
    策略类数量会增多,每个策略都是一个类,复用的可能性很小
    所有的策略类都需要对外暴露
  5. 使用场景
    多个类只有算法或行为上稍有不同的场景
    算法需要自由切换的场景
    需要屏蔽算法规则的场景
  6. 应用实例
    出行方式,自行车、汽车等,每一种出行方式都是一个策略
    商场促销方式,打折、满减等
    Java AWT中的LayoutManager,即布局管理器
  7. 注意事项
    如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题

参考:https://www.cnblogs.com/adamjwh/p/11011095.html

SpringBoot基于注解实现策略模式

基本思路

根据不同的参数type走不同的策略,每个策略类上通过注解与参数类型绑定,项目启动时扫描所有的策略类型,存储到map中,运行时根据业务类的type获取到对应的策略类即可。

实现

模拟订单业务,根据订单的type,需要不同的处理逻辑、,比如:免费订单、半价订单、打折订单等。

一、业务实体Order

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 09:58
 * @description: 业务实体——订单
 */
@Data
@Builder
public class Order {

    /**
     * 免费订单
     */
    public static final int FREE = 1;
    /**
     * 半价订单
     */
    public static final int HALF = 2;
    /**
     * 打折订单
     */
    public static final int DISCOUNT = 3;

    private String name;
    private Double price;
    private Integer type;

}

二、策略接口OrderStrategy及其实现类

OrderStrategy

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 10:09
 * @description: 处理订单策略
 */
public interface OrderStrategy {

    /**
     * 处理订单
     * @param order
     */
    void handleOrder(Order order);

}

FreeOrderStrategy

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 10:54
 * @description: 免费订单
 */
@Component
@HandlerOrderType(value = Order.FREE) // 使用注解标明策略类型
public class FreeOrderStrategy implements OrderStrategy {
    @Override
    public void handleOrder(Order order) {
        System.out.println("----处理免费订单----");
    }
}

HalfOrderStrategy

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 10:56
 * @description: 半价订单处理类
 */
@Component
@HandlerOrderType(value = Order.HALF)
public class HalfOrderStrategy implements OrderStrategy {
    @Override
    public void handleOrder(Order order) {
        System.out.println("----处理半价订单----");
    }
}

DiscountOrderStrategy

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 11:07
 * @description: 打折订单处理类
 */
@Component
@HandlerOrderType(value = Order.DISCOUNT)
public class DiscountOrderStrategy implements OrderStrategy {
    @Override
    public void handleOrder(Order order) {
        System.out.println("----处理打折订单----");
    }
}

三、自定义策略注解

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 09:47
 * @description: 自定义注解策略
 */
@Target(ElementType.TYPE) // 作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited // 子类可以继承此注解
public @interface HandlerOrderType {

    /**
     * 策略类型
     * @return 策略类型
     */
    int value();

}

四、核心功能实现

HandlerOrderContext

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 11:10
 * @description: 策略上下文
 */
@Component
public class HandlerOrderContext {

    @Autowired
    private ApplicationContext applicationContext;
    /**
     * 存放所有策略类Bean的map
     */
    public static Map<Integer, Class<OrderStrategy>> orderStrategyBeanMap = new ConcurrentHashMap<>();

    public OrderStrategy getOrderStrategy(Integer type) throws IllegalAccessException {
        Class<OrderStrategy> orderStrategyClass = orderStrategyBeanMap.get(type);
        if (null == orderStrategyClass) {
            throw new IllegalAccessException("没有对应的订单类型");
        }
        return applicationContext.getBean(orderStrategyClass);
    }

}

策略核心功能,获取所有策略注解的类型,并将对应的class初始化到HandlerOrderContext中

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 15:32
 * @description: 策略核心功能,获取所有策略注解的类型,并将对应的class初始化到HandlerOrderContext中
 */
@Component
public class HandlerOrderProcessor implements ApplicationContextAware {

    /**
     * 获取所有的策略BeanClass 加入HandlerOrderContext属性中
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> orderStrategyMap = applicationContext.getBeansWithAnnotation(HandlerOrderType.class);
        orderStrategyMap.forEach((k, v) -> {
            Class<OrderStrategy> orderStrategyClass = (Class<OrderStrategy>) v.getClass();
            int type = orderStrategyClass.getAnnotation(HandlerOrderType.class).value();
            // 将class加入map中,type作为key
            HandlerOrderContext.orderStrategyBeanMap.put(type, orderStrategyClass);
        });
    }
}

五、业务接口及其实现类

OrderService

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 15:41
 * @description: 订单接口
 */
public interface OrderService {
    /**
     * 处理订单
     * @param order
     */
    void handleOrder(Order order);

}

OrderServiceImpl

/**
 * @author: Jay Mitter
 * @date: 2020-09-06 15:42
 * @description:
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private HandlerOrderContext handlerOrderContext;

    @Override
    public void handleOrder(Order order) {
        // 使用策略处理订单
        OrderStrategy orderStrategy = null;
        try {
            orderStrategy = handlerOrderContext.getOrderStrategy(order.getType());
            orderStrategy.handleOrder(order);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

六、测试

    @Autowired
    private OrderService orderService;

    /**
     * 行为型模式——boot策略模式
     */
    @Test
    public void testBehaviorBootStrategy() {
        Order order = Order.builder().name("微信订单").price(99.9).type(Order.DISCOUNT).build();
        orderService.handleOrder(order);
    }

以后有新的类型的Order时,在Order类中添加新的type和实现对应的type的策略类即可

相关文章

  • 设计模式[13]-策略模式-Strategy Pattern

    1.策略模式简介 策略模式(Strategy Patter)是行为型(Behavioral)设计模式,策略模式封装...

  • Android设计模式——策略模式(十一大行为型)

    1.策略模式介绍 策略模式(Strategy Pattern),是十一大行为型设计模式之一。 在开...

  • 23.策略模式(行为型)

    策略模式(行为型) 原书链接设计模式(刘伟) 适应算法灵活性而产生的设计模式——策略模式。 一、相关概述 1). ...

  • 策略模式(行为型)

    概念定义一系列算法,将这些算法封装起来,使他们可以相互替换,同时算法的修改与更新不影响调用它的对象(Context...

  • 行为型-策略模式

    意图: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。 主要解决: 在有多种算法相似的情况下,使...

  • 策略模式 - 行为型

    一、策略模式的定义定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它...

  • 【设计模式】行为型设计模式汇总(二)

    行为型设计模式范围 观察者模式 模板方法 策略模式 职责链模式 状态模式 迭代器模式 访问者模式 备忘录模式 命令...

  • 【设计模式】行为型设计模式汇总(一)

    行为型设计模式范围 观察者模式 模板方法 策略模式 职责链模式 状态模式 迭代器模式 访问者模式 备忘录模式 命令...

  • java 策略模式

    策略模式1.策略模式简介策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具...

  • 行为型设计模式-策略模式

    定义 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换 解决问题 在有多种算法相似的情况下,使用 i...

网友评论

      本文标题:行为型模式——策略模式

      本文链接:https://www.haomeiwen.com/subject/bwxssktx.html