【设计模式】HeadFirst设计模式(三):装饰者(Decorator)模式

今天就来写一下装饰者模式,该软考了,也该实习了,感觉心态静不下来,设计模式都是一些简单的小例子,但是看了这么久连简单的了解还没有完全搞定,深感惭愧,还是要安静下来,书中才有颜如玉~ ~ ~不扯了,下边进入正题

一、装饰者模式定义

在不修改原类的基础上,动态地扩展原来的对象的功能,装饰者提供了比继承更有弹性的替代方案:通过创建一个包装对象(装饰对象),来包裹真实的对象

二、装饰者模式的特点

(1) 装饰者和被装饰者有相同的超类型
(2) 可以用一个或者多个装饰者包装一个对象
(3) 因为装饰者和被装饰者有相同超类型,则可以在任何需要原始对象(被包装的对象)的场合,用装饰过的对象代替它
(4) 装饰者可以在所委托被装饰者的行为**之前与/或之后**,加上自己的行为,以达到特定的目的(注意加粗部分)
(5) 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用某装饰者来装饰对象

看到这里可能很迷惑,可以跳过看后边的具体例子然后再回头看这里就会明白了

三、 装饰者模式具体实现——设计咖啡店的订单系统

*1、首先看下咖啡店原本的类设计:*
![原本类设计](http://img.blog.csdn.net/20150504224243296)
Beverage类(抽象类):属性description由子类设置
每个子类实现cost抽象方法,返回各自价格

当然,在购买咖啡的时候,可以要求在其中加入各种调料:豆浆(Soy)、摩卡(Mocha)、奶泡(Whip)等等,咖啡店会根据加入调料收取不同的费用,所以订单系统需要考虑这些调料部分

解决方法(1):所以我们可以这样做,设计出这些类:

摩卡和奶泡深焙咖啡类、摩卡深焙咖啡类、豆浆浓缩咖啡类等等

可以看出来,我们根据调料和咖啡的种类要用排列组合计算到底需要多少类了。这简直就是”类爆炸“,制造了维护的噩梦

解决方法(2):重新设计Beverage(饮料)类如下

重新设计后的Beverage不再是一个抽象类而是一个具体类:

public class Beverage {
    String description;
    boolean milk;
    boolean soy;
    boolean mocha;
    boolean whip;
    double milkCost = 1.0;
    double soyCost = 2.0;
    double mochaCost = 3.0;
    double whipCost = 4.0;
    //获得描述
    public String getDescription(){
        return description;
    }
    //得到调料价格
    public double cost(){
        double condimentCost = 0.0;
        if(isMilk()){
            condimentCost += milkCost;
        }
        if(isMocha()){
            condimentCost += mochaCost;
        }
        if(isSoy()){
            condimentCost += soyCost;
        }
        if(isWhip()){
            condimentCost += whipCost;
        }
        return condimentCost;
    }

    //省略milk、mocha、soy、whip的setter和getter方法
}

然后,实现DarkRoast(深焙咖啡类):

public class DarkRoast extends Beverage {
    public DarkRoast(){
        description = "我是深焙咖啡";
    }
    public double cost(){
        return 1.99+super.cost();
    }
}

然后我们写一个main函数:

public class Main {
    public static void main(String[] args) {
        //我想要一个加奶的深焙咖啡
        T t = new T1();
        t.setMilk(true);
        System.out.println("加奶的深焙咖啡价格:"+t.cost());
    }
}

打印出来结果:加奶的深焙咖啡价格:2.99

如此,我们就可以实现我们想要的了。但是,这里有一个很严重的问题:如果我们需要增加一个配料的话,我们就需要继续修改这个Beverage类了,这违反了”扩展开放,修改关闭的开—闭设计原则“。我们如何改良?

2、利用装饰者模式对系统进行重新构造

(1) 如果顾客想要摩卡和奶泡深焙咖啡,那么我们需要做的是

① 拿一个深焙咖啡对象

② 以摩卡对象装饰它

③ 以奶泡对象装饰它

④ 调用cost方法,并依赖委托将调料的价格加上去

步骤:

等到算钱的时候只需要调用最外层Whip的cost方法就可以办到

(2) 定义装饰者模式

3、使用装饰者模式实现咖啡店的订单系统:

Beverage.java

public abstract class Beverage {
    protected String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

HouseBlend.java

//浓缩咖啡
public class HouseBlend extends Beverage {

    public HouseBlend() {
        description = "House Blend Coffee";
    }

    public double cost() {
        return .89;
    }
}

DarkRoast.java

//深焙咖啡
public class DarkRoast extends Beverage {

    public DarkRoast() {
        description = "DarkRoast";
    }

    public double cost() {
        return .99;
    }
}

Epresso.java

//浓缩咖啡
public class Espresso extends Beverage {

    public Espresso() {
        description = "Espresso";
    }

    public double cost() {
        return 1.99;
    }
}

CondimentDecorator.java

//配料类的超类
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

Mocha.java

//摩卡(配料)
public class Mocha extends CondimentDecorator {
    Beverage beverage;

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

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

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

Soy.java

//豆浆(配料)
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();
    }
}

Whip.java

//奶泡(配料)
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();
    }
}

然后写一个简单的main函数:

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(beverage2);
        beverage3 = new Mocha(beverage2);
        beverage3 = new Whip(beverage2);
        System.out
                .println(beverage3.getDescription() + " $" + beverage3.cost());
    }
时间: 2024-10-22 01:18:50

