装饰者模式--《Head First DesignPattern》
装饰者模式动态地将责任附加到对象杭,若要拓展功能,装设置提供了比继承更有弹性的替代方案。
星巴兹有多种咖啡,它们具有不同的价格。在购买咖啡时,也可以要求在其中加入各种调料,例如豆浆、摩卡、奶泡等等。需要根据所加入的调料收取不同的费用。
这里运用”装饰者模式“,以饮料为主体,然后在运行时以调料来“装饰”饮料,比如说顾客想要摩卡和奶泡深焙咖啡,那么
- 哪一个深焙咖啡(DarkRoast)对象
 - 以摩卡对象装饰它
 - 以奶泡对象装饰它
 - 调用cost()方法,并依赖委托(delegate)将调料的价格加上去。
 




看一下装饰者模式的类图是如何实现的:

- ConcreteComponent是我们要动态地加上新行为的对象
 - 每个Component都可以单独地使用,或者被装饰者包起来用
 - 每个装饰者都包装一个组件,也就是说,装饰者有一个实例变量以保存某个Component的应用。
 - Decorator是装饰者共同实现的接口。
 - ConcreteDecorator有一个实例变量,可以记录所装饰的食物。
 
所以实现的类图就变成:

代码如下:
Beverage,是基类,实现了getDescription(),同时cost是抽象方法。由子类去实现。
 package headfirst.decorator.starbuzz;
 public abstract class Beverage {
     String description = "Unknown Beverage";
     public String getDescription() {
         return description;
     }
     public abstract double cost();
 }
四种咖啡:
HouseBlend,DarkRoast,Espresso,Decaf
 package headfirst.decorator.starbuzz;
 public class HouseBlend extends Beverage {
     public HouseBlend() {
         description = "House Blend Coffee";
     }
     public double cost() {
         return .89;
     }
 }
 public class DarkRoast extends Beverage {
     public DarkRoast() {
         description = "Dark Roast Coffee";
     }
     public double cost() {
         return .99;
     }
 }
 public class Espresso extends Beverage {
     public Espresso() {
         description = "Espresso";
     }
     public double cost() {
         return 1.99;
     }
 }
 public class Decaf extends Beverage {
     public Decaf() {
         description = "Decaf Coffee";
     }
     public double cost() {
         return 1.05;
     }
 }
接下来是调料接口,或者是抽象类。它必须继承我们的Beverage。并且声明了getDescription()方法。
 package headfirst.decorator.starbuzz;
 public abstract class CondimentDecorator extends Beverage {
     public abstract String getDescription();
 }
接下来是四种调料:
 package headfirst.decorator.starbuzz;
 public class Mocha extends CondimentDecorator {
     Beverage beverage;
     //保存了一个Berverage对象
     public Mocha(Beverage beverage) {
         this.beverage = beverage;
     }
     public String getDescription() {
         return beverage.getDescription() + ", Mocha";
     }
     public double cost() {
         //注意这里委托了beverage.cost()
         return .20 + beverage.cost();
     }
 }
 public class Whip extends CondimentDecorator {
     Beverage beverage;
     public Whip(Beverage beverage) {
         this.beverage = beverage;
     }
     public String getDescription() {
         return beverage.getDescription() + ", Whip";
     }
     public double cost() {
         return .10 + beverage.cost();
     }
 }
 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 Milk extends CondimentDecorator {
     Beverage beverage;
     public Milk(Beverage beverage) {
         this.beverage = beverage;
     }
     public String getDescription() {
         return beverage.getDescription() + ", Milk";
     }
     public double cost() {
         return .10 + beverage.cost();
     }
 }
最后是测试代码:
 package headfirst.decorator.starbuzz;
 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());
     }
 }
那如果我们这时产生了新的需求,要求在菜单上加上咖啡的容量的大小,供顾客选择大杯,小杯,中杯,那该怎么办?要注意,大杯的饮料比较贵,同时它加的调料也要比较多,所以调料的价格也不一样。
这时我们应该在Beverage中定义size和getSize()的函数,并且在四种饮料中要根据size的大小,cost()函数要返回不同的价格。
在调料中,我们也需要获取被装饰者的size,然后cost函数加上对应调料的价格。
 package headfirst.decorator.starbuzz;
 public class Soy extends CondimentDecorator {
     Beverage beverage;
     public Soy(Beverage beverage) {
         this.beverage = beverage;
     }
     public String getDescription() {
         return beverage.getDescription() + ", Soy";
     }
     public int getSize(){
         return beverage.getSize();
     }
     public double cost() {
         double cost = beverage.cost();
         if (getSize() == Beverage.TALL){
             cost += .10;
         }else if (getSize() == Beverage.GRANDE){
             cost += .15;
         }else if (getSize() == Beverage.VENTI){
             COST += .20;
         }
         return cost;
     }
 }
