Java 设计模式——装饰者模式

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

1.概述

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

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

(2)装饰者模式 (Decorator Pattern) 是一种结构型设计模式,它能在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)。

2.结构

装饰者模式中的角色如下:

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

3.案例实现

我们使用装饰者模式对快餐店案例进行改进,体会装饰者模式的精髓。其类图如下:

Java 设计模式——装饰者模式,Java 设计模式,装饰者模式,设计模式

3.1.抽象组件

FastFood.java

//快餐类
public abstract class FastFood {
    private float price;
    private String desc;
    
    public FastFood() {
    }
    
    public FastFood(float price, String desc) {
        this.price = price;
        this.desc = desc;
    }
    
    public float getPrice() {
        return price;
    }
    
    public void setPrice(float price) {
        this.price = price;
    }
    
    public String getDesc() {
        return desc;
    }
    
    public void setDesc(String desc) {
        this.desc = desc;
    }
    
    public abstract float cost();
}

3.2.具体组件

FriedRice.java

//炒饭
public class FriedRice extends FastFood{
    
    public FriedRice(){
        super(10, "炒饭");
    }
    
    @Override
    public float cost() {
        return getPrice();
    }
}

FriedNoodles.java

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

3.3.抽象装饰

Garnish.java

//装饰者类
public abstract class Garnish extends FastFood{
    //声明快餐类的变量
    private FastFood fastFood;
    
    public FastFood getFastFood() {
        return fastFood;
    }
    
    public void setFastFood(FastFood fastFood) {
        this.fastFood = fastFood;
    }
    
    public Garnish(FastFood fastFood, float price, String desc) {
        super(price, desc);
        this.fastFood = fastFood;
    }
}

3.4.具体装饰

Egg.java

//鸡蛋类
public class Egg extends Garnish{
    
    public Egg(FastFood fastFood){
        super(fastFood, 1, "鸡蛋");
    }
    
    @Override
    public float cost() {
        //计算价格,鸡蛋价格 + 快餐价格
        return getPrice() + getFastFood().cost();
    }
    
    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}

Bacon.java

//培根类
public class Bacon extends Garnish{
    
    public Bacon(FastFood fastFood){
        super(fastFood, 2, "培根");
    }
    
    @Override
    public float cost() {
        //计算价格,培根价格 + 快餐价格
        return getPrice() + getFastFood().cost();
    }
    
    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}

3.5.测试

Client.java

public class Client {
    public static void main(String[] args) {
        //点一份炒饭
        FastFood food = new FriedRice();
    
        System.out.println(food.getDesc() + "  " + food.cost() + " 元");
    
        System.out.println("===============");
    
        //在上面的炒饭中加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + " 元");
    
        System.out.println("================");
        //再加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + " 元");
    
        System.out.println("================");
        food = new Bacon(food);
        System.out.println(food.getDesc() + "  " + food.cost() + " 元");
    }
}

输出结果如下:

炒饭  10.0===============
鸡蛋炒饭  11.0================
鸡蛋鸡蛋炒饭  12.0================
培根鸡蛋鸡蛋炒饭  14.0

在上述例子中使用装饰者模式至少有以下优点:

  • 饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

4.优缺点

(1)装饰者模式的优点和缺点如下所示:

  • 优点
    • 动态扩展:装饰者模式允许在运行时动态给对象添加新的功能,而无需修改其原始类或接口。通过装饰器的层层包装,可以灵活地组合各个功能模块,实现不同组合的功能扩展。
    • 开闭原则:装饰者模式遵循开闭原则,允许向系统中添加新的装饰者,而无需修改现有代码。这使得系统更加灵活,易于扩展和维护。
    • 单一职责原则:装饰者模式通过将功能细分到不同的装饰器中,使得每个装饰器只关注特定的责任或功能。这可以遵循单一职责原则,使类的设计更加清晰和可维护。
  • 缺点
    • 复杂性增加:使用装饰者模式会引入许多小的装饰器类,这可能增加类的数量和复杂性。当装饰者的层级过多时,代码可读性和理解难度会增加,维护也变得复杂。
    • 注重细节:装饰者模式强调在对象之间细粒度的功能组合,这在某些情况下可能会添加不必要的复杂性。对于简单的场景,使用装饰者模式可能会显得过于繁琐。
    • 初始对象需求:装饰者模式要求初始对象实现共同的接口或继承共同的抽象类,以便于装饰器的添加和替换。如果原始对象不符合这些要求,则在引入装饰者时需要进行额外的改造。

