`

转:【HeadFirst 设计模式学习笔记】3 装饰模式

 
阅读更多

原文出处:http://www.cnblogs.com/gnuhpc/archive/2012/12/17/2822401.html

 

1.这个模式可以称为“给爱用继承的人一个全新的设计眼界”的模式。牵扯到第五个设计原则:“类应该对扩展开放,而对修改封闭”。但是要注意,遵循这一标准会带来更多层次上的抽象,增加代码的复杂度,所以并不是所有类都要这样设计。

2.文中举了一个为辛巴克咖啡馆写一个计算咖啡价格+调料价格的类,使用了装饰模式——动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。我们就拿这个计算咖啡价格的东西举例子。

3.在原来的设计中,都是继承于Beverage这个超类中,多一项咖啡+调料组合就多一个子类,最后造成类的爆炸。而使用装饰模式,我们希望用装饰器(这里的调料)一层层的包含被装饰的咖啡,最后达到通过调用最外层的装饰者的cost()方法就可以委托其内部计算计算价钱。我们针对这个目标,从代表饮品的Beverage类下手,这是一个基类,代表一个逻辑上的抽象(但不一定要是抽象类,看是否有抽象方法来定),被装饰者和装饰者都使用该基类,在这个基类中定义了装饰者和被装饰者需要的方法,其中抽象方法是装饰者和被装饰者同时都需要的方法,而普通实现的方法则是装饰者覆盖使用的方法

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

我们将调料视为装饰器,这个装饰器超类为了能够将要被装饰的部分包起来,所以要继承自饮品这个超类:

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 HouseBlend extends Beverage { 
    public HouseBlend() { 
        description = "House Blend Coffee"; 
    } 
    public double cost() { 
        return .89; 
    } 
}

 

然后我们构建具体的装饰者,比如代表摩卡的Mocha类:

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(); 
    } 
}

现在我们测试一下这些代码,喝杯比较多样化的咖啡:

public class StarbuzzCoffee { 
    public static void main(String args[]) { 
        Beverage beverage = new Espresso(); 
        System.out.println(beverage.getDescription() 
                + " $" + beverage.cost()); 
        Beverage beverage3 = new HouseBlend(); 
       beverage3 = new Soy(beverage3);
//一直针对抽象组建类型编程 
        beverage3 = new Mocha(beverage3); 
        beverage3 = new Whip(beverage3); 
        System.out.println(beverage3.getDescription() 
                + " $" + beverage3.cost()); 
    } 
}

4.总结一下装饰模式特点:

  • 装饰者和被装饰对象有相同的基类--都是来自Beverage这个类。
  • 继承关系:基类->被装饰者(就是具体的一些基类延伸),基类->装饰器->装饰者(传入基类)-对应上面的代码。
  • 你可以用一个或多个装饰者包装一个对象--看看beverage3这个对象就知道了。
  • 在任何需要被包装者的场合可以用装饰过的对象代替它--比如首先我们在咖啡上加豆浆,然后我们在加豆浆的咖啡上想再加摩卡的话,我们可以直接在这个加过豆浆的咖啡对象上加摩卡。
  • 装饰者可以在所委托的被装饰者的行为上加上自己的行为,达到特定目的--getDescription和cost方法充分证明了这一点。

5.JDK中的装饰模式

最典型的就是IO系统了,比如BufferedInputStream及LineNumberInputStream都扩展自FilterInputStream——这个类是一个抽象的装饰类。而最高的抽象组件是InputStream类。

我们也可以以假乱真写一个输入流类

public class LowerCaseInputStream extends FilterInputStream {

    public LowerCaseInputStream(InputStream in) { 
        super(in); 
    } 
    public int read() throws IOException { 
        int c = super.read(); 
        return (c == -1 ? c : Character.toLowerCase((char)c)); 
    } 
    public int read(byte[] b, int offset, int len) throws IOException { 
        int result = super.read(b, offset, len); 
        for (int i = offset; i < offset+result; i++) { 
            b[i] = (byte)Character.toLowerCase((char)b[i]); 
        } 
        return result; 
    } 
}

public class InputTest { 
    public static void main(String[] args) throws IOException { 
        int c;

        try { 
            InputStream in = 
                new LowerCaseInputStream( 
                    new BufferedInputStream( 
                        new FileInputStream("test.txt")));

            while((c = in.read()) >= 0) { 
                System.out.print((char)c); 
            }

            in.close(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 
}

6.装饰模式的一些缺陷:

产生各种小类,维护不便。有些代码会依赖特定的类型,而这样的代码一导入装饰者就出问题了。

 

总结:

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

FAQ:

为什么在一定要有Decorator这个类?

基于上边的这个例子我们可以看到Decorator这个类隔离了Component中可能出现的具体实现(比如上例中的getDescription方法),之所以要隔离室因为装饰者对这个方法的实现逻辑和高层的Component类实现的逻辑是不同的。在Decorator将一个方法退化为一个抽象方法,有助于督促具体的装饰器必须实现这个方法,而不会无意使用Component继承而来的方法(如果没有Decorator而直接继承自Component可能会因为实现逻辑不同而出现没有实现新逻辑而误用旧逻辑的情况,这会导致出现运行中错误,而退化为抽象方法后,具体装饰器则不得不实现这个方法,否则不可能编译通过,这就将错误压制在了编译阶段,显然,这相对于运行中出错是要好得多)。

分享到:
评论

相关推荐

    HeadFirst 设计模式学习笔记3--装饰模式 Demo

    在“HeadFirst 设计模式学习笔记3--装饰模式 Demo”中,作者通过实例讲解了装饰模式的基本概念、结构和应用场景。这篇文章可能是从CSDN博客平台上的一个链接访问的,遗憾的是,由于我们当前无法直接访问该链接,所以...

    HeadFirst设计模式学习笔记

    《HeadFirst设计模式学习笔记》是一份详尽的资料,旨在帮助读者深入理解并掌握设计模式这一编程领域的核心概念。设计模式是软件工程中的一种最佳实践,它在解决常见问题时提供了一种标准的解决方案,使得代码更易于...

    HeadFirst 设计模式学习笔记1--策略模式Demo

    《HeadFirst设计模式学习笔记1--策略模式Demo》 在软件工程中,设计模式是一种解决常见问题的标准方案,它提供了一种在特定情况下组织代码的模板。策略模式是设计模式中的一种行为模式,它允许在运行时选择算法或...

    HeadFirst 设计模式学习笔记2--观察者模式 demo

    总的来说,HeadFirst设计模式的学习笔记2关于观察者模式的演示,旨在帮助开发者理解如何使用观察者模式来构建可扩展的系统。通过实际的代码示例,我们可以更深入地掌握这一模式,并将其应用到日常开发中,提升代码的...

    读书笔记:设计模式学习笔记和代码。《图解设计模式》《Head First 设计模式》.zip

    读书笔记:设计模式学习笔记和代码。《图解设计模式》《Head First 设计模式》

    Head.First 设计模式学习笔记.pdf

    ### Head.First 设计模式学习笔记知识点总结 #### 一、设计模式概述 设计模式是一种用于解决软件设计中常见问题的标准化方法。通过采用设计模式,开发者可以提高代码的复用性、灵活性和可维护性。《Head First 设计...

    Head First 设计模式学习笔记(十四)模式的组合使用

    在《Head First 设计模式学习笔记(十四)模式的组合使用》中,作者探讨了如何在实际编程中灵活地组合多种设计模式以解决复杂问题。这篇文章可能是基于《Head First 设计模式》这本书的一个章节,该书是设计模式领域...

    Head First 设计模式 扫描版

    《Head First 设计模式》是软件开发领域内一本广受欢迎的书籍,由Eric Freeman、Elisabeth Robson、Bert Bates和Kathy Sierra四位作者共同撰写。这本书以其独特的视觉风格和易于理解的教学方法,深入浅出地介绍了...

    Head First设计模式读书笔记-DesignPatterns.zip

    《Head First设计模式》是一本深受开发者喜爱的设计模式学习书籍,它以易懂且生动的方式介绍了23种经典设计模式。这些模式是软件工程中经过实践验证的最佳实践,旨在提高代码的可重用性、可读性和可维护性。下面,...

    HeadFirst设计模式笔记

    《HeadFirst设计模式笔记》是深入理解软件设计思想的一份宝贵资料,主要涵盖了设计模式的基础理论和实际应用。设计模式是软件开发中的经验总结,它为解决常见的编程问题提供了标准的解决方案,使得代码更具可读性、...

    基于Java语言的《Head First 设计模式》学习笔记及实战练习源码

    本项目为《Head First 设计模式》的Java语言学习笔记与实战练习源码集合,包含104个文件,主要包括88个Java源文件、12个Markdown文档、3个XML配置文件及少量其他辅助文件。内容涵盖设计模式的学习笔记以及相应的代码...

    Head First Design Pattern 学习笔记

    著名的《Head First Design Pattern》学习笔记,摘要这本书中的设计思路。由于书本过长,整理出笔记帮助回想起设计模式。文件是docx格式,只能由OFFICE Word 2007之后的版本打开,内附Visio类图文件。本文由个人整理...

    head first 设计模式

    通过以上对“Head First设计模式”书中可能涉及的设计模式的介绍,我们可以看出这本书是学习面向对象设计模式的绝佳资源。无论是初学者还是有一定经验的开发人员,都能从中受益匪浅。理解并熟练运用这些模式能够帮助...

    Head First Servlets & JSP 学习笔记

    以上只是《Head First Servlets & JSP》一书中的部分核心知识点,实际内容还包括过滤器、监听器、MVC设计模式、JSTL等更广泛的主题,旨在帮助读者全面理解和掌握Servlet和JSP技术。通过深入学习,开发者能够构建高效...

    head first C#学习笔记:如何创建事件

    本学习笔记将深入探讨如何在C#中创建事件,以实现一个棒球模拟系统的例子。在这个系统中,我们将关注投球手、观众和裁判的交互,当输入棒球的轨迹和距离时,这些对象会根据模拟结果做出相应的反应。 首先,理解事件...

    head_first_servlet&jsp学习笔记

    【Servlet&JSP基础知识】 ...以上是`head_first_servlet&jsp`学习笔记的主要知识点,涵盖了Servlet和JSP的基础、Web应用架构、MVC模式、会话管理和JSP编程等多个方面,为深入理解和实践Servlet与JSP开发奠定了基础。

    设计模式笔记及其源代码(java版)

    设计模式Head First学习笔记,以及使用java编写的设计模式源码,Java原生sdk实现23种设计模式

    head first策略者模式

    《Head First 策略者模式》学习笔记 策略者模式是一种行为设计模式,它使你能在运行时改变对象的行为。在软件开发中,我们常常遇到需要根据不同的情况执行不同算法的问题。策略者模式就是为了解决这类问题而生,它...

Global site tag (gtag.js) - Google Analytics