策略模式

一、策略模式的介绍

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();
    }
}

 

上一篇:WP8:Unity3D之间的值传递


下一篇:用 Flask 来写个轻博客 (12) — M(V)C_编写和继承 Jinja 模板