【设计模式】HeadFirst设计模式(三):装饰者(Decorator)模式的相关文章

Java设计模式菜鸟系列(三)装饰者模式建模与实现

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39759199 装饰者(Decorator)模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具有弹性的替代方案.对于装饰者模式,它其实是一种包装,所以我更愿意称它为一种包装.像咱们以前经常使用的Java里面的IO流就用到了装饰者模式.比如:BufferedReader br = new BufferedReader(new InputStreamReader(new Fi

23种设计模式介绍(三)---- 行为型模式

由于设计模式篇幅比较大,如果在一篇文章讲完所有的设计模式的话不利于阅读.于是我把它分为三篇文章 23种设计模式介绍(一)---- 创建型模式 23种设计模式介绍(二)---- 结构型模式 23种设计模式介绍(三)---- 行为型模式 设计模式都是比较抽象的概念,所以大家一定要确保看懂类图,而后再自己写代码加强记忆. 概述 行为型模式一共有11种: 模板方法模式(Template Method) 策略模式(Strategy) 命令模式(Command) 中介者模式(Mediator) 观察者模式(

Android与设计模式——装饰者(Decorator)模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述装饰(Decorator)模式的: 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的结构 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同.装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展.(上文来源于网络) 装饰模式的类图如下: 在装饰模式中的角色有: ● 抽象构件(Context)角色:给

【Javascript设计模式】第三课 工厂方法模式

在项目开发中经常遇到在网页上显示一些相同的样式但是内容不同的需求,而且这个需求还是动态的,随着需求的变化内容也有可能在不断的变化,对此我们推荐:工厂模式:通过对产品类的抽象使其创建业务主要用于创建多类产品的实例.      比如说有个需求,需要做两个广告,这样我们可以直接定义两个类来实现 var Java = function (content) { //将内容备份到content中,以备日后使用 this.content = content; //创建对象时,通过闭包直接执行,讲内容按照需求的

设计模式之(三)---工厂方法模式

女娲补天的故事大家都听过吧,这个故事是说,女娲在补了天后,下到凡间一看,哇塞,风景太优美了,天空是湛 蓝的,水是清澈的,空气是清新的,太美丽了,然后就待时间长了就有点寂寞了,没有动物,这些看的到 都是静态的东西呀,怎么办? 别忘了是神仙呀,没有办不到的事情,于是女娲就架起了八卦炉(技术术语:建立工厂)开始创建人, 具体过程是这样的:先是泥巴捏,然后放八卦炉里烤,再扔到地上成长,但是意外总是会产生的: 第一次烤泥人,兹兹兹兹~~,感觉应该熟了,往地上一扔,biu~,一个白人诞生了,没烤熟! 第二次

设计模式实例(Lua)笔记之七(Decorator模式)

1.描写叙述 就说说"我"上小学的的糗事吧. 我上小学的时候学习成绩非常的差,班级上 40 多个同学,我基本上都是在排名 45 名以后,依照老师给我的定义就是"不是读书的料",可是我老爸管的非常严格,明知道我不是这块料,还是往赶鸭子上架,每次考试完成我都是战战兢兢的,"竹笋炒肉"是肯定少不了的,能少点就少点吧,肉可是自己的呀. 四年级期末考试考完,学校出来个非常损的招儿(这招儿如今非常流行的),打印出成绩单,要家长签字,然后才干上五年级,我那个恐

Java 实现装饰者(Decorator)模式

在Java中,io包下的很多类就是典型的装饰者模式的体现,如: new BufferedOutputStream(OutputStream out) new BufferedInputStream(InputStream in); new PrintWriter(OutputStream out) new FilterReader(Reader in); 装饰类与被装饰的类 实现相同的接口, 被装饰类,不关心具体是哪个实现类来装饰它, 同样的业务方法,被装饰类调用装饰类的方法,增强装饰类的功能

My.Ioc 代码示例——谈一谈如何实现装饰器 (Decorator) 模式,兼谈如何扩展 My.Ioc

装饰器模式体现了一种“组合优于继承”的思想.当我们要动态为对象增加新功能时,装饰器模式往往是我们的好帮手. 很多后期出现的 Ioc 容器都为装饰器模式提供了支持,比如说 Autofac.在 My.Ioc 中,默认不提供装饰器支持,但我们可以自己进行扩展,以提供此项功能. using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using My.Ioc; u

23种设计模式介绍(二)---- 结构型模式

由于设计模式篇幅比较大,如果在一篇文章讲完所有的设计模式的话不利于阅读.于是我把它分为三篇文章 23种设计模式介绍(一)---- 创建型模式 23种设计模式介绍(二)---- 结构型模式 23种设计模式介绍(三)---- 行为型模式 设计模式都是比较抽象的概念,所以大家一定要确保看懂类图而后再自己写代码加强记忆. 概述 结构型模式共七种: 适配器模式(Adapter) 外观模式(Facade) 桥接模式(Bridge) 装饰器模式(Decorator) 代理模式(Proxy) 享元模式(Flyw

23种设计模式介绍(一)---- 创建型模式

由于设计模式篇幅比较大,如果在一篇文章讲完所有的设计模式的话不利于阅读.于是我把它分为三篇文章 23种设计模式介绍(一)---- 创建型模式 23种设计模式介绍(二)---- 结构型模式 23种设计模式介绍(三)---- 行为型模式 由于设计模式都是比较抽象的概念,所以大家一定要确保看懂类图,而后再自己写代码加强记忆. 简介 设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接