【装饰器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

news2024/11/20 16:34:39

简介

装饰器模式(Decorator Pattern)是一种结构型设计模式。将对象放入到一个特殊封装的对象中,为这个对象绑定新的行为,具备新的能力,同时又不改变其原有结构。

如果你希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为,可以使用装饰模式。或者你用继承来扩展对象行为的方案难以实现或者根本不可行,你可以使用该模式。

作用

  1. 动态地给一个对象添加一些额外的职责,相比生成子类更为灵活。
  2. 在不想增加很多子类的情况下扩展类的能力,实现强大扩展能力。

实现步骤

  1. 创建一个基础工具接口或抽象类,设定基本的方法。
  2. 增加具体工具类实现基础接口,保持工具类的规范性。
  3. 创建一个装饰器抽象类,用于装饰具体工具,聚合基础工具,同时也可以实现基础工具的接口。
  4. 增加多个装饰器类,继承抽象类,根据需要设定装饰能力。

UML

Java代码

基础形状接口

// Shape.java 基础形状接口
public interface Shape {
   void draw();
}

具体形状实现

// Circle.java 具体形状实现了基础形状接口
public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Circle::draw()");
   }
}
// Square.java 具体形状实现了基础形状接口
public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Square::draw()");
   }
}

抽象装饰器

// ShapeDecorator.java 抽象装饰类,是否实现Shape可选
public abstract class ShapeDecorator implements Shape {
// public abstract class ShapeDecorator {
   protected Shape decoratedShape;

   public ShapeDecorator(Shape decoratedShape) {
      this.decoratedShape = decoratedShape;
   }

   public void draw() {
      decoratedShape.draw();
   }
}

具体装饰器

// RedShapeDecorator.java 具体装饰器1
public class RedShapeDecorator extends ShapeDecorator {

  public RedShapeDecorator(Shape decoratedShape) {
    super(decoratedShape);
  }

  @Override
  public void draw() {
    decoratedShape.draw();
    setRedColor(decoratedShape);
  }

  private void setRedColor(Shape decoratedShape) {
    System.out.println(
      "RedShapeDecorator::setRedColor() " + decoratedShape.getClass().getName()
    );
  }
}
// ShadowShapeDecorator.java 具体装饰器2
public class ShadowShapeDecorator extends ShapeDecorator {

  public ShadowShapeDecorator(Shape decoratedShape) {
    super(decoratedShape);
  }

  @Override
  public void draw() {
    // decoratedShape.draw();
    setShadow(decoratedShape);
  }

  private void setShadow(Shape decoratedShape) {
    System.out.println(
      "ShadowShapeDecorator::setShadow() " + decoratedShape.getClass().getName()
    );
  }
}

测试调用

    /**
     * 装饰器模式是将一个对象放到一个装饰器对象中,执行装饰器类里的方法时,对象的行为能力得到增强。
     * 先声明具体对象,然后放到装饰器,得到一个带有装饰器的新对象,该对象具备了新的能力。
     */

    // 声明形状
    Shape circle = new Circle();
    Shape square = new Square();

    // 增加红色装饰
    ShapeDecorator redCircle = new RedShapeDecorator(circle);
    ShapeDecorator redSquare = new RedShapeDecorator(square);
    circle.draw();
    redCircle.draw();
    redSquare.draw();

    // 增加影子装饰
    ShadowShapeDecorator shadowCircle = new ShadowShapeDecorator(circle);
    ShadowShapeDecorator shadowSquare = new ShadowShapeDecorator(square);
    shadowCircle.draw();
    shadowSquare.draw();

Go代码

基础形状接口

// Shape.go 基础形状接口
type Shape interface {
  Draw()
  GetName() string
}

具体形状实现

// Circle.go 具体形状实现了基础形状接口
type Circle struct {
}

func (c *Circle) Draw() {
  fmt.Println("Circle::Draw()")
}

func (c *Circle) GetName() string {
  return "Circle"
}

// Square.go 具体形状实现了基础形状接口
type Square struct {
}

func (c *Square) Draw() {
  fmt.Println("Square::Draw()")
}

func (c *Square) GetName() string {
  return "Square"
}

抽象装饰器

// ShapeDecorator.go 抽象装饰类,是否实现Shape可选
type ShapeDecorator interface {
  Draw()
}

具体装饰器

// RedShapeDecorator.go 具体装饰器1
type RedShapeDecorator struct {
  DecoratedShape Shape
}

func (r *RedShapeDecorator) Draw() {
  r.DecoratedShape.Draw()
  r.SetRedColor(r.DecoratedShape)
}

