首页 > 编程语言 >Decorator 装饰者模式简介与 C# 示例【结构型4】【设计模式来了_9】

Decorator 装饰者模式简介与 C# 示例【结构型4】【设计模式来了_9】

时间:2023-10-18 19:24:07浏览次数:49  
标签:示例 C# IShape 模式 public 对象 添加 设计模式 装饰

〇、简介

1、什么是装饰者模式

一句话解释:

  通过继承统一的抽象类来新增操作,再在使用时通过链式添加到对象中,达到与原有设定无关联可灵活附加。

装饰者模式是一种行为设计模式,它允许向一个现有的对象添加新的行为,同时又不改变其结构。

装饰者模式的基本概念是,将一个对象包装在一个含有对对象进行增强功能的对象中,从而达到对对象扩展功能的目的。

官方意图描述:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。别名:包装器(wrapper)。

一个比喻:(班级内部毕业晚会,提供各种零食)

   毕业晚会开始了,有很多种零食,陆续由供应商送来,送来一种相当于实现了一次装饰者抽象类,对于使用者每位同学,可以按照自己的需求选择是否装进自己的肚子。

2、优缺点和适用场景

优点:

  • 动态添加功能:装饰者模式允许在运行时为对象添加新的功能,而不需要修改其代码。这使得代码更加灵活和可维护。
  • 代码复用:装饰者模式可以避免代码重复,因为可以在一个对象上添加多个装饰器,而不需要为每个对象都编写新的代码。
  • 易于扩展:装饰者模式可以很容易地添加新的装饰器,而不需要修改现有的代码。
  • 提高代码可读性:装饰者模式可以使代码更加模块化,使得代码更易于理解和维护。

缺点:

  • 过度使用可能导致代码难以理解和维护:装饰者模式可以使代码变得更加灵活,但如果过度使用,可能会导致代码难以理解和维护。
  • 依赖关系增加:装饰者模式会增加对象之间的依赖关系,这可能会导致系统的复杂性增加。
  • 无法改变对象的类:装饰者模式无法改变对象的类,只能在现有类的基础上添加新的功能。这可能会限制了装饰者模式的使用。
  • 性能问题:如果过度使用装饰者模式,可能会导致系统的性能下降。因为在运行时需要动态创建和销毁对象,这可能会消耗大量的系统资源。

适用场景:

  • 在游戏开发中,装饰者模式可以用于为角色添加新的能力和技能,而不影响原先已有的设定。
  • 在UI设计中,装饰者模式可以用于为界面元素添加新的样式和效果,如边框、背景、阴影、动画等。
  • 在图像处理中,装饰者模式可以用于为图像添加新的滤镜和效果,如锐化、模糊、旋转、裁剪等。
  • 在文本处理中,装饰者模式可以用于为文本添加新的格式和效果,如加粗、斜体、下划线、高亮等。
  • 在购物车应用中,装饰者模式可以用于为商品添加新的属性和功能,如价格、库存、优惠券等。

一、通过示例代码简单实现

下面是一段示例代码,假设需要画一个圆,需要设置宽度和颜色:

// 测试代码
class Program
{
    static void Main(string[] args)
    {
        IShape circle = new Circle(); // 准备画个圆
        IShape borderCircle = new BorderDecorator(circle, 2); // 边框宽度设置为 2
        IShape fillCircle = new FillDecorator(borderCircle, "blue"); // 颜色设置为 blue
        fillCircle.Draw(); // 最后开始画
    }
}
// 定义一个抽象装饰者接口
public interface IShape
{
    void Draw();
}
// 定义一个抽象装饰者类
public abstract class ShapeDecorator : IShape
{
    protected IShape Shape { get; set; }
    public ShapeDecorator(IShape shape)
    {
        Shape = shape;
    }
    public abstract void Draw();
}
// 定义一个具体装饰者类
public class BorderDecorator : ShapeDecorator
{
    private readonly int _borderWidth;
    public BorderDecorator(IShape shape, int borderWidth)
    : base(shape)
    {
        _borderWidth = borderWidth;
    }
    public override void Draw()
    {
        Console.WriteLine($"Drawing a {Shape.GetType().Name} with border width {_borderWidth}");
        Shape.Draw();
    }
}
// 定义另一个具体装饰者类
public class FillDecorator : ShapeDecorator
{
    private readonly string _fillColor;
    public FillDecorator(IShape shape, string fillColor)
    : base(shape)
    {
        _fillColor = fillColor;
    }
    public override void Draw()
    {
        Console.WriteLine($"Drawing a {Shape.GetType().Name} with fill color {_fillColor}");
        Shape.Draw();
    }
}
// 定义一个原始形状类
public class Circle : IShape
{
    public void Draw()
    {
        Console.WriteLine("Drawing a circle");
    }
}

下面如果需要增加一个画法该怎么扩展呢?如下代码,增加一个画法的扩展:

// 再定义另一个具体装饰者类,定义画法
public class MethodDecorator : ShapeDecorator
{
    private readonly string _fillColor;
    public MethodDecorator(IShape shape, string fillColor)
        : base(shape)
    {
        _fillColor = fillColor;
    }
    public override void Draw()
    {
        Console.WriteLine($"Drawing a {Shape.GetType().Name} with method {_fillColor}");
        Shape.Draw();
    }
}
// 测试代码
class Program
{
    static void Main(string[] args)
    {
        IShape circle = new Circle(); // 准备画个圆
        IShape borderCircle = new BorderDecorator(circle, 2); // 边框宽度设置为 2
        IShape fillCircle = new FillDecorator(borderCircle, "blue"); // 颜色设置为 blue
        IShape methodCircle = new MethodDecorator(fillCircle, "clockwise"); // 设计画法顺时针 clockwise
        methodCircle.Draw(); // 最后开始画
    }
}

这就是装饰者模式的基本思想:通过将一个对象包装在一个含有对对象进行增强功能的对象中,从而达到对对象扩展功能的目的。

二、装饰者模式的结构

根据上一章节的示例代码,可得如下结构图:

IShape:定义一个对象接口,可以给这些对象动态地添加职责。

Cricle:定义一个对象,可以给这个对象添加一些职责。

ShapeDecorator:维持一个指向 IShape 对象的指针,并定义一个与 IShape 接口一致的抽象类。

BorderDecorator、FillDecorator:向  Cricle 对象添加职责。

三、相关模式

关于适配器模式 Adapter:Decorator 模式不同于 Adapter 模式,因为装饰仅改变对象的职责而不改变它的接口;而适配器将给对象一个全新的接口。

关于组合模式 Composite:可以将装饰视为一个退化的、仅有一个组件的组合。然而,装饰仅给对象添加一些额外的职责————它的目的不在于对象聚集。

关于策略模式 Strategy:装饰者模式改变的是对象的外表;而 Strategy 模式使得你可以改变对象的内核。这是改变对象的两种途径。

标签:示例,C#,IShape,模式,public,对象,添加,设计模式,装饰
From: https://www.cnblogs.com/hnzhengfy/p/SJMSLL_Decorator.html

相关文章

  • EFCore学习笔记 - 主键
    主键1、自增主键简单,但是不满足分布式,并发性能差long、int等类型主键,默认为自增自增字段的代码中不能为Id赋值,必须保持默认值0,否则运行的时候就会报错因为是数据库生成的值,所以SaveChanges()后会自动把主键的值更新到Id例子:插入帖子后,自动重定向......
  • EF Core学习笔记 - 配置
    约定配置1、主要规则表名采用DbContext中对应的DbSet的属性名数据表列的名字采用实体类属性的名字,列的数据类型采用喝实体类属性类型最兼容的类型,可以自定义设置数据表列的可空性取决于对应实体类属性的可空性名字为Id的属性为主键如果主键为short,int或者lo......
  • Go - Testing a Web Application or a Web Service
    Problem: Youwanttodounittestingonawebapplicationorawebservice.Solution: Usethehttptest.NewRecorderfunctiontocreateanhttptest.ResponseRecorderthatcanbeusedtorecordwhat’sbeenwrittentothehttp.ResponseWriter.Thiscanthenb......
  • PHPGGC的使用介绍和安装
    PHPGGC的使用介绍和安装PHPGGC:PHPGGC是一个unserialize()有效负载库,以及从命令行或编程方式生成它们的工具。当您在没有代码的网站上遇到反序列化时,或者只是在尝试构建漏洞时,此工具允许您生成有效负载,而无需经历查找小工具并组合它们的繁琐步骤。它可以被视为相当于frohoff的y......
  • RoCE协议 RDMA技术
    RoCE的好处低CPU占用率:访问远程交换机或服务器的内存,无需消耗远程服务器上的CPU周期,从而可以充分利用可用带宽和更高的可伸缩性。零复制:向远程缓冲区发送数据和接收数据。高效:由于RoCE改善了延迟和吞吐量,网络性能得到了很大提高。节省成本:借助RoCE,无需购买新设备或更换以太网......
  • Codeforces Round 882 (Div. 2) B. Hamon Odyssey
    给一个长为\(n\)的数组\(a_1,a_2,\cdots,a_n\)。定义\(f(l,r)=\&_{i=l}^{r}a_i\)。你需要对\(a\)进行分段,使得各段的\(f(l,r)\)之和最小。在各段\(f(l,r)\)之和最小的情况下,尽可能分出更多的段。输出满足上述条件下,\(a\)可分的段数。......
  • react + electron 打包记录
    package.json中的更改:增加: "homepage":"./",  "build":{  "productName":"xxxx",  "appId":"com.xxx.win",  "directories":{   "output":"dist&quo......
  • 开发设计模式之单例模式
    一、单例模式这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。注意:......
  • PHPGGC的使用介绍和安装
    PHPGGC的使用介绍和安装PHPGGC:PHPGGC是一个unserialize()有效负载库,以及从命令行或编程方式生成它们的工具。当您在没有代码的网站上遇到反序列化时,或者只是在尝试构建漏洞时,此工具允许您生成有效负载,而无需经历查找小工具并组合它们的繁琐步骤。它可以被视为相当于frohoff的y......
  • 青蛙跳台阶(C语言数学排列组合公式求解法)
    题目:从前有一只青蛙他想跳台阶,有n级台阶,青蛙一次可以跳1级台阶,也可以跳2级台阶;问:该青蛙跳到第n级台阶一共有多少种跳法。当只有跳一级台阶的方法跳时,总共跳n步,共有1次跳法                 当用了一次跳二级台阶的方法跳时,总共跳n-1步,共有n-1次......