装饰者模式-《Head First 设计模式》第三章

来源:互联网 发布:你曾是少年 知乎 编辑:程序博客网 时间:2024/06/06 09:23

源自《Head First 设计模式》,只进行个人总结方便复习,初次学习者不会有任何收获,请看原著!

1-定义:

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

2-设计原则:

类应该对扩展开放,对修改关闭。

装饰者包装一个组件,等于,装饰者具有组件(component)的一个引用。

1、 实现过程中使用了继承,不是说利用装饰而避免继承的吗?

装饰者(Decorator)继承自组件(Component),这里实际意义是“装饰”,原因在于,通过继承只是为了“类型匹配”而不是为了继承获得某些行为。

2、如何获得行为?

在“装饰”的过程中,添加新的行为,而不是继承自超类,这就是组合对象。

3、通常装饰者模式采用抽象类实现,而java中可以用接口实现。

实例:星巴克

星巴克需要出售各种饮料,并且在饮料上加上调料,比如+奶泡+豆浆的浓缩咖啡,比如+摩卡和豆浆的烘焙咖啡。需要实现Beverage饮料类(抽象组件)、Condiment调料类(抽象装饰者)、具体饮料类(继承Beverage)、具体调料类(Condiment)。

Beverage

public abstract class Beverage {    String description = "unKnow description";    public String getDescription() {        return description;    }    public void setDescription(String description) {        this.description = description;    }    public abstract double cost();}

Condiment

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

Espresso\DarkRoast\HouseBlend(浓缩咖啡\烘焙咖啡)

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

其余类推

Whip\Soy\Mocha(奶泡\豆浆\摩卡)

public class Mocha extends Condiment{    Beverage beverage;    public Mocha(Beverage beverage) {        this.beverage = beverage;    }    public String getDescription() {        return beverage.getDescription() + ", Mocha ";    }    public double cost() {        return beverage.cost() + 1;    }}

其余类推

测试

        Beverage beverage = new Espresso();        System.out.println(beverage.getDescription()+beverage.cost());        beverage = new HouseBlend();        beverage = new Soy(beverage);        beverage = new Whip(beverage);        beverage = new Mocha(beverage);        System.out.println(beverage.getDescription()+beverage.cost());        beverage = new DarkRoast();        beverage = new Whip(beverage);        beverage = new Soy(beverage);        System.out.println(beverage.getDescription()+beverage.cost());

实现方法总结:

  1. 定义一个抽象组件Component—为所有类的超类
  2. 定义抽象装饰者Decorator,继承自抽象组件C
  3. 实现各种具体组件,都继承自抽象组件C
  4. 实现各种具体装饰者,都继承自抽象装饰者D
  5. 使用代码:
Component c = new ChildComponent(); //某个具体组件c = new DecoratorOne(c); //进行一层装饰c = new DecoratorTwo(c); //进行第二层装饰c = new DecoratorThree(c); //进行第三层装饰c.doSomeThing(); //用最终装饰好的组件去做一些操作

装饰者应用:JAVA I/O

Java I/O中FileInputStream>BufferedInputStream>LineNumberInputStream就是层层被包装。

  1. FileInputStream(被装饰组件,提供最基本的字节读取功能)
  2. BufferedInputStream(装饰者:增加利用缓冲输入增强性能和用readline()方法来增强接口两种行为)
  3. LineNumberInputStream(装饰者:加上计算行数的能力)就是层层被包装。

java I/O中的组件和装饰者:

  1. 抽象组件:InputStream

  2. 具体组件(被装饰者):FileInputStream、StringBufferInputStream、ByteArrayInputStream

  3. 装饰者(抽象类):FilterInputStream
  4. 具体装饰者:BufferedInputStream、DataInputSream等等

缺点:

设计中包含大量的小类,导致使用该API程序员的困扰。

实现自己的Java I/O

我们制作一个InputStream用于将得到的字符串中的大写字母都转换为小写模式。主要实现方法就是,继承FilterInputStream然后重写read()read(byte b[], int offset, int len)方法。

LowerCaseInputStream

public class LowerCaseInputStream extends FilterInputStream{    protected LowerCaseInputStream(InputStream arg0) {        super(arg0);    }//for byte    public int read() throws IOException{        int c = super.read();        return ((c == -1)? c : Character.toLowerCase((char)c));     }//for byte array    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;    }}

测试程序

需要写好一个txt文件,我放在E盘

    int c;    try {        //nested Decorators        InputStream inputStream =                 new LowerCaseInputStream(                      new BufferedInputStream(                              new FileInputStream("E:\\test.txt")));        while((c = inputStream.read()) >= 0) {            System.out.print((char)c);        }    } catch (IOException e) {        e.printStackTrace();    }

Java中还有很多部分也是使用了装饰者模式,本质就是不断嵌套装饰添加行为的过程,还是比较简单的。但是会导致出现大量的子类。

原创粉丝点击