func (r *RedShapeDecorator) SetRedColor(decoratedShape Shape) {
  fmt.Println("RedShapeDecorator::setRedColor() " + decoratedShape.GetName())
}
// ShadowShapeDecorator.go 具体装饰器2
type ShadowShapeDecorator struct {
  DecoratedShape Shape
}

func (s *ShadowShapeDecorator) Draw() {
  // 装饰器根据需要是否调用形状的Draw方法
  // s.DecoratedShape.Draw()
  s.SetShadow(s.DecoratedShape)
}

func (s *ShadowShapeDecorator) SetShadow(decoratedShape Shape) {
  fmt.Println("ShadowShapeDecorator::SetShadow() " + decoratedShape.GetName())
}

测试调用

  /**
   * 装饰器模式是将一个对象放到一个装饰器对象中,执行装饰器类里的方法时,对象的行为能力得到增强。
   * 先声明具体对象,然后放到装饰器,得到一个带有装饰器的新对象,该对象具备了新的能力。
   */

  // 声明形状
  var circle = new(src.Circle)
  var square = new(src.Square)

  // 增加红色装饰
  var redCircle = &src.RedShapeDecorator{
    DecoratedShape: circle,
  }
  var redSquare = &src.RedShapeDecorator{
    DecoratedShape: square,
  }
  circle.Draw()
  redCircle.Draw()
  redSquare.Draw()

  // 增加影子装饰
  var shadowCircle = &src.ShadowShapeDecorator{
    DecoratedShape: circle,
  }
  var shadowSquare = &src.ShadowShapeDecorator{
    DecoratedShape: square,
  }
  shadowCircle.Draw()
  shadowSquare.Draw()

更多语言版本

不同语言实现设计模式:GitHub - microwind/design-pattern: Design Pattern 经典设计模式源码 C/Java/Go/JavaScript/Python等不同语言实现。 FP/OOP/MVC/MVP/MVVM/DDD等设计思想研究

 

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

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

相关文章

《水经注地图服务》发布的卫星影像数据在OpenLayers中调用

OpenLayers是一个用于开发WebGIS客户端的JavaScript包。 OpenLayers 支持的地图来源包括Google Maps、Yahoo、 Map、微软Virtual Earth 等,用户还可以用简单的图片地图作为背景图,与其他的图层在OpenLayers 中进行叠加,在这一方面OpenLayers…

Linux6.15 Docker 私有仓库(harbor)

文章目录 计算机系统5G云计算第四章 LINUX Docker 私有仓库(harbor)一、搭建本地私有仓库二、Docker--harbor私有仓库部署与管理1.Harbor 简介1)什么是Harbor2)Harbor的特性3)Harbor的构成 2.Harbor 部署1)…

〔扩〕C# 调用Python

C# 调用Python 一、安装类库 pythonnet 谨慎使用IronPython,好像默认是2.7,运行部分外部引入的第三方包会报错 二、创建pyd 文件供c#调用 2.1 安装cython pip install cython2.2 准备自己的python文件 HtmlToMD.py import sys import html2text as ht…

电脑微信空间占用简便清理

1、打开电脑版微信、点击左下角的三根横线 2、点击左侧的“设置” 3、弹出层左侧点击“通用设置”->“存储空间管理” 4、点击清理缓存,或者管理 5、点击“管理”后,根据选择的筛选条件,勾线需要清理的,最后点击清理

TextClamp for Vue3.0(Vue3.0的文本展开收起组件)

呦!大家好,好久没有更新博客了,最近实现了一个一直想自己完成的一个东西,就是文本的展开收起组件,以前项目需要用到,自己实现一个又太繁琐,所以那个时候都是用的别人的轮子,现在自己…

两种接入微信小程序智能客服对话的方式

微信小程序 此处提供两种接入微信小程序的方式。 方式一:扫码将机器人绑定至指定小程序,通过小程序内的客服组件开启智能对话功能; 方式二:通过小程序插件接入。 方式一:后台扫码绑定 流程示意 效果展示 使用页面…

RPA界面元素定位与操控技术详解-达观数据

RPA 入门介绍 什么是 RPA?RPA 是机器人流程自动化 Robotic Process Automation 的简写。在《智能RPA实战》中,我们这样定义:通过特定的、可模拟人类在计算机界面上进行操作的技术,按照规则自动执行相应的流程任务,代替…

代码随想录额外题目| 数组03 ●34排序数组查首尾位置 ●922按奇偶排序数组II●35搜索插入位置