(2)总体而言,装饰者模式提供了一种灵活的方式来扩展对象的功能,符合开闭原则和单一职责原则。然而,它也可能引入复杂性并要求对代码进行更多的设计和精心安排。在实际应用中,需要根据具体场景来评估使用装饰者模式的利弊,权衡灵活性和复杂性之间的关系。

5.使用场景

(1)装饰者模式适用于以下场景:

  • 动态添加功能:当需要在运行时动态地为对象添加额外的功能时,可以使用装饰者模式。它提供了一种灵活的方式来组合各个功能模块,而不需要修改原始对象的代码。
  • 避免类爆炸:当类的数量可能会爆炸增长时,可以使用装饰者模式来避免创建大量的子类。通过装饰者模式,可以将各个功能划分到不同的装饰器类中,而不是创建多个子类来实现不同组合的功能。
  • 单一职责原则:当一个类承担了多个责任或功能时,可以使用装饰者模式将每个功能划分到不同的装饰器类中。这样做可以遵循单一职责原则,使类的设计更加清晰和可维护。
  • 可撤销的功能:当需要在运行时可以撤销已添加的功能时,装饰者模式提供了一种方便的方式。只需要移除相应的装饰器即可撤销已添加的功能,而不需要修改原始对象的代码。
  • 继承和复合的替代方案:装饰者模式可以替代继承来扩展对象的功能。相比于继承,装饰者模式更加灵活,允许动态地组合各个功能模块,而不受类的继承关系的限制。

(2)总的来说,装饰者模式适用于需要动态地为对象添加功能或对对象的功能进行扩展的场景。它提供了一种灵活的方式来组合各个功能模块,保持接口的一致性,同时符合开闭原则和单一职责原则。常见的应用场景包括:日志记录、缓存、权限验证、事务管理等。

6.JDK 源码解析——BufferedWriter

(1)I/O 流中的包装类使用到了装饰者模式:BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
(2)现以 BufferedWriter 举例来说明,先看看如何使用 BufferedWriter

import java.io.BufferedWriter;
import java.io.FileWriter;

public class Demo { 
    public static void main(String[] args) throws Exception{
        //创建 BufferedWriter 对象
        //创建 FileWriter 对象
        FileWriter fw = new FileWriter("E:\\a.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        //写数据
        bw.write("hello Buffered");
        bw.close();
    }
}

使用起来感觉确实像是装饰者模式,接下来看它们的结构:
Java 设计模式——装饰者模式,Java 设计模式,装饰者模式,设计模式
小结:BufferedWriter 使用装饰者模式对 Writer 子实现类进行了增强,添加了缓冲区,提高了写数据的效率。

7.装饰者模式和代理模式的比较

(1)装饰者模式和代理模式是两种常见的结构型设计模式,它们有一些相似之处,但也有一些区别。

  • 相似之处:
    • 装饰者模式和代理模式都使用了对象组合的方式来实现功能的扩展。
    • 两者都可以在不修改原始对象的情况下对其进行包装,并在其上添加新的行为或功能。
  • 区别:
    • 装饰者模式强调对对象功能的动态扩展,它在不改变接口的前提下,通过包装和嵌套多个装饰器对象来实现功能的叠加。装饰者模式允许对对象的行为进行链式调用和组合,它的目的是增强对象的功能
    • 代理模式则是在不直接访问原始对象的情况下,通过代理对象对原始对象进行控制和访问。代理模式可以在访问对象时引入额外的控制层,用于控制对原始对象的访问并提供其他的辅助功能,如权限控制、延迟加载、缓存等。代理模式的目的是控制对象的访问

(2)简而言之:

