设计模式 结构型 装饰器模式(Decorator Pattern)与 常见技术框架应用 解析

在这里插入图片描述

装饰器模式(Decorator Pattern),又称为包装器模式(Wrapper Pattern),是一种结构型设计模式。它允许在不改变原有对象结构的基础上,动态地给对象添加一些新的职责(即增加其额外功能)。

一、核心思想

装饰器模式的核心思想是通过组合而非继承来实现功能的扩展。它提供了一种比使用子类更加灵活的替代方案,使得对象可以在运行时根据需要动态地添加或移除装饰器,从而实现功能的动态组合。

二、定义与结构

定义:装饰器模式动态地给一个对象添加一些额外的职责。就扩展功能而言,装饰器模式提供了一种比使用子类更加灵活的替代方案。

结构

  1. 抽象组件(Component)角色:定义了一个对象接口,可以给这些对象动态地添加一些职责。
  2. 具体组件(Concrete Component)角色:实现了抽象组件接口,并定义了一个具体的对象,也可以给这个对象添加一些职责。
  3. 装饰器(Decorator)角色:持有一个组件(Component)对象的引用,并定义一个与抽象组件一致的接口。它本身是一个抽象类,通常不会直接实例化。
  4. 具体装饰器(Concrete Decorator)角色:负责给组件添加新的职责。

角色

在装饰器模式中,各个角色之间的关系和职责如下:

  • 抽象构件(Component):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法。它使得客户端能够以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
  • 具体构件(Concrete Component):它是抽象构件类的子类,用于定义具体的构建对象,实现了在抽象构件中声明的方法。装饰类可以给它增加额外的职责。
  • 抽象装饰(Decorator):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护了一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
  • 具体装饰(Concrete Decorator):它是抽象装饰类的子类,负责向构件添加新的职责。它定义了新的方法,并可以增加新的方法用于扩充对象的行为。

三、实现步骤与代码示例

以Java为例,展示装饰器模式的具体实现步骤和代码示例。

步骤

  1. 定义抽象组件接口。
  2. 实现具体组件类。
  3. 定义装饰器抽象类,它实现了抽象组件接口并持有一个抽象组件对象的引用。
  4. 实现具体装饰器类,它继承了装饰器抽象类并添加了新的职责。

代码示例

// 抽象组件接口
public interface Component {
    void operation();
}

// 具体组件类
public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent: Basic operation.");
    }
}

// 装饰器抽象类
public abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

// 具体装饰器A
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehaviorA();
    }

    private void addedBehaviorA() {
        System.out.println("ConcreteDecoratorA: Added behavior A.");
    }
}

// 具体装饰器B
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehaviorB();
    }

    private void addedBehaviorB() {
        System.out.println("ConcreteDecoratorB: Added behavior B.");
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);
        decoratorB.operation();
    }
}

输出

ConcreteComponent: Basic operation.
ConcreteDecoratorA: Added behavior A.
ConcreteDecoratorB: Added behavior B.

在这个例子中,ConcreteComponent 执行了基础操作,之后通过 ConcreteDecoratorAConcreteDecoratorB 为该组件对象动态添加了新的行为。最终的输出显示了基础操作以及两个装饰器的新增行为。

四、常见技术框架应用

虽然装饰器模式在不同的技术框架中可能有不同的实现方式,但其核心思想是一致的。以下是一些在其他技术框架中应用装饰器模式应用:

1、以Java的IO流为例

  • 在Java的java.io包中广泛使用了装饰器模式。
  • 抽象构件是InputStream(字节输入流)和OutputStream(字节输出流)等接口。
  • 具体构件例如FileInputStream(从文件读取字节流)和FileOutputStream(向文件写入字节流)。
  • 抽象装饰类可以是FilterInputStreamFilterOutputStream,它们都实现了对应的InputStreamOutputStream接口,并且包含一个对InputStreamOutputStream的引用。
  • 具体装饰类有很多,比如BufferedInputStream(为输入流添加缓冲功能)和DataInputStream(可以从输入流读取基本数据类型)。以下是简单的代码示例:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("test.txt");
        // 使用装饰器BufferedInputStream为输入流添加缓冲功能
        InputStream bufferedInputStream = new BufferedInputStream(inputStream);
        int data;
        while ((data = bufferedInputStream.read())!= -1) {
            System.out.print((char) data);
        }
        bufferedInputStream.close();
        inputStream.close();
    }
}

2、ES6 装饰器

在ES6(ECMAScript 2015)及之后的版本中,JavaScript引入了装饰器作为实验性特性。装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、访问器、属性或参数上。它们使用@expression这种形式,在编译时执行,并且可以用来修改类的行为。

装饰器本质上是一个函数,它接收目标对象(类构造函数或其原型)、属性名(对于属性和方法),以及描述符(对于方法)。装饰器可以返回一个新的属性描述符来替换旧的描述符,或者返回一个全新的构造函数来替代旧的构造函数。

下面我们将通过几个例子来详细解释如何在JavaScript中使用装饰器模式。

类装饰器

类装饰器应用于类构造函数,通常用于观察、修改或替换类定义。

