【设计模式-3.5】结构型——装饰器模式

说明:本文介绍结构型设计模式之一的装饰器模式

定义

装饰器模式(Decorator Pattern)也叫作包装器模式(Wrapper Pattern),指再不改变原有对象的基础上,动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活,属于结构型设计模式。(引自《设计模式就该这样学》P201)

化妆例子

以女孩化妆为例,如下:

(可展示接口,Showable)

java 复制代码
/**
 * 能展示的
 */
public interface Showable {

    /**
     * 展示方法
     */
    void show();
}

(女生对象,Girl)

java 复制代码
/**
 * 女生对象
 */
public class Girl implements Showable {

    @Override
    public void show() {
        System.out.print("女孩素颜的面容");
    }
}

(装饰类,Decorator)

java 复制代码
/**
 * 装饰类
 */
public class Decorator implements Showable {

    private Showable showable;

    /**
     * 构造器注入
     */
    public Decorator(Showable showable) {
        this.showable = showable;
    }

    @Override
    public void show() {
        System.out.print("抹上淡淡的粉底【");
        showable.show();
        System.out.print("】");
    }
}

(客户端,Client)

java 复制代码
public class Client {
    public static void main(String[] args) {
        new Decorator(new Girl()).show();
    }
}

装饰器类扩展了原对象的功能,像是一种包装,包装后更丰富了

更进一步

在上述化妆的例子上,更进一步,抽象出一个装饰器类,如下:

(装饰抽象类,Decorator)

java 复制代码
/**
 * 装饰类
 */
public abstract class Decorator implements Showable {

    private Showable showable;

    /**
     * 构造器注入
     */
    public Decorator(Showable showable) {
        this.showable = showable;
    }

    @Override
    public void show() {
        showable.show();
    }
}

(粉底类,继承装饰类,FoundationMakeup)

java 复制代码
/**
 * 粉底类
 */
public class FoundationMakeup extends Decorator {

    /**
     * 构造器注入
     */
    public FoundationMakeup(Showable showable) {
        super(showable);
    }

    @Override
    public void show() {
        System.out.print("抹上淡淡的粉底【");
        super.show();
        System.out.print("】");
    }
}

(口红类,继承装饰类,Lipstick)

java 复制代码
/**
 * 口红类
 */
public class Lipstick extends Decorator {

    /**
     * 构造器注入
     */
    public Lipstick(Showable showable) {
        super(showable);
    }

    @Override
    public void show() {
        System.out.print("抹上一层口红【");
        super.show();
        System.out.print("】");
    }
}

(客户端使用,Client,可以自由组合装饰方式)

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 搭配一
        new Lipstick(new FoundationMakeup(new Girl())).show();

        System.out.println();
        // 搭配二
        new FoundationMakeup(new Lipstick(new Girl())).show();
    }
}

运行如下:

JDK源码体现

装饰器模式,在JDK的IO流设计上有体现,如下:

java 复制代码
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

public class Client {
    public static void main(String[] args) throws FileNotFoundException {
        // 装饰器模式在Java源码的体现
        File file = new File("./src/main/java/structural/decorator/Client.java");
        ZipInputStream zipInputStream = new ZipInputStream(
                new BufferedInputStream(
                        new FileInputStream(file)));

    }
}

扒一下源码,可见ZipInputStreamBufferedInputStreamFileInputStream都继承自抽象类InputStream,类比一下前面的化妆例子,InputStream也就是装饰抽象类。

  • ZipInputStream -> InflaterInputStream -> FilterInputStream -> InputStream

  • BufferedInputStream -> FilterInputStream -> InputStream

  • FileInputStream -> InputStream

与代理模式的区别

关于装饰器模式与代理模式的区别,这里介绍两本书中给的区别:

代理模式和装饰模式在实现时有些类似,但是代理模式主要是给真是主题类增加一些全新的职责,例如权限控制、缓冲处理、智能引用、远程访问等,这些职责与原有职责不属于同一个问题域。而装饰模式是通过装饰类为具体构件类增加一些相关的职责,是对原有职责的扩展,这些职责属于同一问题域。代理模式和装饰模式的目的也不相同,前者是控制对对象的访问,而后者是为对象动态地增加功能。

(引自《设计模式的艺术》刘伟著,第一版P201)


在《设计模式就该这样学》(P214)中,举了一个不错的例子:

简单来讲,假设现在想租房,那么势必会有一些事务发生:房源搜索、联系房东谈价格等。

假设按照代理模式进行思考,那么小明只需要找到一个房产中介,让他去做房源搜索、联系房东谈价格这些事情,小明只需要等待通知然后付中介费就行了。

而如果采用装饰器模式进行思考,因为装饰器模式强调的是自身功能扩展,也就是说,如果要找房子,小明自身就要增加房源搜索能力扩展、联系房东谈价格能力扩展,通过相应的装饰器,提升自身能力,一个人做完所有的事情。

我的理解,装饰器模式与代理模式都能解决问题,没有非装饰器模式能解决的问题,代理模式也是,区别在于解决问题的角度:从内到外,是装饰器模式,从外到内,是代理模式。

总结

本文介绍了结构型设计模式中的装饰器模式,参考《设计模式就该这样学》、《秒懂设计模式》、《设计模式的艺术》三本书,其中化妆的例子来自《秒懂设计模式》。

相关推荐
编程、小哥哥13 分钟前
互联网大厂Java求职面试实战:Spring Boot微服务架构及Kafka消息处理示例解析
java·spring boot·微服务·kafka·面试技巧
magic 2451 小时前
return this;返回的是谁
java·开发语言
sg_knight2 小时前
Eureka 高可用集群搭建实战:服务注册与发现的底层原理与避坑指南
java·spring boot·spring·spring cloud·微服务·云原生·eureka
数据潜水员7 小时前
C#基础语法
java·jvm·算法
你这个代码我看不懂8 小时前
Java项目OOM排查
java·开发语言
Zong_09158 小时前
AutoCompose - 携程自动编排【开源】
java·spring boot·开源·自动编排
.生产的驴8 小时前
SpringCloud 分布式锁Redisson锁的重入性与看门狗机制 高并发 可重入
java·分布式·后端·spring·spring cloud·信息可视化·tomcat
虾球xz9 小时前
CppCon 2014 学习:C++ Memory Model Meets High-Update-Rate Data Structures
java·开发语言·c++·学习
攒了一袋星辰9 小时前
Spring @Autowired自动装配的实现机制
java·后端·spring
YGGP9 小时前
【结构型模式】代理模式
设计模式