在策略模式中,我们创建表示各种策略的对象(比如各种算法) 和 一个行为 Context对象 随着策略对象的改变
从而改变Context 对象的执行算法。
**意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
**主要解决:**在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
**何时使用:**一个系统有许多许多类,而区分它们的只是他们直接的行为。
**如何解决:**将这些算法封装成一个一个的类,任意地替换。
**关键代码:**实现同一个接口。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
混合模式 = 其他模式 比如 工厂模式 模板模式 等 根据业务情况而使用
常用的 就是 工厂模式+ 策略模式+单例 这样就能有效管理 类膨胀 和不断new对象 的问题
下面会简单使用混合模式
我们先来演示 策略模式
先写算法的接口
public interface Strategy { public int doOperation(int num1, int num2); }
我们先写3个算法 加,减,乘 然后继承算法接口
OperationAdd
public class OperationAdd implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 + num2; } }
OperationSubtract
public class OperationSubtract implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 - num2; } }
OperationMultiply
public class OperationMultiply implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 * num2; } }
我们在写一个算法调度器
Context
public class Context { //算法接口 private Strategy strategy; //构造函数 接收 实现算法接口的 实现类 public Context(Strategy strategy){ this.strategy = strategy; } //调用实现类中的算法 public int executeStrategy(int num1, int num2){ return strategy.doOperation(num1, num2); } }
然后测试
public class test { public static void main(String[] args) { //使用 加法策略 Context context = new Context(new OperationAdd()); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); //使用 减法策略 context = new Context(new OperationSubtract()); System.out.println("10 - 5 = " + context.executeStrategy(10, 5)); //使用 乘法策略 context = new Context(new OperationMultiply()); System.out.println("10 * 5 = " + context.executeStrategy(10, 5)); } }
结果:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
上面可能你不太理解什么是 类膨胀 简单来说就是 类太多了 不好管理 既然是类太多了 那么我们可以交个工厂模式来 管理 来减轻我们 的负担 已经重复new 对象 造成的内存堆积
我们在上面实例代码基础上增加 工厂模式
创建配置文件 将所有策略类路径放入配置文件里
通过需求创建对应的实例 给调度器
调度器 调用策略类的方法
结构图
OperationAdd , OperationMultiply , OperationSubtract , Strategy
这些上面已经 有了 我们就将没有的 贴上去了
benas.properties
OperationAdd=cn.mb.OperationAdd OperationMultiply=cn.mb.OperationMultiply OperationSubtract=cn.mb.OperationSubtract
Factory
import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class Factory { private static Map<String,Object> map=new HashMap<String,Object>(); static{ Properties pro=new Properties(); InputStream resource = Factory.class.getClassLoader().getResourceAsStream("benas.properties"); try { pro.load(resource); Enumeration<Object> keys = pro.keys(); while (keys.hasMoreElements()){ String key=(String)keys.nextElement(); String value=pro.getProperty(key); Object o = Class.forName(value).newInstance(); map.put(key,o); } } catch (Exception e) { e.printStackTrace(); } } //pattern=true 单例 pattern=false或者null多例 public static Object getBean(String name,Boolean pattern){ if (pattern){ return map.get(name); }else{ Properties pro=new Properties(); InputStream resource = Factory.class.getClassLoader().getResourceAsStream("benas.properties"); try { pro.load(resource); } catch (IOException e) { e.printStackTrace(); } String accountDao = pro.getProperty(name); try { return Class.forName(accountDao).newInstance(); } catch (Exception e) { System.err.println("没有找到此类文件 请检xml文件中bens标签 中的 name属性=文件名 或者写class=类性路径 是否正确 "); e.printStackTrace(); return null; } } } }
测试
import cn.mb.Strategy; import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class test { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("加法", "OperationAdd"); map.put("减法", "OperationSubtract"); map.put("乘法", "OperationMultiply"); Context context = new Context((Strategy) Factory.getBean(map.get("加法"), true)); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); } }
我们 可以通过改变 key的值来 从而改变 引用的 策略类 也就不用使用 大量的 if else 来判断 了
结果:
10 + 5 = 15
如果不解决 类膨胀问题 那么我们需要不断的使用 if - else if … 来 进行判断 如果你有100个策略类呢 ?
一般公司 要求 一个方法不让写过多的代码 因为会导致代码审阅 困难 …