案例展示——Strategy怎么用?
了解一点历史的人都知道商鞅变法,正是由于商鞅变法,奠定了秦国强大的根基,使秦国从一个最弱小的战国迅速成为一个超强战国,奋六世之余烈,终于在秦始皇手上一统天下。可以说,没有商鞅变法,就没有强大的秦国,或许也可以断言,天下将不会由秦朝统一。那么商鞅变法为什么会有这么大的规律呢,现在我们从软件的设计的角度来看看商鞅变法的威力,下面是类图设计:
分析上面的类图:
-
IStrategy:抽象策略类,定义一个执行法律的方法
-
AwardBattle:法律一,鼓励打仗
-
AbolishSlave:法律二,废除奴隶制度
-
DefeatNobility:法律三,推翻贵族的垄断地位,取消封地
-
SYUpdateLaw:商鞅变法,执行法律
看看上面的每一个法律,是不是都透露着变法家的博大情怀。每一个法律就是一个策略,每一次策略的实施都会使秦国发生脱胎换骨的变化。鼓励耕战,使国人争相入军报效国家,国家实力迅速提升;废除奴隶制度,使奴隶得到解放,人人拥护国家,为国效力;最重要的是推翻世族统治,封地收归国有,权利高度集中。正是由于秦国贯彻实施了商鞅变法,才造就了后来的辉煌蓝图。
下面是具体的代码实现:
// 抽象策略类
public interface IStrategy {
// 每天政策都需要切实执行
public void operate();
}
// 法律一:鼓励耕战
public class AwardBattle implements IStrategy {
public void operate() {
System.out.println("奖励有功战士!");
}
}
// 法律二:废除奴隶制
public class AbolishSlave implements IStrategy {
public void operate() {
System.out.println("废除奴隶制度,举国之人皆是国民!");
}
}
// 法律三:推翻贵族统治
public class DefeatNobility implements IStrategy {
public void operate() {
System.out.println("推翻世族,人人平等!");
}
}
// 商鞅变法
public class SYUpdataLaw {
// 构造函数中传入要实施的律法
private IStrategy strategy;
public SYUpdataLaw(IStrategy strategy) {
this.strategy = strategy;
}
// 实施法律
public void operate() {
this.strategy.operate();
}
}
// 开始变法
public class Client {
public static void main(String[] args) {
// 准备好法律,依次颁布实施
SYUpdataLaw ul;
System.out.println("==========前三年:鼓励打仗========");
ul = new SYUpdataLaw(new AwardBattle());
// 执行法律
ul.operate();
System.out.println("==========中三年:废除奴隶制=======");
ul = new SYUpdataLaw(new AbolishSlave());
// 执行法律
ul.operate();
System.out.println("==========时机成熟:推翻世族=======");
ul = new SYUpdataLaw(new DefeatNobility());
// 执行法律
ul.operate();
}
}
// 结果如下:
==========前三年:鼓励打仗========
奖励有功战士!
==========中三年:废除奴隶制=======
废除奴隶制度,举国之人皆是国民!
==========时机成熟:推翻世族=======
推翻世族,人人平等!
上面的例子中就使用到了策略模式,每一个法律就是一个策略,策略用好了,国家就强大了。
深入分析——Strategy是什么?
Strategy的定义
定义: 定义一组算法,将每个算法都封装起来,并且使它们可以相互交换。通用类图设计如下:
-
Context组建:上下文角色,起承上启下的作用,屏蔽高层模块、算法的直接
直接访问,封装可能存在的变化 -
Strategy组建:抽象策略角色,通常是接口,定义每个策略或算法所必须具有的方法和属性
-
ConcreateStrategy组建:具体的策略,实现了Strategy接口
下面是通用代码实现:
// 策略接口
public interface Strategy {
// 执行策略
public void doSomething();
}
// 策略1
public class ConcreateStrategy1 implements Strategy {
public void doSomething() {
System.out.println("执行策略1");
}
}
// 策略2
public class ConcreateStrategy2 implements Strategy {
public void doSomething() {
System.out.println("执行策略2");
}
}
// 妙计锦囊
public class Context {
// 抽象策略
private Strategy strategy = null;
// 在构造函数中设置具体策略
public Context(Strategy strategy) {
this.strategy = strategy;
}
// 执行策略方法
public void doAnything() {
this.strategy.doSomething();
}
}
// 实施策略
public class Client {
public static void main(String[] args) {
// 声明一个具体的策略
Strategy strategy = new ConcreateStrategy1();
// 造一个锦囊
Context context = new Context(strategy);
// 执行策略
context.doAnything();
}
}
Strategy的优点
-
算法可以自由切换
-
避免多重条件判断
-
扩展性良好,新增一个算法只要实现接口就行了
Strategy的缺点
-
策略类数量增多会增加系统的复杂性
-
所有的策略类都需要向外暴露,不利于和高层模块的解耦
策略模式的扩展——策略枚举
直接看代码:
// 枚举的计算类
public enum Calculator {
// 加法运算
ADD("+") {
public int exec(int a, int b) {
return a + b;
}
},
// 减法运算
SUB("-") {
public int exec(int a, int b) {
return a - b;
}
};
String value = "";
// 定义成员值类型
private Calculator(String value) {
this.value = value;
}
// 获得枚举成员的值
public String getValue() {
return this.value;
}
// 声明一个抽象函数
public abstract int exec(int a, int b);
}
// 计算
public class Client {
public static void main(String[] args) {
// 两个参数
int a = 10, b = 20;
System.out.println("运算结果为:" + Calculator.ADD.exec(a, b));
System.out.println("运算结果为:" + Calculator.SUB.exec(a, b));
}
}
程序是什么意思一眼就能看出来,现在来说说什么是枚举策略,下面简单定义一下:
- 是一个枚举类
- 浓缩了策略模式的枚举,换句话说,每一个枚举算法就是策略
参考
《设计模式之禅》