要做一个模拟鸭子的设计,鸭子可以游泳,可以呱呱叫(Quack),很容易的,可以设计一个Duck超类,超类中实现了swim()方法和quack()方法,然后不同种类的鸭子继承该超类即可。但这种实现在扩展时存在缺陷,比如飞翔(Fly),野鸭可以Fly,但家鸭不会,如果在超类中实现fly()抽象函数,然后子类重写方式,必须每个子类都需要为继承的fly()函数重写代码,这样都会飞的鸭子子类们都要写一遍,势必造成重复代码浪费。此外,不会飞的实例中存在fly()函数也不雅观^_^。
那么用接口实现如何呢?
OH,My God,这种方式是一种笨方法,容易造成重复的代码变多,而且无法复用!!!!
现在来介绍下我们的第一个设计原则:
分离意味着,代码的变化不会影响不变的部分,系统更加具有弹性奥!!!
我们已经知道Duck类中,fly()和quack()随着鸭子的不同而不同,而且不同的鸭子,飞翔姿势也可能不同,因此我们从Duck类中分离出这两种行为,分别建立两种行为接口:FlyBehavior接口与QuackBehavior接口。
我们首先来学习第二个设计原则:
,这次Duck类不会实现这两种接口,而是另外定义额外的行为类专门实现这两个接口。这种与之前的行为来自超类的具体实现或是子类implements某个接口由子类自行实现不同【基于“实现”的方式,限制的恨死,没办法更改行为(除非写更多代码)】。
针对"接口"编程,真正意思是"针对超类型编程",关键就在于多态,利用多态,程序可以针对超类型编程,执行时会根据实际情况执行真正的行为,不会被绑死在超类性的行为上。
新的实现方式是:鸭子子类将使用实现了行为接口的行为类。
现在谈一下第三个设计原则:
,使用组合建立系统具有很大的弹性,不仅可将算法族封装成类,更可以在"运行时动态地改变行为",只要组合的行为对象符合正确的接口标准即可。
如下是模拟鸭子的类图:Duck的子类可以在自己的构造函数中对自己继承的属性flyBehavior和quackBehavior赋值,如:
flyBehavior = new FlyWithWings();
然后Duck子类实例就可以调用继承而来的performFly(){flyBehavior.fly()}飞翔,也可以调用继承而来的
setFlyBehavior(FlyBehavior fb)
{
flyBehavior = fb;
}
来动态改变飞翔的行为