设计模式:装饰器模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

news2024/9/25 13:23:03

上一篇《桥接模式》                                                               下一篇《迭代器模式》

简介:

装饰器模式,它是一种结构型模式,它通过将一个对象封装在一个装饰器对象中,使得你可以通过改变装饰器对象来改变原始对象的行为。
装饰器模式通常涉及到四种角色:
1、抽象构件角色,定义了一个接口,规范了准备接收附加责任的对象。
2、具体构件角色,实现了抽象构件角色,并通过装饰角色为其添加一些职责。
3、抽象装饰角色,继承了抽象构件角色,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
4、具体装饰角色,实现了抽象装饰的相关方法,并给具体构件对象添加附加的责任。

装饰器模式可以避免继承带来的类膨胀问题,因为你可以通过组合装饰器对象来扩展对象的行为,而不是通过继承来添加新的功能。此外,装饰器模式还提供了更好的灵活性,因为你可以在运行时动态地组合和替换装饰器对象,从而改变对象的行为。

但是,使用装饰器模式也需要注意一些问题。首先,使用装饰器模式会增加系统中类的数量,这可能会增加复杂度和理解难度。其次,如果使用不当,可能会导致过多嵌套或产生大量小粒度对象,这会使得代码变得难以维护。因此,在使用装饰器模式时需要谨慎考虑设计是否合适。

总之,装饰器模式是一种非常实用的设计模式,它可以在不修改原始对象结构的情况下,动态地给对象添加额外的职责,使得你可以更加灵活地扩展对象的行为。

装饰器模式的使用场景:
1、需要扩展一个类的功能或给一个类添加附加职责,且不能采用生成子类的方法进行扩充。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
2、需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。
3、对象的功能要求可以动态地添加,也可以再动态地撤销。

装饰器模式的创建步骤:
1、创建接口:首先定义一个接口,该接口规范了对象的基本行为。
2、创建实现接口的实体类:创建一个或多个实体类来实现接口,这些实体类将作为被装饰的对象。
3、创建实现Shape接口的抽象装饰类:创建一个抽象装饰类,该类继承了接口并提供了添加额外职责的方法。
4、创建具体装饰类:创建一个或多个具体装饰类,它们继承了抽象装饰类并实现了添加额外职责的方法。
5、使用装饰器模式:通过将对象封装在装饰器对象中,可以在运行时动态地给对象添加额外的职责。

装饰器模式的优点,主要包括:
1、灵活性:装饰器模式可以以动态的方式在运行时给对象增加额外的职责,而不需要在编译时决定添加哪些功能。通过使用装饰器模式,可以在不改变原始对象结构的情况下,根据需要灵活地扩展对象的行为。
2、可插拔:通过使用装饰器模式,可以将功能分解成一系列的装饰器类,使得代码更加模块化和易于维护。可以在运行时动态地组合和替换装饰器对象,从而改变对象的行为。
3、可扩展性:装饰器模式可以避免继承带来的类膨胀问题,因为你可以通过组合装饰器对象来扩展对象的行为,而不是通过继承来添加新的功能。
4、符合开闭原则:装饰器模式完全遵守开闭原则,即对扩展开放,对修改封闭。通过使用装饰器模式,可以方便地添加新的装饰器类来扩展对象的行为,而不需要修改原始对象的代码。

装饰器模式的缺点,主要包括:
1、代码量增加:装饰器模式需要创建很多小类,即使只添加一个功能,也要额外创建一个类,这会使得程序更复杂。
2、增加代码复杂度:使用装饰器模式不但需要实例化组件,还要把组件包装到装饰者中,这会增加代码的复杂度。
3、设计难度高:装饰器模式需要对系统进行全面理解,设计出结构良好的装饰器类和被装饰类,才能够达到预期的效果。
4、性能问题:由于装饰器模式需要在运行时动态地创建对象和调用方法,这可能会导致性能上的问题。

