设计模式笔记03-装饰者模式

设计模式笔记03-装饰者模式


1 引言


本章可以称为“给爱用继承的人一个全新的设计眼界”。
我们即将再度探讨典型的继承滥用问题,一旦你熟悉了装饰者模式的技巧,你将能够在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。

2 正文


2.1本章需求背景

1、咖啡店,有四种原材料咖啡:综合、深焙、低咖啡因、浓缩,四种调料:牛奶、摩卡、豆浆、奶泡;
2、原材料和调料可以任意搭配形成新的饮料,且后期可以加入新的原材料和调料。

如果单纯的为每种咖啡(原材料+调料)建立一个类(接口),无疑是最笨拙的方法,且违背了设计原则:封装变化(材料价格),多用组合少用继承。

public class Beverage
{
    //为每种调料设置静态变量
    public void cost()
    {
         float condimentCost = 0.0;
         if(hasMilk)
         {
             condimentCost += milkCost;
         }
         //以此类推其他三种调料的价格
    }
}

再为每种原材料建立一个类,继承Beverage,覆盖cost()方法加上原材料的价格,得到最终饮料的价格。

以上设计的缺点:
1、一旦出现新的调料,将要修改Bererage代码;
2、以某种原材料为基础的饮料并不会包含所有调料,比如新增一个Tea;
3、万一顾客需要双份的调料呢?

在这里引入一条新的设计原则: 类应该对扩展开放,对修改关闭。
我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。如果能实现这样的目标,有什么好处呢?
这样的设计具有弹性可以应对change,可以接受新的功能来应对改变的需求。
在选择需要被扩展的代码部分时要小心。每个地方都采用 开放-关闭 原则,是一种浪费,也没必要,还会最终导致代码变得复杂且难以理解。


2.2 认识装饰者模式


目前所知道的关于装饰者的一切:
1、装饰者和被装饰者对象有相同的超类型;
2、你可以用一个或者多个装饰者包装一个对象;
3、既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象的场合,可以用装饰过的对象代替它
4、装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的;
5、对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

还记得本章的需求背景吗?里面谈到的原材料就是装饰者对象,而调料则是装饰者。
在以上分析的基础上,我们以Beverage为装饰者对象和装饰者的超类,装饰者对象直接继承Beverage类,为所有调料类设计一个超类condimentDecorator(抽象装饰者)继承于Beverage类。

Beverage类定义

public abstract class Beverage {
	String description = "Unknown Beverage";
  
	public String getDescription() {
		return description;
	}
 
	public abstract double cost();
}


CondimentDecorator类定义

public abstract class CondimentDecorator extends Beverage {
	public abstract String getDescription();
}

原材料类定义

public class Espresso extends Beverage {
  
	public Espresso() {
		description = "Espresso";
	}
  
	public double cost() {
		return 1.99;
	}
}


调料类定义

public class Soy extends CondimentDecorator {
	Beverage beverage;

	public Soy(Beverage beverage) {
		this.beverage = beverage;
	}

	public String getDescription() {
		return beverage.getDescription() + ", Soy";
	}

	public double cost() {
		return .15 + beverage.cost();
	}
}


测试代码

public class StarbuzzCoffee {
 
	public static void main(String args[]) {
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription() 
				+ " $" + beverage.cost());
 
		Beverage beverage2 = new DarkRoast();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription() 
				+ " $" + beverage2.cost());
 
		Beverage beverage3 = new HouseBlend();
		beverage3 = new Soy(beverage3);
		beverage3 = new Mocha(beverage3);
		beverage3 = new Whip(beverage3);
		System.out.println(beverage3.getDescription() 
				+ " $" + beverage3.cost());
	}
}



2.3 真实世界的装饰者


java.io包内的类太多了,简直是排山倒海。下面是一个典型的对象集合,用装饰者来将功能结合起来,以读取文件数据:
超类:InputStream
组件:FileInputStream、StringBufferInputStream、ByteArrayInputStream
抽象装饰者:FilterInputStream
具体装饰者:PushBackInputStream、BufferedInputStream、DataInputStream、LineNumberInputStream

但是Java I/O也引出装饰者模式的一个“缺点”:利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,可能会造成所用此API程序员的困扰。
但是,现在你已经了解了装饰者的工作原来,以后当使用别人的大量装饰的API时,就可以很容易地辨别出他们的装饰者类时如何组织的,已方便用包装方式取得想要的行为。


3 本章小结


装饰者模式是JDK中另一个使用较多的设计模式,上一个是观察者模式(在Swing中大量使用),业内好的API设计无一离不开常见的设计模式,通常我们所说要阅读源码,也是为了学习大牛们的设计思路。
与本书《Head First 设计模式》相比,一个理论,一个实践,实践是检验真理的唯一方式,理论结合实际才是一个码农进步的关键思想。

















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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值