第八章结构型模式—装饰者模式

这篇具有很好参考价值的文章主要介绍了第八章结构型模式—装饰者模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


结构型模式描述如何将类或对象按某种布局组成更大的结构,有以下两种:
  • 类结构型模式:采用继承机制来组织接口和类。
  • 对象结构型模式:釆用组合或聚合来组合对象。

由于组合关系或聚合关系比继承关系耦合度低,满足 “合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下 7 种:

  • 代理模式
  • 适配器模式
  • 装饰者模式
  • 桥接模式
  • 外观模式
  • 组合模式
  • 享元模式

装饰者模式

解决的问题

第八章结构型模式—装饰者模式

  • 假如我们有一个初代的机器人,他具有对话,唱歌,放音乐的功能,如果我们想要一个新的功能,拖地和跳舞
  • 第一种方式就是我们用第二代机器人,第二代机器人利用继承了第一代机器的基础上进行扩展,如果我们想要新的功能,就需要第三代机器人(因为要满足开放闭合的原则)
    • 由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
    • 我们要引入一个有功能为飞行的机器人就需要重新定义一个类,如果有一天又想要一个游泳的功能,又得重新定义一个类,哪天不想要飞行功能了,又得重新定义一个类来只实现游泳
  • 第二种模式就用我们的装饰器模式,我们类似在初代机器人上套一个盒子,然后在盒子上进行功能的扩展 这样就可以扩展一个类的功能。 动态增加功能,动态撤销。
    • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

概念

**装饰者模式:**在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

结构

装饰者(Decorator)模式中的角色:

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

案例

第八章结构型模式—装饰者模式

先来看一个快餐店的例子:快餐店有炒面、炒饭等快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。下面是使用继承方式的类图:

使用继承的方式存在的问题:

  • 扩展性不好:如果要再加一种配料(火腿肠),我们就会发现需要给 FriedRice 和 FriedNoodles 分别定义一个子类。如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子类。
  • 产生过多的子类

使用装配者进行改进

采用使用装饰者模式对快餐店案例进行改进,类图如下:

第八章结构型模式—装饰者模式

抽象构件角色—快餐类

@Data
public abstract class FastFood {
    private float price;//价格
    private String desc;//描述

    public FastFood(float price, String desc) {
        this.price = price;
        this.desc = desc;
    }
    public abstract float cost();
}

具体构建角色—炒饭 炒面

public class FireRice extends FastFood{

    public FireRice() {
        super(10,"炒饭");
    }

    @Override
    public float cost() {
        return getPrice();
    }
}
public class FireNoodles extends FastFood{
    public FireNoodles() {
        super(12, "炒面");
    }

    @Override
    public float cost() {
        return getPrice();
    }
}

抽象装饰者角色:配料类

public abstract class Garnish extends FastFood{
    //声明快餐类的变量
    private FastFood fastFood;

    public Garnish(FastFood fastFood,float price,String desc){
        super(price,desc);
        this.fastFood=fastFood;
    }

}
  • 为什么我们的配料类要求继承我们的FastFood? 有什么意义呢?等后面的测试时的分析

具体的装饰者角色 鸡蛋和培根

public class Egg extends Garnish {
    public Egg(FastFood fastFood) {
        super(fastFood, 1, "鸡蛋");
    }

    // 计算价格
    public float cost() {
        return getPrice() + getFastFood().cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}
public class Bacon extends Garnish {
    public Bacon(FastFood fastFood) {
        super(fastFood, 2, "培根");
    }

    // 计算价格
    public float cost() {
        return getPrice() + getFastFood().cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}

测试

public class Client {
    public static void main(String[] args) {
        //  点一份炒饭
        FastFood fastFood=new FireNoodles();
        System.out.println(fastFood.getDesc() + "  " + fastFood.cost() + "元");
        //加一个鸡蛋
        fastFood=new Egg(fastFood);
        System.out.println(fastFood.getDesc() + "  " + fastFood.cost() + "元");
        //加一个培根
        fastFood=new Bacon(fastFood);
        System.out.println(fastFood.getDesc() + "  " + fastFood.cost() + "元");
    }
}
//炒面  12.0元
//鸡蛋炒面  13.0元
//培根鸡蛋炒面  15.0元
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
    • 就像一开始举例子的机器人,我们第二代的机器人不是在我们的第一代机器的基础上进行功能扩展,我们类似在初代机器人上套一个盒子,然后在盒子上进行功能的扩展 去掉箱子就取消对应的拓展
  • fastFood=new Egg(fastFood) 我们用的是new Egg,最后还是用fastFood去接收,这也是我们为什么要让配料去继承我们的FastFood,不然在这我们只能用配料类去接收返回的对象,而不是用传进去的fastFood对象
    • 我们本来的意思是给我们的炒面加一个鸡蛋。所以返回的应该还是我们的炒面,如果不实现继承,那么我们加个鸡蛋,最后返回了却是一个配料(鸡蛋),这是不符合我们的意图的

使用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    • 不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。