注意:过度使用装饰器模式可能会导致程序变得复杂,增加系统中类的数量,并可能产生大量小粒度对象,使得代码变得难以维护。因此,在使用装饰器模式时需要谨慎考虑设计是否合适。

示例:

一、C#装饰器模式

以下是一个示例,展示了如何在C#中实现装饰器模式:

//定义一个接口
public interface IMyService  
{  
    void DoSomething();  
}
//创建一个实现该接口的具体类
public class MyService : IMyService  
{  
    public void DoSomething()  
    {  
        Console.WriteLine("Doing something in MyService.");  
    }  
}
//创建一个实现IMyService接口的抽象装饰类
public abstract class MyServiceDecorator : IMyService  
{  
    protected IMyService decoratedMyService;  
  
    public MyServiceDecorator(IMyService myService)  
    {  
        decoratedMyService = myService;  
    }  
  
    public virtual void DoSomething()  
    {  
        decoratedMyService.DoSomething();  
    }  
}
//创建具体装饰类,它们继承自抽象装饰类并实现了添加额外职责的方法
public class MyServiceDecoratorA : MyServiceDecorator  
{  
    public MyServiceDecoratorA(IMyService myService) : base(myService) { }  
  
    public override void DoSomething()  
    {  
        base.DoSomething(); // 调用原始方法。  
        Console.WriteLine("Doing something extra in MyServiceDecoratorA."); // 添加新的功能。  
    }  
}
//实例应用
class Program  
{  
    static void Main(string[] args)  
    {
        IMyService myService = new MyService(); // 创建具体对象。  
        IMyService decoratorA = new MyServiceDecoratorA(myService); // 创建具体装饰类对象并将具体对象作为被装饰对象传入构造函数。  
        decoratorA.DoSomething(); // 调用具体装饰类中的方法,扩展具体对象的行为。
    }
}

二、java装饰器模式

装饰器模式通常通过以下方式实现:

//定义一个接口
public interface Component {  
    void operation();  
}
//创建一个实现该接口的具体类
public class ConcreteComponent implements Component {  
    public void operation() {  
        System.out.println("具体对象操作");  
    }  
}
//创建一个实现IMyService接口的抽象装饰类
public abstract class Decorator implements Component {  
    protected Component component;  
  
    public Decorator(Component component) {  
        this.component = component;  
    }  
  
    public void operation() {  
        component.operation(); // 先调用原始对象的方法。  
        decorate(); // 再添加新的功能。  
    }  
  
    public abstract void decorate(); // 抽象方法,用于添加新的功能。  
}
//创建具体装饰类,它们继承自抽象装饰类并实现了添加额外职责的方法
public class ConcreteDecorator extends Decorator {  
    public ConcreteDecorator(Component component) : super(component) { }  
  
    public void decorate() {  
        System.out.println("具体装饰器添加的功能"); // 添加新的功能。  
    }  
}
//实例应用
public class Main {  
    public static void main(String[] args) {  
        Component c = new ConcreteComponent(); // 创建具体对象。  
        Decorator decorator = new ConcreteDecorator(c); // 创建具体装饰类对象并将具体对象作为被装饰对象传入构造函数。  
        decorator.operation(); // 调用具体装饰类中的方法,扩展具体对象的行为。输出:具体对象操作 具体装饰器添加的功能。
    }
}

三、javascript装饰器模式

在JavaScript中,装饰器实现方式如下:

//定义一个接口
const Component = {  
  methods: {  
    operation() {  
      console.log('Component operation');  
    }  
  }  
};
//创建一个实现了该接口的具体类
const ConcreteComponent = {  
  ...Component,  
  constructor() {  
    this.operation();  
  }  
};
//创建一个实现了该接口的抽象装饰器类
const Decorator = {  
  methods: {  
    operation() {  
      this.component.operation();  
      this.decorate();  
    },  
    decorate() {  
      console.log('Decorator decorate');  
    }  
  }  
};
//创建具体装饰类,它们继承自抽象装饰器类并实现了添加额外职责的方法
const ConcreteDecoratorA = {  
  ...Decorator,  
  constructor(component) {  
    this.component = component;  
  },  
  decorate() {  
    console.log('ConcreteDecoratorA decorate');  
  }  
};