#34排序数组查首尾位置 medium&#xff0c;我写的:1 暴力 vector<int> searchRange(vector<int>& nums, int target) {int start-1;int end-1;for(int i0;i<nums.size();i){if(nums[i]target && start-1) starti;if(nums[i]target && sta…

Photoshop-Beta智能版ps安装教程

Photoshop-Beta智能版ps安装教程 获取方式 安装包工具&#xff0c;关注公众号搜索 荷逸云&#xff0c;发送关键词&#xff1a;ps&#xff0c;即可获得 安装教程 0&#xff1a;注意事项 注意&#xff1a;安装此工具需要魔法上网&#xff0c;获取魔法方式&#xff1a; http…

工业以太网的发展历程与应用前景

工业以太网是在工业自动化和物联网领域广泛使用的通信网络&#xff0c;它具有应用广泛、价格低廉、通信速率高、软硬件产品丰富、应用支持技术成熟等优点&#xff0c;目前它已经在工业企业综合自动化系统中的资源管理层、执行制造层得到了广泛应用&#xff0c;并呈现向下延伸直…

数据结构和算法二(基础查找问题)

一、列表查找&#xff1a; index()&#xff0c;是线性查找&#xff0c;因为二分查找需要进行排序 1、顺序查找 def linear_search(data_set,value):for ind,val in enumerate(data_set):if valvalue:return indelse:return时间复杂度O(n)&#xff0c;从头到尾循环一遍 2、二分…

LED像素间距是什么?

像素间距是指LED显示屏上像素&#xff08;LED晶元&#xff09;之间的距离&#xff0c;也称为点间距&#xff0c;它与显示屏的分辨率相关。具体来说&#xff0c;它描述的是从某一像素的中心到相邻像素中心的距离&#xff0c;单位通常为毫米。像素间距的大小反映了两个像素之间的…

Rancher 加入集群

一、设置rancher为中文界面 1、点击右上角图标--》preferences 2、切换语言&#xff1a;默认为英文&#xff0c;切换成简体中文即可 3、切换成中文后的界面 二、导入K3S集群 1、点击导入已有集群 2、选择集群--》通用 3、输入集群的名字--》创建 4、根据下面的提示&#xff0…

PostgreSQL 查询json/jsonb是否存在某个片段

文章目录 前言实现实现思路坑1坑2坑3 恍然大悟 前言 在PostgreSQL中&#xff0c;jsonb有额外的操作符&#xff0c;如 >、<、?、?|、?& 可以用来查询是否包含路径/值&#xff0c;以及顶层键值是否存在。 详细文章&#xff1a;PostgreSQL 操作json/jsonb 那么&am…

python软件包检索办法--[推荐]

一、官方包管理网站 https://pypi.org/ 二、官网地址 官方源地址: https://pypi.org/simple 中文&#xff1a; https://pypi.com.cn/ PyPI中文网 可以参考&#xff0c;偏慢&#xff01; 三、国内源头 # 清华源 pip config set global.index-url https://pypi.tuna.tsinghua.…

【学会动态规划】礼物的最大价值(12)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

redis在linux系统安装

redis在linux系统安装&#xff1a; 1.下载压缩包 .tar.gz 2.文件安装到/opt mv .tar.gz /opt 解压文件 tar -zxvf .tar.gz 3.安装基本c环境//yum install gcc-c &#xff08;gcc -v 查看c版本&#xff09; 4.make 命令 加载环境&#xff08;make结束多src文件&#xff09;make之…

10.函数

10.1为什么需要函数 ●函数: function&#xff0c;是被设计为 执行特定任务的代码块 ●作用&#xff1a; 精简代码方便复用&#xff08;实现代码复用&#xff0c;提高开发效率&#xff09; 比如我们前面使用的alert()、prompt() 和console.log()都是一些js函数&#xff0c;只不…

gitee中fork了其他仓库,如何在本地进行同步

GitHub 操作&#xff1a;同步 Fork 来的仓库&#xff08;上游仓库&#xff09;_sigmarising的博客-CSDN博客 1. 设置upstream 2. git pull --rebase 3. 然后再执行pull、push操作

请将所有未处理的消息传递给 DefWindowProc

在之前的一篇文章中&#xff0c;我曾提到&#xff1a;如果你希望拒绝一次设备移除查询请求&#xff0c;则需要返回一个特殊的 BROADCAST_QUERY_DENY 值&#xff0c;因为太多的程序开发者认为&#xff0c;他们已经覆盖了所有 Windows 消息的处理了&#xff0c;对于其他的消息&am…