概述

装饰器模式是结构性模式之一,很多人容易把装饰器模式和适配器模式搞混,本次分享的是装饰器模式,后面会分享适配模式,然后就很清楚的区别他们两各自的特性了。


装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。


特点

动态添加或者覆盖被装饰的接口/抽象类行为。

关系

装饰者和被装饰者有着接口/抽象类层次关系。

自写案例

/**
 * 抽象构建角色
 *
 * @author tianwc
 * @date 2018/11/20
 */
public interface PayService {
/**
     * 支付
     */
    void pay();
}
/**
 * 具体构建角色
 *
 * @author tianwc
 * @date 2018/11/20
 */
public class PayServiceImpl implements PayService {
@Override
    public void pay() {
        System.out.println("执行PayServiceImpl--的--支付--支付方法");
    }
}
/**
 * 装饰角色
 *
 * @author tianwc
 * @date 2018/11/20
 */
public interface PayMsgService extends PayService {
/**
     * 支付
     */
    @Override
    void pay();

    /**
     * 发站内信
     */
    void sendMsg();
}
/**
 * 装饰角色 增加了sendMsg
 *
 * @author tianwc
 * @date 2018/11/20
 */
public class PayMsgServiceImpl implements PayMsgService {

private PayService payService;

    public PayMsgServiceImpl(PayService payService) {
this.payService = payService;
    }

/**
     * 交易
     */
    @Override
    public void pay() {
        System.out.println("开始交易");
        payService.pay();
        sendMsg();
        System.out.println("交易完成");
    }

/**
     * 发送站内信
     */
    @Override
    public void sendMsg() {
        System.out.println("发送站内信");
    }
}
/**
 * 装饰模式demo测试类
 *
 * @author tianwc
 * @date 2018/11/20
 */
public class DecoratorDemo {
public static void main(String[] args) {
        PayService payService = new PayServiceImpl();
        PayService payService2 = new PayMsgServiceImpl(payService);
        payService2.pay();
    }
}

一篇搞定---装饰器模式_装饰模式

原有功能只是支付功能,现在我在这基础之上添加了一个功能发送站内信(用户在自己消息里能看到的交易信息)。以前的代码是完全没有动的。这样就咱们就把装饰模式给用起来了。

大佬们应用

装饰模式在Java I/O的应用

import java.io.DataInputStream;
import java.io.FilterInputStream;
import java.io.InputStream;

/**
 * 装饰器适配模式demo
 *
 * @author tianwc
 * @date 2017/11/18
 */
public class DecoratorDemo {
public static void main(String[] args) {
/**
     * 这个怎么获取的咱们不关心,(被装饰者)
     */
    InputStream inputStream = null;
    /**
     * 装饰者
     * FilterInputStream的构造方法是protected,所以这里就不能new了,
     * DataInputStream是FilterInputStream的子类,并且构造函数是public
     *
     */
//    FilterInputStream fileInputStream=new FilterInputStream(inputStream);
    FilterInputStream fileInputStream = new DataInputStream(inputStream);
  }
}

咱们看看他们的关系

InputStream是顶层抽象类


public abstract class InputStream implements Closeable {


FilterInputStream

一篇搞定---装饰器模式_ide_02

从上面代码可以看得出来FilterInputStream是InpoutStream的子类,并且还有个构造函数其入参是InputStream。

一篇搞定---装饰器模式_System_03

因为FilterInpoutStream中的构造方法是protected修饰的,所以上面的new对象的时候就得借助于其子类DataIputStream。上面可以看出构造方法入参都是父类接口。

装饰模式在dubbo中的应用

一篇搞定---装饰器模式_装饰模式_04

一篇搞定---装饰器模式_装饰模式_05

ProtocolFilterWrapper的构造方法入参为它的Protocol接口类这也是装饰模式的应用之一。

优缺点

优点

  • 与继承关系目的都是要扩展对象的功能,但装饰模式可以提供比继承更多的灵活性,装饰模式允许系统动态的决定贴上一个需要的装饰,或者除掉一个不需要的装饰。继承关系则不同,继承关系是静态的,他在系统运行前就已经决定了。 
  • 通过使用不同的具体修饰类及这些装饰类的排列组合,设计师可以创造出很多不同的行为组合。而继承没有这个关系优势。每一种不同的组合均需要事先通过子类继承的方式设计好。 
  • 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加容易出错 

缺点 

  • 使用装饰模式会产生比使用继承关系更多的类。特别是这些类看上去都比较相近