在这个示例中,我们创建了一个具体装饰器类ConcreteDecoratorA,它继承自抽象装饰器类并添加了一个新的方法decorate,这个方法会在调用被装饰组件的operation方法后被调用,从而添加新的功能。

四、C++装饰器模式

以下是在C++中实现装饰器模式:

//首先,定义一个接口类:
class IComponent {  
public:  
  virtual void operation() = 0;  
};
//接着,创建一个实现了该接口的具体类:
class ConcreteComponent : public IComponent {  
public:  
  void operation() override {  
    cout << "ConcreteComponent operation" << endl;  
  }  
};
//然后,创建一个实现了该接口的抽象装饰器类:
class IDecorator : public IComponent {  
protected:  
  IComponent* component;  
public:  
  IDeveloper(IComponent* component) : component(component) {}  
  virtual void operation() override {  
    component->operation();  
    decorate();  
  }  
  virtual void decorate() = 0;  
};
//最后,创建具体装饰类,它们继承自抽象装饰器类并实现了添加额外职责的方法:
class ConcreteDecoratorA : public IDecorator {  
public:  
  ConcreteDecoratorA(IComponent* component) : IDecorator(component) {}  
  void decorate() override {  
    cout << "ConcreteDecoratorA decorate" << endl;  
  }  
};

五、python装饰器模式

在Python中,装饰器模式是通过装饰器函数实现的。装饰器函数是一个接受函数作为参数的可调用对象,并返回一个包装后的函数。
下面是一个简单的Python装饰器模式的示例代码:

def my_decorator(func):  
    def wrapper():  
        print("Before the function is called.")  
        func()  
        print("After the function is called.")  
    return wrapper  
  
@my_decorator  
def say_hello():  
    print("Hello!")  
  
say_hello()

六、go装饰器模式

以下是一个示例,展示了如何在go中实现装饰器模式:

package main  
  
import "fmt"  
  
// 原始函数  
func sayHello() {  
    fmt.Println("Hello!")  
}  
  
// 装饰器函数  
func myDecorator(f func()) {  
    fmt.Println("Before the function is called.")  
    f()  
    fmt.Println("After the function is called.")  
}  
  
func main() {  
    // 使用装饰器函数包装原始函数  
    myDecorator(sayHello)  
}

七、PHP装饰器模式

在PHP装饰器模式中,我们创建一个装饰器类,它实现与目标类相同的接口,并在内部维护一个对目标对象的引用。装饰器类可以添加新的方法或覆盖目标类的方法,以实现动态地扩展目标对象的功能。

下面是一个简单的PHP装饰器模式的示例代码:

<?php  
  
// 目标类  
class Target {  
    public function operation() {  
        echo "Target operation";  
    }  
}  
  
// 装饰器类  
class Decorator extends Target {  
    private $target;  
  
    public function __construct(Target $target) {  
        $this->target = $target;  
    }  
  
    public function operation() {  
        echo "Decorator operation before";  
        $this->target->operation();  
        echo "Decorator operation after";  
    }  
}  
  
// 使用装饰器模式  
$target = new Target();  
$decorator = new Decorator($target);  
$decorator->operation();


《完结》

上一篇《桥接模式》                                                                     下一篇《迭代器模式》​​​​​​​

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

layui移除(删除)table表格的一行

表格里添加删除按钮&#xff1a; , {field: wealth, width: 150, title: 操作, align: center, fixed: right,templet: function (item) {return <a style"margin:0px 5px; color:red; cursor: pointer;" lay-event"delete" id"DeleteTr" >…

c++找工作现状是怎样的?

