Head First Design Parttern学习笔记(to be continued)

一、策略模式(Strategy Pattern)

设计一个父类Duck,定义并实现了fly()和quack()方法,定义abstract方法Display。子类MallardDuck和RedheadDuck继承Duck,并实现各自的Display方法。如下图:

image 图1

1 继承的缺点

step 1:增加子类RubberDuck(橡皮鸭),继承Duck。如下图:

image 图2

于是问题1出现了:橡皮鸭会fly(),会quack()(嘎嘎叫)。---------------------------

继承缺点1:父类的非abstract方法,会作用于所有子类。实现代码重用性的同时,造成了极大的不灵活,甚至错误。

step 2:在RubberDuck中,覆盖fly()和quack(),使之不会飞,叫声为squeak(吱吱叫)。如下图:

image 图3

出现问题2:我想增加DecoyDuck(),诱饵鸭,诱饵鸭是木头假鸭,不会飞也不会叫。于是又得覆盖fly方法,内容完全与RubberDuck的fly方法一样,代码重复;再覆盖quack,不叫。如果我想在增加动力鸭呢,不会叫但会飞。。。。。。可怕的代码重复。

继承缺点2:如对父类的方法覆盖来实现个性化,造成代码在各子类中重复。

继承缺点3:无尽的覆盖,导致代码一致性差,很难知道所有鸭子的全部行为。

step 3:我想增加一头贪吃鸭,平时不叫,想吃东西时叫。出现问题3:oh,如何动态改变鸭子的行为?

继承缺点4:在运行时很难改变行为。

2 利用接口如何?

把fly和quack从Duck父类中剥离出来,分别放进flyable和quackable接口。这样一来,只有会飞的鸭子来实现flyable接口,会叫的鸭子来实现quackable接口。如下图:

image 图4

这真是一个笨主意,重复的代码更多。因为每个会飞或会叫的鸭子子类,都得去实现一遍flyable或quackable方法。

3 解决之道

设计原则一:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。

fly和quack行为,会随鸭子的不同而改变。所以我们将把他们从Duck类中取出来,建立一组新类来代表每个行为。

设计原则二:针对接口编程,而不是针对实现编程。

我们利用接口代表每个行为,比方说,FlyBehavior与QuackBehavior,而行为的每个实现都将实现其中的一个接口。鸭子类不负责实现flyable和quackable接口,而是由我们制造一组其他类专门来实现FlyBehavior和QuackBehavior,这就称为“行为”类。这样,我们就把鸭子和行为分离开来,而以前的做法是:行为来自与父类的具体实现,或是子类的覆盖实现。这两种做法都是依赖于“实现”,我们想描述的的鸭子,被实现绑得死死的。

实质上,针对接口编程即是舍弃继承,使用组合。即是把各个行为的具体实现(行为为可变部分)组合成一种特性,赋给对应的Duck。如把FlyBehavior的不会飞的实现,和QuackBehavior的squeak(吱吱叫)实现,组合起来,和Duck父类和在一起,表示橡皮鸭。

于是,我们整合鸭子的行为如下:

Duck

FlyBehavior flyBehavior
QuackBehavior quackBehavoior
performQuack()
performFly()
swim()
display()

public class Duck{

QuackBehavior quackBehavior;

//还有更多

public void performQuack(){

          quackBehavior.quack();

}

}

public class MallardDuck extends Duck{

    public MallardDuck(){

    quackBehavior = new quack();

    flayBehavior = new FlyWithWings();

}

public void display(){

    System.out.println(“I’m a real Mallard duck”);

}

}

4 动态设定鸭子行为,增加2个方法:

Duck

FlyBehavior flyBehavior
QuackBehavior quackBehavoior
performQuack()
performFly()
swim()
display()
setFlyBehavior()
setQuackBehavior()

public void setFlyBehavior(FlyBehavoir fb){

    flyBehavior = fb;

}

setQuackBehavior()类似。

5 封装行为的大局观:

我们把可变的一组行为,如Quack,叫做一族算法,加以封装。鸭子可以不关注算法的具体实现,只是委托算法去做某种行为即可。如委托Quack算法去吱吱叫。

鸭子的不变部分通过继承超类得到,鸭子的可变部分,通过组合所需要的行为对象得到。这里用到了以下原则:

设计原则3:多用组合,少用继承

策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此算法让算法的变化,独立于使用算法的客户。

综上,该示例设计如下图:

image

图5

http://wickedlysmart.com/headfirstdesignpatterns/code.html (souce code download address)

6 C语言的策略模式---鸭子的C实现

image

 

image

 

二、观察者模式(Observer Pattern)

观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,其他所有依赖者都会收到通知并自动更新。

出版者(Subject)+订阅者(Observer)=观察者模式。

定义观察者模式:类图

image 图6

Subject是被依赖方,Observer是依赖方;Subject拥有数据并提供访问数据的方法,Observer使用Subject提供的方法访问数据,获取和使用这些数据。Subject负责数据的更新,并通知Observer,Observer接收到数据有更新的通知后,自己决定是否要去获取新数据,并进行相应动作。

松耦合的威力:当两个对象之间的松耦合,他们依然可以交互,但是不太清楚彼此间的细节。观察者提供了一种对象设计,让主题和观察者之间松耦合。

改变主题或观察者之间的任何一方,并不会影响另一方。因为两者是松耦合的,所以只要他们之间的接口仍被遵守,我们就可以自由改变他们。

设计原则4:为了交互对象之间的松耦合设计而努力。

松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖性降到了最低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值