设计模式之策略模式

Posted ProChick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之策略模式相关的知识,希望对你有一定的参考价值。

1.简要概述

  • 策略模式也叫作决策模式,属于行为型设计模式。
  • 策略模式定义了解决某一个问题的一个算法族,允许用户从该算法族中针对不同的场景选择一个算法解决该问题,同时可以方便的更换算法或者增加新的算法。
  • 策略模式会定义一系列算法,然后对其进行封装并使它们可以相互替换,让算法独立于使用它的客户端。
  • 策略模式的本质就是将不同的算法进行分离,然后选择性的进行实现。
  • 策略模式和状态模式的对象类图类似,并且都是能够动态改变对象的行为。但是状态模式主要是用来解决状态转移的问题,当状态发生变化了,那么对象的行为就会改变;而策略模式主要是用来封装一组可以互相替代的算法族,然后根据需要动态地替换使用的算法。

2.模式结构

👉通常由一个策略接口( 负责定义一个算法族的行为策略方法接口 ),多个具体的策略类( 负责对特定场景下的问题,将解决的行为方法进行实现 ),一个上下文环境类( 负责对策略接口进行管理和维护,然后根据不同的请求设置不同的策略做响应处理 ),一个客户类( 负责调用上下文环境类,然后通过指定某个具体的策略,完成对某个问题的处理)共同组成。

3.实现代码

举例 💡 :假设现在有一个商店在搞促销活动,但是对于不同的用户来说,折扣的力度是不同的。比如:对于新用户来说可以打7折、对于老用户来说可以打6折,但是对于普通用户来说只能打9折,那么这种打折促销的手段就可以使用策略模式进行处理。

打折策略(策略接口)

public interface DiscountStrategy {
	// 定义折扣的方法接口
    void discount();
}

普通用户策略(具体策略类)

public class CommonConsumerStrategy implements DiscountStrategy{
	
    @Override
	public void discount() {
		System.out.println("打九折");
	}
}

新用户策略(具体策略类)

public class NewConsumerStrategy implements DiscountStrategy{
	
    @Override
	public void discount() {
		System.out.println("打七折");
	}
}

老用户策略(具体策略类)

public class OldConsumerStrategy implements DiscountStrategy{
	
    @Override
	public void discount() {
		System.out.println("打六折");
	}
}

商店(上下文环境类)

public class Store {
	private DiscountStrategy strategy;

    // 设置策略
	public setStrategy(DiscountStrategy strategy) {
		this.strategy = strategy;
	}
	
	public void selling() {
        if (strategy != null){
             System.out.println("进行售卖,并" + strategy.discount());
        } else {
             System.out.println("进行售卖,不打折");
        }
	}
}

客户类

// 测试客户端
public class StrategyClient{
    public static void main(String[] args) {
        Store store = new Store();
        store.selling(); // 进行售卖,不打折
        
        // 对于普通用户
        store.setStrategy(new CommonCustomerStrategy());
        store.selling(); // 进行售卖,打九折
        
        // 对于新用户
        store.setStrategy(new NewCustomerStrategy());
        store.selling(); // 进行售卖,打七折
        
        // 对于老用户
        store.setStrategy(new OldCustomerStrategy());
        store.selling(); // 进行售卖,打六折
    }
}

4.优点好处

  • 在策略模式中,我们可以很容易添加新的策略或者修改原有的策略,而不需要改变原有的代码,符合开闭原则。
  • 在策略模式中,提供了一种替代继承的方法,而且保持了继承中代码复用的优点。
  • 在策略模式中,提供了管理相关的算法族的办法, 然后对算法进行了封装,使得客户端不需要知道算法的具体内部逻辑,提高了算法的保密性和安全性。
  • 在策略模式中,避免了程序中使用多重条件转移语句,使得系统更加灵活,并且更加易于扩展。

5.缺点弊端

  • 在策略模式中,每针对一种场景都需要创建一个对应的策略类进行实现,所以如果系统中面对某个问题所存在的解决场景有非常多,那么就会导致整个策略方法族非常庞大,不利于后期系统的维护。
  • 在策略模式中,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。

6.应用场景

  • 当系统中的多个类只区别在表现行为上不同,在运行时需要动态的选择具体要执行的行为的时候,就可以使用策略模式。
  • 当系统中需要在不同情况下使用不同的策略,并且可以根据不同的需求,动态的添加新的策略的时候,就可以使用策略模式。
  • 当系统需要对客户端隐藏具体策略的实现细节,并使每一种策略可以相互独立替换的时候,就可以使用策略模式。

7.应用示例

JDK源码中对于Arrays.sort方法中传入的Comparator对象进行排序的过程

  1. 首先看下方的代码,我们通过Arrays.sort方法对变量a这个数组进行排序,然后通过传入不同的排序比较器得到了不同的排序结果。

    Integer[] a = new Integer[]{1, 5, 7, 2, 3};
    
    // 从小到大比较器
    Comparator<Integer> comparable1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 > o2 ? 1 : -1;
        }
    };
    
    // 从大到小比较器
    Comparator<Integer> comparable2 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 > o2 ? -1 : 1;
        }
    };
    
    Arrays.sort(a, comparable1); // {1, 2, 3, 5, 7}
    Arrays.sort(a, comparable2); // {7, 5, 3, 2, 1}
    
  2. 在这里,Comparator接口就可以看做是策略接口,里面定义了一个compare接口方法。

  3. 在上面的代码中,我们通过匿名类的形式创建了两个Comparator接口的两个子类,分别对compare方法进行了不同的实现,那这两个类就可以看做是具体的策略类。

  4. 在Arrays.sort方法的内部,我们可以看到Comparator接口作为方法的形参,会根据传入实现类的不同完成不同的实现,那么Arrays这个类就可以看作是Comparator接口的上下文环境类。

  5. 所以通过上面的流程分析可以看出,Arrays.sort中关于Comparator的处理过程就采用了策略模式进行实现。

以上是关于设计模式之策略模式的主要内容,如果未能解决你的问题,请参考以下文章

java设计模式之策略模式

设计模式之策略模式

阿昌之丑陋代码优化通过策略模式&模版模式来优化Controller执行流程

设计模式之策略模式

设计模式之策略模式

Javascript设计模式总结之 -- 策略模式