c找工作现状是怎样的&#xff1f; 因为发现最近的就业市场c加加的工作岗位多&#xff0c;Java的工作岗位少了&#xff0c;所以就连某些Java培训机构今 年也纷纷开设了c加加嵌入式开发培训专业。 最近很多小伙伴找我&#xff0c;说想要一些C资料&#xff0c;然后我根据自己从业…

【JAVA核心知识】深度了解MySql的innodb引擎

关键词InnoDB架构图表空间数据页顺序下数据页的存储页分裂页合并高水位排序索引构建img_v2_455d98d3-a67a-47ef-b15a-c1798de6f56g.jpg 索引优化模糊查询打断最左匹配&#xff1f;-索引下推仅能使用一个索引&#xff1f;-索引合并自适应Hash索引 AUTO_INCREMENT计数器新增语句的…

GOPS·2023上海站 | 提前剧透!阿里、腾讯、字节、擎创等专家齐聚上海,共话互联网运维

一、前言 2023年10月26日-27日&#xff0c;第二十一届 GOPS 全球运维大会 2023 上海站即将举行。作为年终前最后一场面向 IT 技术从业者的高端运维盛会。大会上&#xff0c;来自腾讯、阿里、字节跳动、抖音、美团、擎创科技等明星专家&#xff0c;将带来十大互联网行业精彩主…

混淆技术研究笔记(八)扩展yGuard实现签名

前面铺垫了这么多&#xff0c;终于开始实现签名反篡改的功能了。 下载 yGuard 源码&#xff08;https://github.com/yWorks/yGuard&#xff09;&#xff0c;然后先修改一处错误&#xff0c;在 settings.gradle 中定义的项目名是错的&#xff08;和github上的名字不一样&#x…

国密 SM2 SSL 证书 Nginx 安装指南 linux版

一、获取国密证书 1、在您完成申请西部GDCA服务器证书的流程后&#xff0c;下载证书将获取一个证书包&#xff0c;有以下 *.***.com_sign.crt&#xff1a;签名证书 *.***.com_sign.key&#xff1a;签名证书私钥 *.***.com_encrypt.crt&#xff1a;加密证书 *.***.com_encr…

弗洛伊德(Floyd)算法求个顶点之间最短路径问题(详解+图解)

弗洛伊德算法&#xff0c;也称为迪科斯彻算法&#xff0c;是一种用于寻找图形中所有最短路径的算法。它的基本思想是通过一定的规则逐步更新每个节点的最短路径估计值&#xff0c;直到每个节点的最短路径估计值收敛为止。 具体来说&#xff0c;弗洛伊德算法通过求解所有点对之…

澳福外汇还不会超短线交易,可以了解一下混沌理论

很多投资者还不会使用超短线交易盈利&#xff0c;澳福外汇认为投资者还没有了解混沌理论的三大原则&#xff0c; 混沌理论有三个原则&#xff1a; 1、能量永远会遵循阻力最小的途径 2、始终存在着通常不可见的根本结构&#xff0c;这个结构决定阻力最小的途径。 3、 这种始终存…

护眼灯有效果吗?五款好用热门的护眼台灯推荐

可以肯定的是&#xff0c;护眼灯一般可以达到护眼的效果。看书和写字时&#xff0c;光线应适度&#xff0c;不宜过强或过暗&#xff0c;护眼灯光线较柔和&#xff0c;通常并不刺眼&#xff0c;眼球容易适应&#xff0c;可以防止光线过强或过暗导致的用眼疲劳。如果平时生活中需…

新生儿蒙古斑:原因、科普和注意事项

引言&#xff1a; 新生儿蒙古斑是一种常见的皮肤状况&#xff0c;通常在新生儿期间出现。尽管它通常是无害的&#xff0c;但许多父母对它感到担忧&#xff0c;不清楚它的原因和如何处理。本文将科普新生儿蒙古斑的原因&#xff0c;提供相关信息&#xff0c;以及为父母和监护人…