function sealed(constructor) {
    console.log('Sealed decorator called');
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

@sealed
class Person {
    constructor(name) {
        this.name = name;
    }
}

在这个例子中,当定义Person类时,sealed装饰器会立即执行,并将Person构造函数及其原型都密封起来,防止进一步扩展。

方法装饰器

方法装饰器用于修饰类的方法,可以改变方法的行为。

function enumerable(value) {
    return function (target, propertyKey, descriptor) {
        descriptor.enumerable = value;
        return descriptor;
    };
}

class Example {
    @enumerable(false)
    method() {}
}

这里我们定义了一个enumerable装饰器,它可以控制类方法是否可以在遍历中出现。当我们在Example类中使用这个装饰器时,我们可以设置method方法是否可枚举。

属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  • 成员的名字。
function format(formatString) {
    return function(target, key) {
        let _value = target[key];

        const getter = () => _value;
        const setter = (value) => {
            console.log(`Setting ${key} to ${formatString.replace('{}', value)}`);
            _value = value;
        };

        delete target[key];
        Object.defineProperty(target, key, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
        });
    };
}

class Greeting {
    @format('Hello, {}!')
    name = '';
}

const greeting = new Greeting();
greeting.name = 'Alice';
console.log(greeting.name); // Output: Hello, Alice!

在这个例子中,format装饰器用来格式化name属性的值,当设置name属性时,它会输出一条格式化的消息。

注意事项

不同的框架(如TypeScript、Angular)对装饰器的支持程度也不同。在实际项目中使用装饰器之前,请确认你的开发环境支持这一特性。

五、应用场景

装饰器模式适用于以下场景:

  1. 当不能采用继承的方式扩展系统,或采用继承的方式扩展系统不利于系统维护时。
  2. 当对象的功能要求可以动态增加、撤销时。
  3. 需要灵活扩展对象的功能,而不想增加大量子类时。

具体应用场景包括:

  1. I/O流处理:如Java的I/O库中的BufferedReaderBufferedWriter等类都是对基本的ReaderWriter进行装饰,增加了缓冲功能。
  2. GUI组件定制:如按钮、文本框等组件的定制。
  3. 报表生成:如分页、标题、水印等格式的动态添加。
  4. 权限控制:如为不同的资源或操作添加权限检查。
  5. 日志记录:如为不同的对象或方法添加日志记录功能。

六、优缺点

优点

  1. 灵活性强:装饰器和被装饰类可以独立发展,互不耦合。可以通过组合多个装饰器来灵活地组合对象的行为。
  2. 扩展性好:提供了比继承更加灵活的扩展方式。不需要创建大量的子类,就可以给对象增加新的行为或功能。
  3. 透明性好:用户可以根据需要选择性地添加装饰器,而不需要了解这些装饰器是如何实现的。这使得代码更加清晰和简洁。
  4. 复用性高:装饰器可以被重复使用在多个对象上,提高了代码的复用性。

缺点

  1. 复杂性增加:过多地使用装饰器可能会使代码变得复杂,特别是当装饰器链很长时,理解和维护起来会比较困难。
  2. 性能开销:在装饰器链中,每个方法调用都会经过多层装饰器的包装,这可能会导致性能上的开销。

总之,装饰器模式是一种非常有用的设计模式,它可以提高代码的可扩展性和灵活性。但在设计时需要慎重考虑是否使用该模式,并权衡其优缺点。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947669.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机毕业设计Python+Vue.js游戏推荐系统 Steam游戏推荐系统 Django Flask 游 戏可视化 游戏数据分析 游戏大数据 爬虫

2021年12月21日 姓名 专业 软件工程 班级 20-IBM-企Java2 题目 基于hadoopSpark的游戏推荐与可视化系统的设计与实现 指导教师 王文钧、王春娴 一、与本题目有关的国内外研究情况、题目研究的目的和意义、主要内容、本课题创新之处、拟解决的问题: 国内外…

