【阅读笔记】Head First Java
Head First 设计模式
1.设计模式入门
问题:实现各种不同的鸭子。

Duck() 是一个抽象超类,其具体实现类 MallardDuck() 和 RedheadDuck() 继承超类 Duck() 并实现了抽象方法 display()。
现在需要让鸭子能飞,解决办法是在超类 Duck 上增加一个 fly() 方法。

但是这样做会存在严重的问题:并非所有的鸭子都是会飞的。得到的结论:为了复用而盲目使用继承结果并不完美。

使用继承可能会导致子类中有一些父类中有但是自己不应该有的方法,只能进行覆盖
一种解决办法:将 fly() 这个功能抽离出来,放到一个接口中。实现接口无法达到代码的复用,因为每种会飞的鸭子都需要单独实现这个接口里面的方法,而它们会飞的行为有可能是相同的。

每当新出现一个鸭子类型都需要判断这个鸭子是否具备飞的特性,如果能飞则实现这个 Flyable 接口,否则不实现这个接口。
不管当初软件设计得多好,一段时间之后,总是需要成长与改变,否则软件就会死亡。
设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分的代码需要被抽出来,和其
他稳定的代码有所区分。下面是这个原则的另一种思考方式:会变化的部分取出井封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分。把会变化的部分取出并“封装”起来,好让其他部分不会受到影响。
由于 Duck 类内的 fly() 和 quack() 会随着鸭子的不同而改变,将这两个行为从Duck类中分开,建立一组新类来代表每个行为。

设计元组:针对接口编程,而不是针对实现编程。
所以这次鸭子类不会负责实现 Flying 与 Quacking 接口,反而是由我们制造一组其他类专门实现 FlyBehavior 与 QuackBehavior,这就称为 行为 类。由行为类而不是 Duck 类来实现行为接口。
在我们的新设计中,鸭子的子类将使用接口(Fly Behavior与 Quack Behavior)所表示的行为,所以实际的“实现不会被绑
死在鸭子的子类中。(换句话说,特定的具体行为编写在实现了 Fly Behavior与 QuakcBehavior的类中)

这样的设计,可以让飞行和呱呱叫的动作被其他的对象复用,因为这些行为已经与鸭子类无关了。而我们可以新增一些行为,不会影响到既有的为类,也不会影响“使用”到飞行行为的鸭子类。
关键在于,鸭子现在会将飞行和呱呱叫的动作“委托”(delegate别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法。
首先在 Duck 类中加入两个实例变量,声明为接口类型

最后的实现效果:
请注意,我们描述事情的方式也稍有改变。不再把鸭子的行为说成是“一组行为”,我们开始把行为想成是一族算法”。想想看,在 SimUDuck的设计中,算法代表鸭子能做的事(不同的叫法和飞行法)这样的做法也能很容易地用于用一群类计算不同州的销售税金

设计原则:多用组合,少用继承
“有一个”可能比“是一个”更好。
当你将两个类结合起来使用,如同本例一般,这就是组合(composition)。这种做法和“继承不同的地方在于,鸭子的行为不是继承来的,而是和适当的行为对象“组合”来的。
策略模式 (
Strategy Pattern)定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

浙公网安备 33010602011771号