最后要说的就是java.io包中,定义了很多类,就是装饰者模式的实现。我们可以看看InputStream的实现。
OutputStream和Reader,Writer的设计大致差不多。
装饰者模式--《Head First DesignPattern》的更多相关文章
- Java设计模式——装饰者模式
		
JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...
 - JAVA设计模式--装饰器模式
		
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
 - 从源码角度理解Java设计模式——装饰者模式
		
一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...
 - 【设计模式】Java设计模式 - 装饰者模式
		
Java设计模式 - 装饰者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自 ...
 - [Head First设计模式]山西面馆中的设计模式——装饰者模式
		
引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里也就依葫芦画瓢,换汤不换药的用装饰者模式来模拟一碗鸡蛋面是怎么出来的吧.吃 ...
 - JAVA 设计模式 装饰者模式
		
用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式. 结构
 - 浅谈设计模式--装饰者模式(Decorator Pattern)
		
挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...
 - javascript设计模式——装饰者模式
		
前面的话 在程序开发中,许多时候都并不希望某个类天生就非常庞大,一次性包含许多职责.那么可以使用装饰者模式.装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象.本文将 ...
 - 设计模式-装饰者模式(Decorator Pattern)
		
本文由@呆代待殆原创,转载请注明出处. 此设计模式遵循的设计原则之一:类应该支持扩展,而拒绝修改(Open-Closed Principle) 装饰者模式简述 装饰者模式通过组合的方式扩展对象的特性, ...
 - C#设计模式--装饰器模式
		
0.C#设计模式-简单工厂模式 1.C#设计模式--工厂方法模式 2.C#设计模式--抽象工厂模式 3.C#设计模式--单例模式 4.C#设计模式--建造者模式 5.C#设计模式--原型模式 6.C# ...
 
随机推荐
- Tkinter教程之Button篇(1)
			
本文转载自:http://blog.csdn.net/jcodeer/article/details/1811298 #Tkinter教程之Button篇(1)#Button功能触发事件'''1.一个 ...
 - 自定义Camera综述(一般步骤、注意事项、遇到的难题<【内存溢出问题】>、像素参考)
			
一般步骤: 1. 检查和访问Camera:创建代码来检查Camera和所申请访问的存在性: 2. 创建一个预览类:继承SurfaceView来创建一个Camera的预览类,并实现SurfaceHold ...
 - [HIve - LanguageManual]   Transform [没懂]
			
Transform/Map-Reduce Syntax SQL Standard Based Authorization Disallows TRANSFORM TRANSFORM Examples ...
 - CSS布局基础
			
(初级)css布局 一.单列布局1.基础知识块级元素 div p ul li dl dt 行级元素 img span input strong同一行显示.无换行2.盒子模型盒子模型 (边框border ...
 - nodejs API笔记
			
一.URL 涉及到的方法 1.parse():解析地址 2.format():生成地址 3.resolve(from,to):组合成地址 举例说明: url.parse('http://baidu.c ...
 - 【移动开发】安卓Lab2(02)
			
Design UI 总共有三个activity 1. MainActitivty: search bar:先用edittext来代替 map:用imageview装图片 2. DetailActiti ...
 - Spark计算工作流
			
下图 中描述了 Spark 的输入.运行转换.输出.在运行转换中通过算子对 RDD进行转换.算子是 RDD 中定义的函数,可以对 RDD 中的数据进行转换和操作. 输入:在 Spark 程序运行中, ...
 - Hibernate之基于主键映射的一对一关联关系
			
1. 基于主键的映射策略:指一端的主键生成器使用foreign策略,表明根据"对方"的主键来生成自己的主键,自己并不能独立生成主键.并用<param> 子元素指定使用当 ...
 - HDU 5768 Lucky7 (中国剩余定理 + 容斥 + 快速乘法)
			
Lucky7 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5768 Description When ?? was born, seven crow ...
 - mysql从一个表中拷贝数据到另一个表中sql语句
			
这一段在找新的工作,今天面试时,要做一套题,其中遇到这么一句话,从一个表中拷贝所有的数据到另一个表中的sql是什么? 原来我很少用到,也没注意过这个问题,面试后我上网查查,回来自己亲手写了写,测试了下 ...