[创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较

目录 一、波士顿矩阵 1、基本原理 2、各象限产品的定义及战略对策 3、应用 4、优点与局限性 二、技术成熟度模型与产品生命周期模型的配对 1、技术成熟度模型 2、产品生命周期模型 3、技术成熟度模型与产品生命周期模型的配对 三、产品生命周期与产品类型的对应关系 …

使用Python类库pandas操作Excel表格

Date: 2025.01.02 20:33:30 author: lijianzhan 简述:pandas 是处理 Excel 文件的强大工具,它提供了简单易用的接口来读取、操作和写入 Excel 数据。以下是使用 pandas 处理 Excel 文件的详细指南,包括常见操作和示例代码。 安装依赖,pandas …

Deepseek v3 的笔记

基本概述 Deepseek v3是Deepseek发布的旗舰模型,属于607B的混合专家(MoE)模型,其中活跃参数为37B。在当前的模型领域,它堪称最佳的开源模型,性能超越了Llama 3.1 405b、Qwen和Mistral等知名模型。根据基准…

Python多分类Logistic回归详解与实践

在机器学习中,Logistic回归是一种基本但非常有效的分类算法。它不仅可以用于二分类问题,还可以扩展应用于多分类问题。本文将详细介绍如何使用Python实现一个多分类的Logistic回归模型,并给出详细的代码示例。 一、Logistic回归简介 Logist…

前端,npm install安装依赖卡在sill idealTree buildDeps(设置淘宝依赖)

输入npm i后,一直卡在sill idealTree buildDeps,一动不动 cnpm可以安装成功,但使用cnpm不会生成package-lock.json文件 设置淘宝依赖,依然卡住,挂梯子也不行 解决方法: // 取消ssl验证 set strict-ssl …

装饰者模式

1、定义 装饰者模式:在不必改变原类和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象 2、实际应用 星巴克的咖啡系统项目: 星巴克要求的各种下单功能:大杯原味、大…

招银网路Java后端一面,难度有点大!

这是一位武汉理工大学同学的招银网络一面面经,同样附带超详细的参考答案。大家可以用来查漏补缺,针对性地补短板。 招银网络一面还是比较简单的,基本都是一些比较重要且高频的常规八股,项目问的不多。到了二面的时候, 会开始主要考察你的项目。 1、自我介绍 自我介绍一般…

C++之设计模式

设计模式 简介单例模式饿汉模式懒汉模式 工厂模式简单工厂模式工厂方法模式抽象工厂模式 建造者模式代理模式 简介 设计模式是前辈们对代码开发经验的总结,是解决特定问题的⼀系列套路它不是语法规定,而是⼀套⽤来提高代码可复用性、可维护性、可读性、…

云效流水线使用Node构建部署前端web项目

云效流水线实现自动化部署 背景新建流水线配置流水线运行流水线总结 背景 先来看看没有配置云效流水线之前的部署流程: 而且宝塔会经常要求重新登录,麻烦的很 网上博客分享了不少的配置流程,这一篇博客的亮点就是不仅给出了npm命令构建&…

pycharm如何拉取一个git项目,然后,修改后再上传到自建的项目中?

以chattts为例 https://github.com/2noise/ChatTTS.git 1.建一个虚拟环境,用于项目使用 2.pycharm新建工程 3.忽略 提示 勾选,新建远程仓库 设置账号和密码 设置git路径,一般是正确的,点测试即可 &…

(五)开机自启动以及scp工具文件传输小问题

文章目录 程序开机自启动先制作一个可执行程序第一种 通过命令行实现程序开机自启动第二种 通过 Linux 系统镜像实现程序开机自启动 scp工具文件传输小问题 程序开机自启动 原因:做成产品后,用户直接开机使用,总不能在开机执行程序后才可以使…

供需平台信息发布付费查看小程序系统开发方案

供需平台信息发布付费查看小程序系统主要是为了满足个人及企业用户的供需信息发布与匹配需求。 一、目标用户群体 个人用户:寻找兼职工作、二手物品交换、本地服务(如家政、维修)等。 小微企业:推广产品和服务,寻找合…

中建海龙:科技助力福城南产业片区绿色建筑发展

在快速发展的城市化进程中,绿色建筑以其环保、节能、可持续的特点日益受到重视。作为建筑工业化领域的领军企业,中建海龙科技有限公司(简称“中建海龙”)凭借其卓越的科技实力和创新举措,在推动绿色建筑发展方面做出了…

OJ随机链表的复制题目分析

题目内容: 138. 随机链表的复制 - 力扣(LeetCode) 分析: 这道题目,第一眼感觉非常乱,这是正常的,但是我们经过仔细分析示例明白后,其实也并不是那么难。现在让我们一起来分析分析…

动态规划回文串问题系列一>回文子串

题目: 解析: 注意:字串和子数组差不多 状态表示: 状态转移方程: 初始化: 填表顺序: 返回值: 返回dp表里true的个数

万里数据库GreatSQL监控解析

GreatSQL是MySQL的一个分支,专注于提升MGR(MySQL Group Replication)的可靠性及性能。乐维监控平台可以有效地监控GreatSQL,帮助用户及时发现并解决潜在的性能问题。 通过在GreatSQL服务器上安装监控代理,收集数据库性…

君正T41交叉编译ffmpeg、opencv并做h264软解,利用君正SDK做h264硬件编码

目录 1 交叉编译ffmpeg----错误解决过程,不要看 1.1 下载源码 1.2 配置 1.3 编译 安装 1.3.1 报错:libavfilter/libavfilter.so: undefined reference to fminf 1.3.2 报错:error: unknown type name HEVCContext; did you mean HEVCPr…

Sublime Text4 4189 安装激活【 2025年1月3日 亲测可用】

-----------------测试时间2025年1月3日------------------- 下载地址 官方网址:https://www.sublimetext.com 更新日志:https://www.sublimetext.com/download V4189 64位:https://www.sublimetext.com/download_thanks?targetwin-x64 ....…

Zabbix5.0版本(监控Nginx+PHP服务状态信息)

目录 1.监控Nginx服务状态信息 (1)通过Nginx监控模块,监控Nginx的7种状态 (2)开启Nginx状态模块 (3)配置监控项 (4)创建模板 (5)用默认键值…