【图解 LeetCode 房屋染色 动态规划思想 + 代码实现】

LeetCode 房屋染色 动态规划 问题描述&#xff1a; 假如有一排房子&#xff0c;共 n 个&#xff0c;每个房子可以被粉刷成 k 种颜色中的一种&#xff0c;你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。 当然&#xff0c;因为市场上不同颜色油漆的价格不同&#x…

视频特效制作软件 After Effects 2024 mac中文版新增功能

After Effects 2024 mac是一款专业的视频特效和动态图形设计软件&#xff0c;它可以帮助用户创建各种令人惊叹的视觉效果&#xff0c;例如粒子系统、合成特效、绿屏抠像等。AE2024软件支持动画制作&#xff0c;包括关键帧动画、形状动画、运动跟踪等工具&#xff0c;可以创建复…

IBM展示非冯·诺依曼架构AI芯片NorthPole

我们正处于人工智能的“寒武纪大爆发”时期。在过去的十年中&#xff0c;人工智能已经从理论和小型测试发展到企业规模的使用案例。但是&#xff0c;用于运行人工智能系统的硬件虽然越来越强大&#xff0c;但在设计时却没有考虑到当今的人工智能。随着人工智能系统规模的扩大&a…

使用C# RDLC环境搭建

搭建C# RDLC环境 在vs环境中&#xff0c;菜单扩展>管理扩展 用来打开报表文件的 用来新建报表文件的 搜索Microsoft Reporting Services Projects 选择第一个进行下载 安装完以上两个即可进行报表文件的创建和预览 reportview组件 推荐nuget安装&#xff1a;Install-…

RabbitMQ 笔记

一、win10安装erlang 1.1 安装erLang语言&#xff0c;配置环境变量 erLang官网地址 1.2 配置环境变量 &#xff08;1&#xff09;添加系统变量ERLANG_HOME &#xff08;2&#xff09;path路径&#xff0c;指向bin目录 1.3 配置完成后再cmd命令窗口erl -version可以查看…

ubuntu安装golang

看版本&#xff1a;https://go.dev/dl/ 下载&#xff1a; wget https://go.dev/dl/go1.21.3.linux-amd64.tar.gz卸载已有的go&#xff0c;可以apt remove go&#xff0c;也可以which go之后删除那个go文件&#xff0c;然后&#xff1a; rm -rf /usr/local/go && tar…

苹果手机怎么设置壁纸?解锁设置壁纸的2种方法!

手机壁纸便是我们常说的屏幕背景图&#xff0c;一张好看的手机壁纸能使我们的心情变得愉悦。这个壁纸可以是风景、美食、喜欢的偶像、自己养的宠物&#xff0c;或者是你的家人、朋友。 拥有特殊含义的照片会更让人想要设置成壁纸。苹果手机怎么设置壁纸&#xff1f;本文将给大…

18.1 Socket 原生套接字抓包

原生套接字抓包的实现原理依赖于Windows系统中提供的ioctlsocket函数&#xff0c;该函数可将指定的网卡设置为混杂模式&#xff0c;网卡混杂模式&#xff08;Promiscuous Mode&#xff09;是常用于计算机网络抓包的一种模式&#xff0c;也称为监听模式。在混杂模式下&#xff0…

从github下载文件时遇到报错(Unable to render code block)解决办法

1、报错情况 2、解决办法 https://ghproxy.com/ &#xff08;GitHub 文件 , Releases , archive , gist , raw.githubusercontent.com 文件代理加速下载服务&#xff09;

提高生产力,开启高效办公——ConceptDraw Office办公软件套件

在当今快节奏的工作环境中&#xff0c;一款强大的办公软件套件对于提高工作效率和生产力至关重要。ConceptDraw Office&#xff0c;作为一款专业的办公软件套件&#xff0c;凭借其强大的功能和易用性&#xff0c;成为了市场上备受瞩目的办公利器。本文将带您深入了解ConceptDra…