    • 第二类是因为类定义不能继承(如 final 类)。

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

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

JDK源码分析

JDK源码解析
IO流中的包装类使用到了装饰者模式:BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。

以 BufferedWriter 举例来说明,先看看如何使用 BufferedWriter:

// 创建FileWriter对象
FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt");
// 创建BufferedWriter对象
BufferedWriter bw = new BufferedWriter(fw);
// 写数据
bw.write("hello Buffered");
bw.close();

使用起来感觉确实像是装饰者模式,接下来看它们的结构

第八章结构型模式—装饰者模式

  • InputStreamWriter是抽象构件 FileWriter是具体构件
  • BufferWriter是具体装饰角色

BufferedWriter 使用装饰者模式对 Writer 子实现类进行了增强,添加了缓冲区,提高了写数据的效率。

静态代理和装饰者的区别

相同点:

  • 都要实现与目标类相同的业务接口

  • 在两个类中都要声明目标对象

  • 都可以在不修改目标类的前提下增强目标方法

不同点:

  • 目的不同

    • 装饰者是为了增强目标对象

      • 静态代理是为了保护和隐藏目标对象
  • 装饰者可以迭代增强,代理只能增强一次

    • 比如我们上面的例子,我们的炒饭可以加鸡蛋,然后再加一个培根
    • 而我们的代理,比如我们的日志功能,我们想要给某个类添加日志功能,我们直接进行调用代理对象进行功能增强
  • 获取目标对象构建的地方不同文章来源地址https://www.toymoban.com/news/detail-447036.html

    • 装饰者是由外界传递进来,可以通过构造方法传递
      • 我们的装饰着中的具体构建对象是由外部传入到我们的装配者中
    • 静态代理是在代理类内部创建,以此来隐藏目标对象
      • 我们的静态代理中的真实主题类对象是在我们的静态类内部中创建的。而不是由外部传入的

到了这里,关于第八章结构型模式—装饰者模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【设计模式】第11节:结构型模式之“装饰器模式”

    装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设

    2024年02月06日
    浏览(37)
  • 【地铁上的设计模式】--结构型模式:装饰器模式

    什么是装饰器模式 装饰器模式是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装对象中来为原对象添加新的行为,同时又不改变原有对象的结构。装饰器模式中,包装器对象和被包装对象实现了相同的接口,因此客户端无需知道具体的实现细节,只需通过

    2024年02月02日
    浏览(28)
  • 【C++设计模式之装饰模式:结构型】分析及示例

    装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在运行时动态地给一个对象添加额外的行为。 描述 装饰模式通过创建一个包装器(Wrapper)来包裹原始对象,并在原始对象的行为前后添加额外的功能。通过这种方式,可以实现在不改变原始对象结构的情况下,动态

    2024年02月07日
    浏览(28)
  • (二)结构型模式:5、装饰器模式(Decorator Pattern)(C++实例)

    目录 1、装饰器模式(Decorator Pattern)含义 2、装饰器模式的UML图学习 3、装饰器模式的应用场景 4、装饰器模式的优缺点 5、C++实现装饰器模式的简单实例 1、装饰器模式(Decorator Pattern)含义 装饰模式(Decorator),动态地给一个对象添加一些额外地职责,就增加功能来说,装

    2024年02月12日
    浏览(30)
  • 《golang设计模式》第二部分·结构型模式-04-装饰器模式(Decorator)

    装饰器(Decorator)通过包装(不是继承)的方式向目标对象中动态地添加或删除功能。 Component(抽象组件):定义了原始对象的接口,装饰器也会实现这个接口。 Concrete Component(具体组件):原始对象,以后装饰器会装饰它。 Decorator(抽象装饰器):关联/聚合了抽象组件,

    2024年02月09日
    浏览(35)
  • Java设计模式之结构型-装饰器模式(UML类图+案例分析)

    目录 一、基本概念 二、UML类图 三、角色设计 四、代码实现 案例一 案例二  五、总结  装饰器模式是指不必在改变原有的类和不使用继承的情况下,动态扩展一个对象的功能。 角色 描述 抽象构件 是一个接口或者抽象类,定义我们最核心的对象 具体构件 抽象构件的实现,

    2024年02月11日
    浏览(27)
  • 设计模式-04.01-结构型-代理&桥接&装饰器&适配器

    创建型模式比较好理解,后面的结构型和行为型设计模式不是那么好理解。如果遇到不好理解的设计模式,我一般会在开头举比较简单的Demo案例来帮助理解。 前面几节,我们讲了设计模式中的创建型模式。创建型模式主要解决对象的创建问题,封装复杂的创建过程,解耦对

    2024年02月09日
    浏览(48)
  • 结构型模式 - 代理模式

    由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。 Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态

    2024年02月17日
    浏览(24)
  • 结构型模式-组合模式

    用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 意图: 将对象组合成树形结构以表示\\\"部分-整体\\\"的层次结构。组合模式使得用户对单个对象和

    2024年02月09日
    浏览(32)
  • 16结构型模式-组合模式

    我们很容易将“组合模式”和“组合关系”搞混。 组合模式最初只是用于解决树形结构的场景 ,更多的是处理对象组织结构之间的问题。而组合关系则是通过将不同对象封装起来完成一个统一功能. 1 组合模式介绍 将对象组合成树形结构以表示整个部分的层次结构.组合模式

    2024年02月08日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包