  • 装饰者模式注重功能的动态扩展和组合,它通过装饰器对象将新的功能添加到原始对象上。
  • 代理模式注重对对象的控制和访问,它通过代理对象控制对原始对象的访问,并可以提供额外的辅助功能。

相关知识点:
Java 设计模式——代理模式文章来源地址https://www.toymoban.com/news/detail-598321.html

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

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

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

相关文章

  • 【设计模式——学习笔记】23种设计模式——装饰器模式Decorator(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    在咖啡厅中,有多种不同类型的咖啡,客户在预定了咖啡之后,还可以选择添加不同的调料来调整咖啡的口味,当客户点了咖啡添加了不同的调料,咖啡的价格需要做出相应的改变。 要求 :程序实现具有良好的拓展性、改动方便、维护方便 【方案一】 写一个抽象类Drink,然

    2024年02月15日
    浏览(47)
  • 简化代码结构与提高灵活性:学习Java设计模式中的装饰器模式

    简化代码结构与提高灵活性:学习Java设计模式中的装饰器模式 在软件开发中,我们经常会遇到需要在不修改现有代码的情况下,对已有对象进行功能扩展或修改的需求。此时,装饰器模式就是一种非常有用的设计模式,它通过动态地将责任附加到对象上,来扩展对象的功能

    2024年02月16日
    浏览(47)
  • 【Java面试题】设计模式之七种结构性模式——代理模式、适配器模式、桥接模式、装饰模式、外观模式、享元模式、组合模式

    目录 一、代理模式 二、适配器模式 三、桥接模式 四、装饰模式 五、外观模式 六、享元模式 七、组合模式 概念: 代理模式是为其他对象提供一种以代理控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对

    2023年04月09日
    浏览(52)
  • 设计模式-装饰器模式

    装饰者模式的定义为:动态的给一个对象添加其它功能。 从扩展性来说,这种方式比继承更有弹性,更加灵活,装饰者模式也体现了开闭原则(OCP)。 星巴克咖啡订单项目(咖啡馆) : 1)咖啡种类/单品咖啡: Espresso(意大利浓咖啡)、ShortBlack、Decaf(无因咖啡)、LongBlack(美式咖啡) 2)

    2024年02月06日
    浏览(41)
  • 设计模式——装饰器模式

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。 这种模式创建了一个装饰类,用来包装原有的

    2024年02月10日
    浏览(38)
  • 【设计模式】-装饰器模式

    在软件开发中,经常有需求对已有的对象进行功能的扩展,但是传统的继承方式会导致类的数量快速增多,且难以维护。为了解决这个问题,装饰器模式应运而生。 装饰器模式是一种结构型设计模式,它可以在运行时动态地将新的行为附加到对象上,而不改变其结构。这种方

    2024年02月14日
    浏览(35)
  • 设计模式(3)装饰模式

    一、介绍: 1、应用场景:把所需的功能按正确的顺序串联起来进行控制。动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是

    2024年02月13日
    浏览(39)
  • 设计模式——装饰者模式

    更多内容,前往 IT-BLOG 现实生活中常常需要给某类产品动态增加新的功能,如:给面条各种调味品。在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成一些核心功能。但在不改变其架构的情况下,可以动态地扩展其功能。所以这些都可以采用装饰模式来实

    2024年02月22日
    浏览(33)
  • 设计模式--装饰者模式

    (1) 可乐种类/单品可乐 :BaiShiCola(百事可乐) FeiChangCola(非常可乐) CoCola(可口可乐) (2) 调料/附品: Milk  Chocolate (3) 要求在扩展新的可乐种类时 要具有良好的扩展性 改动方便 维护方便 (4) 使用OO的来就算不同之类可乐的费用 客户可以点单品可乐 也可以单品可乐+调料组合 方案1 

    2024年02月02日
    浏览(40)
  • 【设计模式】装饰器模式

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。 这种模式创建了一个装饰类,用来包装原有的

    2024年02月13日
    浏览(37)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包