从零开始学设计模式(八):装饰器模式(Decorator Pattern)

简介: 在编程语言中一般有两种方式给一个类或者对象增加额外的行为或者功能:

定义


在编程语言中一般有两种方式给一个类或者对象增加额外的行为或者功能:


一种是继承:一个子类继承一个父类可以使得子类在拥有自身方法之外还能够同时拥有父类的方法。


还有一种是关联:即将一个类的对象嵌入到另一个对象中,并且由另一个对象决定是否调用嵌入对象的行为来扩展自己的功能,可见这种方式是动态的比继承更加灵活。而嵌入的对象就是这里要说的装饰器。


装饰器模式是继承关系的一个替代方案,在不必改变原类文件和原类使用的继承的情况  下,通过使用对象之间的关联关系来取代类之间的继承关系,从而能够动态的给一个对   象拓展一些额外的功能。它也是一种对象结构型模式。


组成部分


装饰器模式具有以下四个成员角色:


抽象构件角色(Project):给出一个接口,以规范准备接收附加责任的对象。


具体构件角色(Employe):定义一个将要接收附加责任的类。


装饰角色(Manager):持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口。


具体装饰角色(ManagerA、ManagerB):负责给构件对象贴上附加的责任。


例子


这里以手机的功能为例:


声明一个抽象构件角色手机的公共接口,并且具有拍照的功能:


public interface Phone {
    //手机具有拍照的功能
    void photo();
}
复制代码


再声明一个具体构件角色,


public class OldPhone implements Phone{
    @Override
    public void photo() {
        System.out.println("手机的拍照功能");
    }
}
复制代码


抽象装饰角色:


public class NewPhone implements  Phone{
    public OldPhone oldPhone;
    public NewPhone(OldPhone oldPhone) {
        this.oldPhone = oldPhone;
    }
    @Override
    public void photo() {
        System.out.println("手机的拍照功能");
    }
}
复制代码


具体装饰角色:


public class ConcreteDecorator extends NewPhone {
    public ConcreteDecorator(OldPhone oldPhone) {
        super(oldPhone);
    }
    public void photo() {
        super.photo();
        video();
    }
    public void video() {
        System.out.println("为手机增加额外的拍视频的功能");
    }
}
复制代码


测试:


public class Test {
    public static void main(String[] args) {
        Phone p = new OldPhone();
        p.photo();
        Phone phone = new ConcreteDecorator(new OldPhone());
        phone.photo();
    }
}
复制代码


结果:

27dbfb1b517842f884d0576c41ae39a3~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


通过例子可以看到,没有改变原来的OldPhone类,同时也没有定义他的子类而实现了Phone的扩展新增了拍视频的功能,这就是装饰器模式的作用。


装饰器模式优点:


1、装饰器模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。


2、可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。


3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。


4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”


装饰器模式缺点


1、使用装饰器模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类,增加了系统的复杂性


2、装饰器模式比继承更加灵活机动的特性,但同时也装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。


装饰器模式和继承的区别:


前面说了装饰器模式和继承机制都可以给一个类或者对象增加额外的行为或者功能,那么它们有什么区别:


继承比较于装饰器模式的优点在于代码结构清晰,而且实现简单;但是对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。


而装饰器模式则可以动态的对对多个需要增强的类进行增强,同理需要维护需要增强的类的实例。进而使得代码稍微复杂。


装饰器模式与适配器模式的区别:


装饰器模式和适配器模式都是类结构设计模式,它们又有什么区别:


1、适配器模式主要用来兼容那些不能在一起工作的类,将它们转化为可以兼容目标接口,虽然也可以实现和装饰器一样的增加新职责,但是它的目的并不是这个。而装饰器模式主要是给被装饰的增加新职责的。


2、适配器模式是用新接口来调用原接口,原接口对新系统是不可见或者说不可用的。而装饰器模式原封不动的使用原接口,系统对装饰的对象也通过原接口来完成使用。


3、适配器模式是知道被适配者的详细情况的;而装饰器模式只知道其接口是什么,至于其具体类型(是基类还是其他派生类)只有在运行期间才知道。


使用场景


1、当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。


2、当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。


3、当对象的功能要求可以动态地添加,也可以再动态地撤销时。


4、装饰器模式在java中的最著名的应用就是I/O 标准库的设计了。比如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。

目录
相关文章
|
1月前
|
设计模式 XML Java
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
29 0
|
2月前
|
设计模式 Java
Java设计模式-装饰器模式(10)
Java设计模式-装饰器模式(10)
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
5月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
5月前
|
设计模式 Java
Java设计模式:深入装饰器模式的三种写法(六)
Java设计模式:深入装饰器模式的三种写法(六)
|
6月前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
5月前
|
设计模式 架构师 安全
设计模式第五讲-装饰器模式和代理模式详解
远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
264 0
|
16天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78