设计模式之装饰者模式

装饰者模式

定义

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

(引用 Head First 设计模式)

一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。

通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。

(引用 维基百科)

这种类型属于结构型模式,它是作为现有的类的一个包装。创建一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

类图

decorator-uml

  • Component

    被装饰者抽象类。

  • ConcreteComponent

    动态地加上新行为的对象。继承Component。

  • Decorator

    装饰者。每个装饰者都有一个组件。持有被装饰者的引用。且需要继承被装饰者。

    我们复用继承达到类型匹配,而不是复用继承获得了行为。当我们将装饰者与组件组合时,就是在加入新的行为。所得到的新行为,并不是继承自超类,而是由组合对象得来的。继承Beverage抽象类,是为了有正确的类型,而不是继承它的行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。

  • ConcreteDecorator

    具体的装饰者。

实现

decorator-beverage-uml

1. 定义Component抽象类

/**
 * 饮料抽象类
 * 被装饰者抽象类
 */
public abstract class Beverage {
    /**
     * 描述字段
     */
    String description = "Unknown Beverage";
    public String getDescription() {
        return description;
    }

    /**
     * 待每个不同类型的子类实现的方法
     * @return
     */
    public abstract double cost();
}

2. 定义Decorator抽象类

/**
 * 装饰者抽象类
 * 所有的辅料都要继承该类
 * 必须让Condiment Decorator能取代Beverage
 */
public abstract class CondimentDecorator extends Beverage{
    /**
     * 所有子类必须重新实现该方法。因为装饰器需要保持被装饰者的类方法签名完整
     * @return
     */
    public abstract String getDescription();
}

3. 定义Component实现类

/**
 * 被装饰者实现类
 * 浓咖啡
 */
public class Espresso extends Beverage {
    public Espresso() {
        description = "Espresso";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}

4. 定义Decorator实现类

/**
 * 摩卡是一个装饰者,对Beverage进行装饰
 * 该类清楚知道被装饰对象。因为需要持有被装饰对象引用
 * 1.持有被装饰者的引用
 * 2.保证被装饰者的方法签名的实现(getDescription())
 * 3.实现装饰(cost)
 */
public class Mocha extends CondimentDecorator{
    Beverage beverage;
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

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

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

/**
 * 1.持有被装饰者的引用
 * 2.保证被装饰者的方法签名的实现(getDescription())
 * 3.实现装饰(cost)
 */
public class Whip extends CondimentDecorator{
    Beverage beverage;
    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Whip";
    }

    @Override
    public double cost() {
        return .66 + beverage.cost();
    }
}

5. Main方法

public class T {
    public static void main(String[] args) {
        // 创建基础类
        Beverage beverage = new Espresso();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        // 用摩卡装饰
        Mocha mocha = new Mocha(beverage);
        System.out.println(mocha.getDescription() + " $" + mocha.cost());
        // 用Whip装饰Mocha
        Whip whip = new Whip(mocha);
        System.out.println(whip.getDescription() + " $" + whip.cost());
    }
}

Espresso $1.99
Espresso, Mocha $2.19
Espresso, Mocha, Whip $2.8

浅析 Java IO 装饰模式

类图

在这里插入图片描述

引用 https://www.cnblogs.com/LUA123/p/10685693.html

  • 抽象组件InputStream

    这个抽象类为各种子类型流处理器提供统一的接口。

  • 具体组件

    FileInputStream、ObjectInputStream 、ByteArrayInputStream等原始流处理器扮演,他们实现了InputStream的接口,可以被装饰器装饰。

  • 抽象装饰类

    FilterInputStream,也实现了InputStream的接口。

  • 具体装饰者

    DataInputStream 、BufferedInputStream

Java IO流分类

流分类使用分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderWriter
节点流访问文件FileInputStreamFileOutStreamFileReaderFileWriter
节点流访问数值ByteArrayInputStreamByteArrayOutStreamCharArrayReaderCharArrayWriter
节点流访问管道PipedInputStreamPipedOutStreamPipedReaderPipedWriter
节点流访问字符串StringReaderStringWriter
处理流缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
处理流转换流InputStreamReaderOutputStreamWriter
处理流对象流ObjectInputStreamObjectOutputStream
处理流抽象基类(过滤)FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
处理流打印流PrintStreamPrintWriter
处理流推回输入流PushbackInputStreamPushbackReader
处理流特殊流DataInputStreamDataOutputStream

节点流和处理流

节点流是真正处理数据的。处理流是装饰者。

  • 节点流
    • 文件流:FileInputStream,FileOutputStrean,FileReader,FileWriter,底层调用native方法实现文件读取、写入功能。
    • 数组流:ByteArrayInputStream,ByteArrayOutputStream,CharArrayReader,CharArrayWriter,对数组进行处理的节点流。
    • 字符串流:StringReader,StringWriter,其中 StringReader 能从 String 中读取数据并保存到 char 数组。
    • 管道流:PipedInputStream,PipedOutputStream,PipedReader,PipedWrite,对管道进行处理的节点流。
  • 处理流
    • 缓冲流 :BufferedImputStrean,BufferedOutputStream,BufferedReader ,BufferedWriter,需要父类作为参数构造,增加缓冲功能,避免频繁读写硬盘,可以初始化缓冲数据的大小,由于带了缓冲功能,所以就写数据的时候需要使用 flush 方法,另外,BufferedReader 提供一个 readLine( ) 方法可以读取一行,而 FileInputStream 和 FileReader 只能读取一个字节或者一个字符,因此 BufferedReader 也被称为行读取器。
    • 转换流:InputStreamReader,OutputStreamWriter,要 inputStream 或 OutputStream 作为参数,实现从字节流到字符流的转换,我们经常在读取键盘输入(System.in)或网络通信的时候,需要使用这两个类。
    • 数据流:DataInputStream,DataOutputStream,提供将基础数据类型写入到文件中,或者读取出来。

实例

Reader reader = new FileRead();

小结

  1. 装饰者和被装饰对象有相同的超类型。所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。我们复用继承达到类型匹配,而不是复用继承获得了行为

  2. 你可以用一个或多个装饰者包装一个对象。

  3. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。

  4. 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

  5. 局限性

    1. 导致程序中增加许多功能类似的很小的类
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值