定义:
定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
书中P9的原话如下:
找出应用中可能需要变化之处,把他们独立出来,不用和那些不需要变化的代码混在一起
当然书中也提供了另外一种思考方式(也是在第九页的下方)
把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部门,而不影响不需要变化地其他部门
转换的思想:
把会变化的部分取出并“封装”起来,好让其他部门不会受到影响。
这样整的结果:
代码变化引起的不经意后果变少,系统变得更有弹性。
将会下方中讲解如何用到这个原则
书中原话:P11
首先得懂得“接口”这个概念:
接口:在java中主要是用于定义“行为”(也就是动作),然后让子类实现该接口时,实现该方法。
另外,接口的另外一种作用:是多态。可以在“运行时”动态地“改变”。(引入一个问题:说明是“运行时”,我的理解是:在程序跑的过程中,可以进行调用不同的该接口的实例去切换 – 例如:一个游戏中,猎人可以切换不同的武器进行攻击。那么武器就是一个接口,斧头以及匕首都是对应的实现类,在程序的运行的过程中,可以进行在不同的场景切换不同的武器【书中P34页】)
多态: 程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。
在P12页中有更详细对“针对接口编程”的说明:
针对接口编程 真正意思是:“针对超类型(supertype)编程”【抽象超类型可以是抽象类或者接口】
针对超类型编程 == “变量的声明类型应该是超类型(Animal a) ,通常是一个抽象类或者是一个接口,如此,主要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着,声明类时不用理会以后执行时的真正对象类型”
组合前提要懂得一个概念: “有一个”。
例如: 一个鸭子里面“有一个”行为:飞行行为类,那么可以将飞行行为类和鸭子类进行组合在一起。
组合的好处:使用组合建立系统具有很大的弹性,不仅可将算法族封装成类,更可以“在运行时动态地改变行为”,只要组合地行为对象符合正确地接口标准即可。
概念以及原则讲完后,那么就从书中copy例子了。
有一个鸭子,会叫、会游泳,有展示自己地行为。
1.1 使用标准地OO技术,设置一个鸭子的超类:
1.2 突然新增一个需求,鸭子有飞行的行为:
1.3 可是新增一个“橡皮鸭子”继承了鸭子超类,突然有一个问题了:橡皮鸭子怎么飞呢?
1.4 于是乎,从继承的角度来讲,鸭子超类中的fly()方法设置为抽象方法,让所有的子类都重新覆盖fly()方法。
至此,引出的一个问题:
绿头鸭、红头鸭都会飞,可让他们重新覆盖这些方法的话,重复有冗余。
2.1 既然fly()是抽象方法,那为何不定义说哪个鸭子需要实现飞行fly方法的话,那就让他去实现算了。
于是乎得到如下图片:
2.1的方式虽然解决部分实例问题(橡皮鸭),但是会造成代码无法复用了(举个栗子:如果有48个不同类型的Duck,那么每个Duck都需要重新覆盖fly方法。。。太多了,并且后期假如每一个鸭子都需要修改fly里面的具体实现的话,,,会奔溃的)
回顾第一点和第二点,是否觉得问题好麻烦,这也不对,那也不对的。
那么,把所有东西都不管着先 – 把问题归零
上述的内容中,整理出如下内容:
不会变化的部分:
变化的部分:
为了要把两个行为从Duck类中分开,建立一组新类来代表每个行为。
到此,下一步工作是如何设计鸭子的行为。 提示: 行为 是动作,那么与之挂钩的应该是接口
如何设计实现飞行和呱呱叫的行为的类呢?-- 在一切能有弹性的基础上去设计实现。
如果在鸭子类中包含设定行为的方法,那么-》在“运行时”动态的“改变”绿头鸭的飞行行为。(这里其实包含了另一种的设计原则:组合 – 什么是组合,在这里我的定义是:在主要类(Duck)中的接口(FlyBehavior、QuackBehavior)或者抽象类的实例变量,他们组合在主要的类中,然后如果独立出来便没有什么意义,他们是主要类中的一部分,这便是组合。组合并不是什么实体,而是一种关系,值得是主体以及被分离出来的部分(可从uml中学习)的一种关系)。
组合: 在uml中,组合就是“有一个”(废话:有一个就是组合咯)。组合从字面上的定义上来说:组合成主类的一部分,被分出来后,没有什么意义了。
代码架构:
4.1 行为接口
FlyBehavior.java
package com.behavior;
public interface FlyBehavior {
public void fly();
}
QuackBehavior.java
package com.behavior;
public interface QuackBehavior {
void quack();
}
4.2 接口实现类
4.2.1 FlyBehavior的接口实现类
FlyWithWings.java
package com.behavior.impl;
import com.behavior.FlyBehavior;
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("用翅膀飞");
}
}
FlyRocketPowered.java
package com.behavior.impl;
import com.behavior.FlyBehavior;
public class FlyRocketPowered implements FlyBehavior {
public void fly() {
System.out.println("我是用火箭飞的");
}
}
FlyNoWay.java
package com.behavior.impl;
import com.behavior.FlyBehavior;
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("这是不能飞");
}
}
4.2.2 QuackBehavior的接口实现类
Quack.java
package com.behavior.impl;
import com.behavior.QuackBehavior;
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("呱呱叫");
}
}
Squeak.java
package com.behavior.impl;
import com.behavior.QuackBehavior;
public class Squeak implements QuackBehavior {
public void quack() {
System.out.println("叽叽叫");
}
}
MuteQuack.java
package com.behavior.impl;
import com.behavior.QuackBehavior;
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("不会叫");
}
}
4.3 Duck抽象类以及它的子类
Duck.java
package com.entity;
import com.behavior.FlyBehavior;
import com.behavior.QuackBehavior;
/**
* 鸭子类,为抽象类
*/
public abstract class Duck {
QuackBehavior quackBehavior;
FlyBehavior flyBehavior;
public void swim(){
System.out.println("I can swin");
}
// 展示样貌,子类必须实现它
public abstract void display();
// 父类调用组合的方法
public void performQuack(){
quackBehavior.quack();
}
// 父类中调用组合的方法 -- 利用多态,调用运行时所赋值的真正实例
public void performFly() {
flyBehavior.fly();
}
// 运行时可调用
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
// 运行时可调用
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
MallardDuck.java
package com.entity;
import com.behavior.impl.FlyWithWings;
import com.behavior.impl.Quack;
/**
* 绿头鸭
*/
public class MallardDuck extends Duck{
// 这里还是不够灵活的--弹性不足的情况
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("这是绿头鸭");
}
}
ModelDuck.java
package com.entity;
import com.behavior.impl.FlyNoWay;
import com.behavior.impl.Quack;
public class ModelDuck extends Duck {
public ModelDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyNoWay();
}
public void display() {
System.out.println("绿头鸭");
}
}
4.4 调用
package com.cxx;
import com.behavior.impl.FlyNoWay;
import com.behavior.impl.FlyRocketPowered;
import com.behavior.impl.Squeak;
import com.entity.Duck;
import com.entity.MallardDuck;
import com.entity.ModelDuck;
public class strategypattern {
public static void main(String[] args) {
Duck mallard = new MallardDuck();
mallard.display();
mallard.performFly();
mallard.performQuack();
System.out.println("---------------------");
// 运行时改变行为
mallard.setFlyBehavior(new FlyNoWay());
mallard.setQuackBehavior(new Squeak());
mallard.performFly();
mallard.performQuack();
System.out.println("======");
Duck modelDuck = new ModelDuck();
modelDuck.display();
modelDuck.performFly();
// 运行时改变为用火箭飞
modelDuck.setFlyBehavior(new FlyRocketPowered());
modelDuck.performFly();
}
}
5.输出
这是绿头鸭
用翅膀飞
呱呱叫
---------------------
这是不能飞
叽叽叫
======
绿头鸭
这是不能飞
我是用火箭飞的
如何使用该模式呢?
第一点:抽象分离出行为,行为有“算法族”的时候,并且能够“组合”在主类中。
关键字:主类、行为、算法族、组合、多态