设计模式-策略模式

设计模式-策略模式(Stategy Pattern)

 概要

 策略模式是一种行为型模式:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

 策略模式结构图如下:

 

 一、 涉及的角色

 1)Strategy

定义所有支持的算法的公共接口
1 public interface DealStrategy {
2     /**
3      * 定义策略接口
4      *
5      * @param option 请求参数
6      */
7     void dealMethod(String option);
8 }
2)ConcreteStrategy
封装了具体的算法或行为,继承于Strategy
 1 public class DealSina implements DealStrategy{
 2 
 3     /**
 4      * 定义策略接口
 5      *
 6      * @param option 请求参数
 7      */
 8     public void dealMethod(String option) {
 9         System.out.println("分享到新浪");
10     }
11 }

3)Context
用一个ConcreteStrategy 来配置,维护一个对Strategy 对象的引用
 1 public class DealContext {
 2     private final String type;
 3     private final DealStrategy deal;
 4 
 5     public DealContext(String type, DealStrategy deal) {
 6         this.type = type;
 7         this.deal = deal;
 8     }
 9 
10     public DealStrategy getDeal(){
11         return deal;
12     }
13 
14     public boolean options(String type) {
15         return this.type.equals(type);
16     }
17 }
客户端调用:
 1 public class Share {
 2 
 3     private static final List<DealContext> ALGORITHMS = new ArrayList<>();
 4 
 5     //静态代码块,先加载所有的策略
 6     static {
 7         ALGORITHMS.add(new DealContext("Sina", new DealSina()));
 8         ALGORITHMS.add(new DealContext("Wechat", new DealWechat()));
 9     }
10 
11     public static void shareOptions(String type) {
12         DealStrategy dealStrategy = null;
13         for (DealContext deal : ALGORITHMS) {
14             if (deal.options(type)) {
15                 dealStrategy = deal.getDeal();
16                 break;
17             }
18         }
19 
20         Optional.ofNullable(dealStrategy).ifPresent(s -> s.dealMethod(type));
21     }
22 
23     public static void main(String[] args) {
24         shareOptions("Wechat");
25     }
26 }

UML类图如下:

2.  使用场景
在Java中,比较器接口Comparator就是一个常见的策略模式实践
 1     public static <T> void sort(T[] a, Comparator<? super T> c) {
 2         if (c == null) {
 3             sort(a);
 4         } else {
 5             if (LegacyMergeSort.userRequested)
 6                 legacyMergeSort(a, c);
 7             else
 8                 TimSort.sort(a, 0, a.length, c, null, 0, 0);
 9         }
10     }

比如 Arrays.sort(numbers, new ReverseComparator());它允许我们传入一个Comparator实例来指定我们想要的策略
1 public class ReverseComparator implements Comparator{
2   public int compare(String s1, String s2) {
3       return Integer.compare(s1.length(), s2.length());
4  }
5 }

 二、实际项目中的应用:简单工厂+策略模式结合
 UML类图如下:

定义了一个 ShowDateFactory 工厂类,用于管理和获取不同风格的 ShowDateStrategy 策略对象

 1 public class ShowDateFactory {
 2 
 3     private ShowDateFactory() {}
 4 
 5     private static final Map<ShowDateStyleEnum, ShowDateStrategy> MAP = new HashMap<>();
 6 
 7     public static void setMap(ShowDateStyleEnum strategy, ShowDateStrategy showDateStrategy) {
 8         MAP.putIfAbsent(strategy, showDateStrategy);
 9     }
10 
11     public static ShowDateStrategy getMap(ShowDateStyleEnum strategy) {
12         return MAP.get(strategy);
13     }
14 }

具体策略类 FuzzyDateStyle

 1 @Service
 2 public class FuzzyDateStyle implements ShowDateStrategy {
 3     /**
 4      *  将策略类注册到工厂中,以便后续可以通过工厂类获取相应的策略对象
 5      *
 6      */
 7     @PostConstruct
 8     public void init() {
 9         ShowDateFactory.setMap(strategySign(), this);
10     }
11 
12     /**
13      * 模糊时间样式
14      *
15      * @return String
16      */
17     @Override
18     public ShowDateStyleEnum strategySign() {
19         return ShowDateStyleEnum.SHOW_DATE_FUZZY;
20     }
21 
22 }

  说明:上面这段代码这段代码使用了 @PostConstruct 注解,表明该方法会在该类被 Spring 容器初始化时执行。在系统初始化的时候,策略类就会被注册到工厂,而不需要手动在其他地方显式地调用注册方法。这种自动注册的机制使得系统更加灵活,可以动态地添加新的策略类而无需修改工厂类。在使用该策略工厂时,只需要调用工厂类的相应方法就能获取到对应的策略对象。

  除了上面这种方式,还可以进行动态加载配置文件,通过反射动态地加载这些策略类、创建策略对象实现策略模式

  1. 创建属性文件(例如 strategies.properties)
  creditCard=com.example.CreditCardPayment
  payPal=com.example.PayPalPayment

  2. 定义工厂类:PaymentStrategyFactory,以动态加载配置文件中的策略类信息

 1 public class PaymentStrategyFactory {
 2     private static final Map<String, Class<? extends PaymentStrategy>> strategies = new HashMap<>();
 3 
 4     static {
 5         loadStrategies();
 6     }
 7 
 8     private static void loadStrategies() {
 9         Properties properties = new Properties();
10         try {
11             properties.load(PaymentStrategyFactory.class.getClassLoader().getResourceAsStream("strategies.properties"));
12         } catch (IOException e) {
13             e.printStackTrace();
14         }
15 
16         for (String strategyName : properties.stringPropertyNames()) {
17             String className = properties.getProperty(strategyName);
18             try {
19                 Class<? extends PaymentStrategy> strategyClass = Class.forName(className).asSubclass(PaymentStrategy.class);
20                 strategies.put(strategyName, strategyClass);
21             } catch (ClassNotFoundException | ClassCastException e) {
22                 e.printStackTrace();
23             }
24         }
25     }
26 
27     public static PaymentStrategy getPaymentStrategy(String strategyName) {
28         Class<? extends PaymentStrategy> strategyClass = strategies.get(strategyName);
29         if (strategyClass == null) {
30             throw new IllegalArgumentException("Unknown payment strategy: " + strategyName);
31         }
32 
33         try {
34             return strategyClass.getDeclaredConstructor().newInstance();
35         } catch (Exception e) {
36             throw new RuntimeException("Failed to create payment strategy", e);
37         }
38     }
39 }

   三、算法的分析

   1.  策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
   2. 在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色
   3. 策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度

  4. 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象,这本身并没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化地减轻了客户端的职责

 

  四、 策略模式的使用场景

  •   一个项目中有许多类,它们之间的区别仅在于它们的行为,希望动态地让一个对象在许多行为中选择一种行为时;
  •   一个项目需要动态地在几种算法中选择一种时;
  •   一个对象有很多的行为,不想使用多重的条件选择语句来选择使用哪个行为时。

  通过策略模式将策略的定义、创建、使用解耦,让每一部分都不至于太复杂,也去除了if...else这样的条件判断语句,代码的可维护性和可拓展性都提高了。

 

 

参考链接:

https://mp.weixin.qq.com/s/gB1nM4q9PculNVZJr9NSHA

https://design-patterns.readthedocs.io/zh-cn/latest/behavioral_patterns/strategy.html

posted @ 2023-10-01 22:20  欢乐豆123  阅读(8)  评论(0编辑  收藏  举报