设计原则
- 找出应用中可能需要变化之处,把它们独立出来,不要和哪些那些不需要变化的代码混在一起。
- 面向接口编程,而不是面向实现编程。面向接口编程,真正的意思是面对超类型(supertype)编程,即“变量”的声明类型应该是超类型,通常是一个抽象类或者是一个接口。这样,只要是 具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着声明类时不用理会以后执行的真正的对象类型。
- 多用组合,少用继承。
定义
定义了算法族(把具有相同特性的行为看作一族算法,比如鸭子的飞,不同的飞法即不同的算法),分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
根据相同特性的行为族创建supertype(接口或者抽象类),然后根据supertype构建出具体实现类。在需要该特性的客户基类中加入supertype的实例变量,然后根据子类所需要的行为的不同在子类构造器中为该变量赋予不同的具体实现类对象(根据supertype构建),也可以在基类中加入实例变量的set方法,那么就可以在运行时动态设定行为了(即通过set赋予不同的行为实例)。
实现方式
- 定义Strategy和Context接口。Strategy和Context接口必须使得ConcreteStrategy能够有效的访问它所需要的Context中的任何数据,反之亦然。
一种办法是让Context将数据放在参数中传递给Strategy操作—也就是说,将数据发送给Strategy。这使得Strategy和Context解耦。但另一方面,Context可能发送一些Strategy不需要的数据。
另一种办法是让Context将自身作为一个参数传递给Strategy,该Strategy再显式地向该Context请求数据。或者,Strategy可以存储对它的Context的一个引用,这样根本不再需要传递任何东西。这两种情况下,Strategy都可以请求到它所需要的数据。但现在Context必须对它的数据定义一个更为精细的接口,这将Strategy和Context更紧密地耦合在一起。
- 使Strategy对象成为可选的。如果即使在不使用额外的Strategy对象的情况下,Context也还有意义的话,那么它还可以被简化。Context在访问某Strategy前先检查它是否存在,如果有,那么就使用它;如果没有,那么Context执行缺省的行为。这种方法的好处是客户根本不需要处理Strategy对象,除非它们不喜欢缺省的行为。比如TreeSet类型的对象在创建时可以选择传入Comparator对象也可以传入,这就是策略模式的一个例子。
什么时候使用策略模式
解决类直接实现接口造成的方法具体代码不能复用可以考虑采用策略模式,更本质的讲,是想要设计出可复用、可扩展的行为族时。在这里的族可以是根据一个(抽象)基类来创建,也可以像是本例中根据一个接口FlyBehavior来创立。