一、策略模式的介绍
1、定义
策略模式定义一组算法,将每个算法都封装起来,并且使它们之间可以互相转换。也就是说,针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换,使得算法可以在不影响到客户端的情况下发生变化。
策略模式涉及到的三个角色:
- 环境角色(Context):又称上下文角色,起到承上启下的作用。用来屏蔽高层模块对策略、算法的直接访问,它持有一个Strategy的引用。
- 抽象策略角色(Strategy):该角色对策略、算法进行抽象,通常定义每个策略或算法必须具有的属性和方法。
- 具体策略角色(ConcreteStrategy):该角色实现抽象策略中的具体操作,含有具体的算法。
策略模式的类图如下:
2、使用场景
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
- 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
- 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
- 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
3、优缺点
(1)优点
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if...else 语句、switch...case 语句。
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
- 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
- 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
- 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
(2)缺点
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
- 策略模式造成很多的策略类,增加维护难度。
二、策略模式的实现
场景描述:刘备去东吴,诸葛亮给赵云的三个锦囊妙计帮助刘备脱险。类图如下:
代码实现:
/**
* 抽象策略角色:锦囊
*/
public interface SilkBag {
/**
* 策略方法
*/
void programme();
}
/**
* 具体策略角色:锦囊A
*/
public class SilkBagA implements SilkBag{
@Override
public void programme() {
System.out.println("见乔国老,把主公娶亲的事情搞得东吴人尽皆知");
}
}
/**
* 具体策略角色:锦囊B
*/
public class SilkBagB implements SilkBag{
@Override
public void programme() {
System.out.println("用谎言(曹操打荆州)骗泡在温柔乡里的主公回去");
}
}
/**
* 具体策略角色:锦囊C
*/
public class SilkBagC implements SilkBag{
@Override
public void programme() {
System.out.println("让孙夫人摆平东吴的追兵,她是孙权妹妹,东吴将领惧她三分");
}
}
/**
* 环境角色
*/
public class Danger {
private SilkBag silkBag;
public void setSilkBag(SilkBag silkBag) {
this.silkBag = silkBag;
}
/**
* 危机的应对方案
*/
public void plan(){
silkBag.programme();
}
}
public class StrategyDemo {
public static void main(String[] args) {
Danger danger = new Danger();
System.out.println("危机一应对方案:");
danger.setSilkBag(new SilkBagA());
danger.plan();
System.out.println("危机二应对方案:");
danger.setSilkBag(new SilkBagB());
danger.plan();
System.out.println("危机三应对方案:");
danger.setSilkBag(new SilkBagC());
danger.plan();
}
}