java 设计模式 学习笔记(5) 装饰模式

装饰模式: 动态地给一个对象添加额外的职责。就增加功能来说,装饰模式比增加子类更加灵活。

我承认我看了《大话设计模式》 中的装饰模式,花了一个小时才消化掉,为此,我改写了《大话设计模式》 的例子以便加深印象。

在这里,我简单的以给某个人类穿衣服裤子等行为来表示对一个对象的装饰动作。

1. 根据面向接口编程的原则,建立一个 Humen 类,这个类是一个抽象类,并有一个抽象方法 dress() ,是人类都要穿衣服吧。

/** * 该 类实际上是 装饰模式中的 Component 类,用户可以对 humen 类动态的添加职责 * @author liaogang.pt */ public abstract class Humen { public abstract void dress(); }

2. 建立Baby 类作为 Humen 的子类,并重写 dress 方法。不过Baby 怎么重写dress 方法 ?当然是哭闹说:“我要起床,要穿衣服”。实际上他是不会给自己穿衣服的。

public class Baby extends Humen { @Override public void dress() { // TODO Auto-generated method stub System.out.println("I will get up !"); } }

3. Baby 要起床,但是不会自己穿衣服,这个时候就需要其他人来为 Baby 穿衣服。但是 Baby 今天说我要先穿外套,然后再穿裤子,明天说我要先穿裤子,然后穿外套。或者说今天我就只穿裤子,不穿外套了。对于Baby 的要求,无人能够拒绝。

对于Baby 的不同穿衣要求,我们可以先建立一个的 Decorator 类,用来负责为 Baby 穿衣服。

Decorator 作为抽象装饰类,表示这个类还需要被继承,并希望其子类能够扩展Humen 的功能。因为 Decorator 是抽象类,其必须被继承。同时 Decorator需要保存一个 Humen 引用,这个Humen 就是装饰类需要去装饰的对象。

/** * Decorator抽象类,也是 Humen 的子类。我们在这里可以将 Decorator 看成是 Baby 的父母亲或 其他亲属。 * Decorator 类当然会重写 dress方法,不过在这里,Decorator 的职责就是为Baby 穿衣 * @author liaogang.pt */ abstract class Decorator extends Humen { public Humen humen; public void setHumen(Humen humen) { this.humen = humen; } @Override public void dress() { humen.dress(); } }

4. 既然有抽象类,那么就建立一个JacketDecorator 类作为 Decorator 子类,JacketDecorator 同时也是 Humen 的孙子类,因此也必须重写 dress () 方法,它的 dress()方法 就是听到 Baby 说要起床后就给 Baby 穿 Jacket 。

/** * JacketDecorator 类作用是给Baby 穿 外套 * @author liaogang.pt * */ public class JacketDecorator extends Decorator{ public void dress(){ super.dress(); addJacket(); } public void addJacket(){ System.out.println("add Jacket"); } }

5. 有了穿 外套的类,那还需要一个 为Baby 穿裤子的类,功能和JacketDecorator 类似

/** * 为 Baby 穿裤子的类 * @author liaogang.pt * */ public class TrouserDecorator extends Decorator{ public void dress(){ super.dress(); addTrousers(); } public void addTrousers(){ System.out.print("add trousers") ; } }

6.提一个先给Baby 穿外套,再穿裤子的需求 编写一个测试的类,来验证试验的正确性 :

public class TestDecoratorPattern { public static void main(String[] args){ Baby baby =new Baby(); JacketDecorator jDecorator= new JacketDecorator(); TrouserDecorator tDecorator= new TrouserDecorator(); jDecorator.setHumen(baby); tDecorator.setHumen(jDecorator); tDecorator.dress(); } }

结果是 :

I will get up ! add Jacket add trousers

讨论:

在最后的测试类中,有一个令人容易迷惑的地方:

jDecorator.setHumen(baby);
tDecorator.setHumen(jDecorator);
tDecorator.dress();

为什么能够做到先穿外套,再穿裤子?

首先 jDecorator 中保存了一个 Baby 的对象引用 baby

tDecorator.setHumen(jDecorator); 表示 tDecorator 又保存了一个 JacketDecorator 对象的引用 tDecorator

这三个对象的关系是 jDecorator 保存了 baby ,tDecorator 保存了 jDecorator 。

TrouserDecorator 类中的 dress() 方法:

public void dress(){ super.dress(); addTrousers(); }

从代码可以得知,首先要 执行 父类的 dress() 方法,然后才能执行 TrouserDecorator 的装饰方法,也就是 addTrousers() 方法。回溯到 TrouserDecorator 的父类 Decorator 的 dress()方法:

public void dress() { humen.dress(); }

humen 对象就是通过 setHumen 方法注入进来的 humen。 而在测试类里,Decorator 中的humen 就是 baby ,baby 先执行了 dress()方法,说“ i wil get up”

然后再执行 JacketDecorator 类自己的 addJacket()方法,给 baby 穿 外套

JacketDecorator 的dress() 方法执行完了,才能轮到TrouserDecorator 类执行自己的addTrousers() 方法,给baby 穿裤子。

再论:

如果想换个需求 : 先给Baby 穿内裤,不小心把baby 惊醒了,然后给baby 穿裤子,再穿外套。

这个时候,我们就需要增加一个 给 Humen 穿内裤的装饰类: BriefsDecorator
BriefsDecorator 类继承了 Decorator ,并重写dress() 方法,重写内容是先执行自己的 addBriefs() 方法,然后执行父类的dress()方法。

通过这样的顺序就能保证先执行自己的 addBriefs() 方法,也就满足给baby 穿内裤,不小心 让Baby 惊醒的需求。

public class BriefsDecorator extends Decorator{ public void dress(){ // 先给 Humen 穿内裤,然后执行 父类的dress方法 addBriefs(); super.dress(); } public void addBriefs(){ System.out.println("add Briefs"); } }

这个时候,需要改写测试类,改写后的类如下:

public class TestDecoratorPattern { public static void main(String[] args){ Baby baby =new Baby(); BriefsDecorator bDecorator = new BriefsDecorator(); JacketDecorator jDecorator= new JacketDecorator(); TrouserDecorator tDecorator= new TrouserDecorator(); bDecorator.setHumen(baby); tDecorator.setHumen(bDecorator); jDecorator.setHumen(tDecorator); jDecorator.dress(); } }

解释 : 因为穿内裤动作在前,所以 bDecorator.setHumen(baby); 这样就保证了先执行 穿内裤,再执行baby 惊醒

tDecorator.setHumen(bDecorator); 将bDecorator 注入到 tDecorator ,保证了 接着执行 addTrousers() 方法

jDecorator.setHumen(tDecorator); 将 tDecorator 注入到jDecorator ,保证了 最后执行 addJacket() 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值