package com.cheng.zenofdesignpatterns.patterns.strategy;
import android.view.View;
import com.cheng.zenofdesignpatterns.ZoDPChapterBaseActivity;
import com.cheng.zenofdesignpatterns.patterns.strategy.calculator.Add;
import com.cheng.zenofdesignpatterns.patterns.strategy.calculator.CalculatorContext;
import com.cheng.zenofdesignpatterns.patterns.strategy.calculator.Sub;
import com.cheng.zenofdesignpatterns.patterns.strategy.common.ConcreteStrategy1;
import com.cheng.zenofdesignpatterns.patterns.strategy.common.ContextRole;
import com.cheng.zenofdesignpatterns.patterns.strategy.common.IStrategy;
import com.cheng.zenofdesignpatterns.patterns.strategy.smartexpress.BackDoor;
import com.cheng.zenofdesignpatterns.patterns.strategy.smartexpress.BlockEnemy;
import com.cheng.zenofdesignpatterns.patterns.strategy.smartexpress.GivenGreenLight;
import com.cheng.zenofdesignpatterns.patterns.strategy.smartexpress.SmartExpress;
import com.cheng.zenofdesignpatterns.patterns.strategy.strategyenum.CalculatorEnum;
public class ZoDPStrategyActivity extends ZoDPChapterBaseActivity {
@Override
protected void initData() {
mTitleTV.setText("策略模式");
String content = "定义:\n" +
"Define a family of algorithms, encapsulate each one, and make them " +
"interchangeable.\n" +
"定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。\n\n" +
"策略模式的优点\n" +
"- 算法可以自由切换\n" +
"这是策略模式本身定义的,只要实现抽象策略,它就成为策略家族的一个成员,通过" +
"封装角色对其进行封装,保证对外提供‘可自由切换’的策略。\n" +
"- 避免使用多重条件判断\n" +
"使用策略模式后,可以由其他模块决定采用何种策略,策略家族对外提供的访问接口" +
"就是封装类,简化了操作,同时避免的条件语句判断。\n" +
"- 扩展性良好\n" +
"策略模式的缺点\n" +
"- 策略类数量增多\n" +
"每一个策略都是一个类,复用的可能性很小,类数量增多。\n" +
"- 所有的策略类都需要对外暴露\n" +
"上层模块必须知道有哪些策略,然后才能决定使用哪个策略,这与迪米特法则是相违背" +
"的。这是原装策略模式的一个缺点,幸运的是,可以使用其他模式来修正这个缺陷,如" +
"工厂方法模式、代理模式或享元模式。\n\n" +
"使用场景\n" +
"- 多个类只有在算法或行为上稍有不同的场景\n" +
"- 算法需要自由切换的场景\n" +
"- 需要屏蔽算法规则的场景\n\n" +
"注意事项\n" +
"如果系统中的一个策略家族的具体策略数量超过4个,则需要考虑使用混合模式,解决策略" +
"类膨胀和对外暴露的问题,否则日后的系统维护很麻烦。\n\n" +
"扩展\n" +
"* 策略枚举\n" +
"- 它是一个枚举\n" +
"- 它是一个浓缩了的策略模式的枚举\n" +
"注意 策略枚举是一个非常优秀和方便的模式,但是它受枚举类型的限制,每个枚举项都是" +
"public、final、static的,扩展性受到了一定的约束,因此在系统开发中,策略枚举一" +
"般担当不经常发生变化的角色。\n\n" +
"最佳实践\n" +
"策略模式单独使用的地方比较少,因为它有致命的缺陷:所有的策略都需要暴露出去,这样才" +
"方便客户端决定使用哪一个策略。在实际项目中,一般通过工厂方法模式来实现策略类的声明," +
"可以参考混编模式。";
mContentTV.setText(content);
}
@Override
public void onClick(View v) {
// 1. 模拟诸葛亮的锦囊妙计
SmartExpress smartExpress;
// 刚刚到吴国的时候拆第一个
System.out.println("---刚刚到吴国的时候拆第一个---");
smartExpress = new SmartExpress(new BackDoor()); // 拿到妙计
smartExpress.operate(); // 拆开执行
System.out.println("\n\n");
// 刘备乐不思蜀了,拆第二个了
System.out.println("---刘备乐不思蜀了,拆第二个了---");
smartExpress = new SmartExpress(new GivenGreenLight());
smartExpress.operate(); // 执行了第二个锦囊了
System.out.println("\n\n");
// 孙权的小兵追了,咋办?拆第三个
System.out.println("---孙权的小兵追了,咋办?拆第三个---");
smartExpress = new SmartExpress(new BlockEnemy());
smartExpress.operate(); // 孙夫人退兵
System.out.println("\n\n");
/*
* 问题来了:赵云实际不知道是那个策略呀,他只知道拆第一个锦囊,
* 而不知道是BackDoor这个妙计,咋办? 似乎这个策略模式已经把计谋名称写出来了
*
* 错!BackDoor、GivenGreenLight、BlockEnemy只是一个代码,你写成first、
* second、third,没人会说你错!
*
* 策略模式的好处就是:体现了高内聚低耦合的特性呀
*/
// 2. 通用策略模式的演示
// 声明出一个具体的策略
IStrategy strategy = new ConcreteStrategy1();
// 声明出上下文对象
ContextRole context = new ContextRole(strategy);
// 执行封装后的方法
context.doAnythinig();
// 3. 策略模式实现计算器
// 加符号
final String ADD_SYMBOL = "+";
// 减符号
final String SUB_SYMBOL = "-";
// 输入的两个参数是数字
int a = 50;
String symbol = "+"; // 符号
int b = 80;
System.out.println("输入的参数为:" + a + symbol + b);
//上下文
CalculatorContext calculatorContext = null;
//判断初始化哪一个策略
if(symbol.equals(ADD_SYMBOL)){
calculatorContext = new CalculatorContext(new Add());
}else if(symbol.equals(SUB_SYMBOL)){
calculatorContext = new CalculatorContext(new Sub());
}
System.out.println("运行结果为:" + a + symbol + b + "=" + calculatorContext.exec(a, b, symbol));
// 4. 策略枚举
//输入的两个参数是数字
int a2 = 121;
String symbol2 = "+"; //符号
int b2 = 321;
System.out.println("输入的参数为:" + a2 + symbol2 + b2);
System.out.println("运行结果为:"+a + symbol + b + "=" + CalculatorEnum.ADD.exec(a, b));
a2 = 131;
b2 = 333;
symbol2 = "-";
System.out.println("输入的参数为:" + a2 + symbol2 + b2);
System.out.println("运行结果为:"+a + symbol + b + "=" + CalculatorEnum.SUB.exec(a, b));
}
}