JAVA SCRIPT设计模式--结构型--设计模式之Decorator装饰模式(9)

news2025/1/6 18:52:37

          JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C++,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代表全部的正确,特此声明。若读者需要了解设计模式目录、原则、设计变化方向,环境相关等信息请查看设计模式开篇。


一、UML类图

参与者:

1.1 Component(VisualComponent)  

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

1.2 ConcreteComponent(TextView)

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

1.3 Decorator

  • 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。

1.4 ConcreteDecorator(BorderDecorator,ScrollDecorator)

  • 向组件添加职责。

 

二、意图

     动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类 更为灵活。

三、适用性

  1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
  2.  处理那些可以撤消的职责  
  3. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持 每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类 定义被隐藏,或类定义不能用于生成子类。

四、优点和缺点

  1. 比静态继承更灵活与对象的静态继承(多重继承)相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类(例如,BorderScrollableTextView,BorderedTextView)。这会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性,例如在TextView上添加双边框时,仅需将添加两个BorderDecorator即可。而两次继承Border类则极容易出错的。
  2. 避免在层次结构高层的类有太多的特征Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时也更易于不依赖于Decorator所扩展(甚至是不可预知的扩展)的类而独立地定义新类型的Decorator。扩展一个复杂类的时候,很可能会暴露与添加的职责无关的细节。
  3. Decorator与它的Component不一样Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识
  4. 有许多小对象采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

五、示例代码

5.1  动机

        有时我们希望给某个对象而不是整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动。

        使用继承机制是添加功能的一种有效途径,从其他类继承过来的边框特性可以被多个子类的实例所使用。但这种方法不够灵活,因为边框的选择是静态的,用户不能控制对组件加边框的方式和时机。

        一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌 入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明 它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画一个边框)。 透明性使得你可以递归的嵌套多个装饰,从而可以添加任意多的功能,如下图所示。

         例如,假定有一个对象TextView,它可以在窗口中显示正文。缺省的TextView没有滚动条,因为我们可能有时并不需要滚动条。当需要滚动条时,我们可以用ScrollDecorator添加滚
动条。如果我们还想在TextView周围添加一个粗黑边框,可以使用BorderDecorator添加。因此只要简单地将这些装饰和TextView进行组合,就可以达到预期的效果。

        下面的对象图展示了如何将一个TextView对象与BorderDecorator以及ScrollDecorator对象组装起来产生一个具有边框和滚动条的文本显示窗口。

        

         ScrollDecorator和BorderDecorator类是Decorator类的子类。Decorator类是一个可视组件的抽象类,用于装饰其他可视组件,如下图所示。

        VisualComponent是一个描述可视对象的抽象类,它定义了绘制和事件处理的接口。注意Decorator类怎样将绘制请求简单地发送给它的组件,以及Decorator的子类如何扩展这个操作。
Decorator的子类为特定功能可以自由地添加一些操作。例如,如果其他对象知道界面中恰好有一个ScrollDecorator对象,这些对象就可以用ScrollDecorator对象的ScrollTo操作滚动这个界面。这个模式中有一点很重要,它使得在VisualComponent可以出现的任何地方都可以有装饰。因此,客户通常不会感觉到装饰过的组件与未装饰组件之间的差异,也不会与装饰产生任何依赖关系。
 

5.2  示例UML

目录结构:

5.2 Component(VisualComponent)  

  • 定义一个对象接口,可以给这些对象动态地添加职责。
export default  class VisualComponent {
	ctx;
    constructor(ctx) {
		this.ctx=ctx;
    }
    Draw() {   
		
    }
     
  }

5.3 ConcreteComponent(TextView)

  • 定义一个对象,可以给这个对象添加一些职责。
import VisualComponent  from '../VisualComponent.js';

export default  class TextView extends VisualComponent {
    x;y;
	constructor(ctx,x,y) {
		 super(ctx);
		 this.x=x;
		 this.y=y;
    }
    Draw() {
		this.ctx.font="40px Arial";
		this.ctx.fillText("Hello World!",this.x,this.y);
		console.log(` TextView Draw `);
    }

  } 

5.4 Decorator

  • 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。

import VisualComponent  from '../VisualComponent.js';
export default  class Decorator extends VisualComponent {
	visualComponent;
    constructor(ctx,visualComponent) {
		 super(ctx);
		 this.visualComponent=visualComponent;
    }
    Draw() {
		this.visualComponent.Draw();
    }
    
  } 

5.5 ConcreteDecorator(BorderDecorator,ScrollDecorator)

  • 向组件添加职责。

import Decorator  from '../Decorator.js';
export default  class BorderDecorator extends Decorator {
	pos;
    constructor(ctx,visualComponent,pos) {
		 super(ctx,visualComponent); 
		 this.pos=pos;
    }
    Draw() {
		super.Draw();
		this.DrawBorder();
    }
	DrawBorder()
	{
		this.ctx.beginPath();
		this.ctx.lineWidth="2";
		this.ctx.strokeStyle="red";
		this.ctx.rect(this.pos.x,this.pos.y,this.pos.width,this.pos.height);
		this.ctx.stroke();
	}
    
  } 
import Decorator  from '../Decorator.js';
export default  class ScrollDecorator extends Decorator {
	pos;
    constructor(ctx,visualComponent,pos) {
		 super(ctx,visualComponent); 
		 this.pos=pos;
    }
    Draw() {
		super.Draw();
		this.DrawScroll();
    }
	DrawScroll()
	{
		this.ctx.beginPath();
		this.ctx.lineWidth="4";
		this.ctx.fillStyle="#0000ff";
		this.ctx.fillRect(this.pos.x,this.pos.y,this.pos.width,this.pos.height);
		// this.ctx.rect(this.pos.x,this.pos.y,this.pos.width,this.pos.height);
		this.ctx.stroke();
	}
    
  } 

5.6 Client

import VisualComponent  from './VisualComponent/VisualComponent.js';
import TextView  from './VisualComponent/impl/TextView.js';
import BorderDecorator  from './VisualComponent/Decorator/impl/BorderDecorator.js';
import ScrollDecorator  from './VisualComponent/Decorator/impl/ScrollDecorator.js';
 
 
export default class Client{
    main(ctx){
	  /*只是一个装饰的例子,还原原文中的装饰思路,忽略硬代码部分*/
	    let atextView =new TextView(ctx,40,150);//Graphic
		let ascrollDecorator =new ScrollDecorator(ctx,atextView,{x:280,y:0,width:15,height:300});//Graphic
		let aborderDecorator =new BorderDecorator(ctx,ascrollDecorator,{x:0,y:0,width:300,height:300});//Graphic
	
		aborderDecorator.Draw();
    } 
 }

5.7 测试HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
 
 
 <script  type="module" >
 import Client  from './Client.js'; 
 var x=document.getElementById("mycanvas")
 var ctx=x.getContext("2d") //create 2d object
let cl=new Client();
cl.main(ctx)

 </script>
</head>
<body>
<canvas id="mycanvas" width=300px height=300px></canvas>
    
</body>
</html>

测试结果:

六、源代码下载

        下载链接:https://pan.baidu.com/s/1XuPqp84cccBNVkbnMY3sKw 
         提取码:q2ut

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

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

相关文章

JSP ssh房地产项目管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP ssh房地产项目管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7…

吉林省教育学院学报杂志社吉林省教育学院学报编辑部2022年第11期目录

特稿 高职院校思政课“一体两翼四融合”教学模式的构建探索——以吉林工业职业技术学院为例 杨宝忠;解静; 1-5 高校业财融合体系研究 朱延辉; 6-9 教育理论与管理《吉林教育学院学报》投稿&#xff1a;cn7kantougao163.com 新教育评价改革背景下幼儿园教师评价能力…

pikachu-xss部分速通

pikachu-xss部分速通 &#x1f349; &#x1f349;目录pikachu-xss部分速通反射型xss(get)反射性xss(post)存储型xssDOM型xss、DOM型xss-xxss盲打xss之过滤xss之htmlspecialcharsxss之href输出xss之js输出反射型xss(get) payload: </p><script>alert(1)</scr…

AI绘画绘图流量主小程序开发

AI绘画绘图流量主小程序开发 响应式设计——响应式布局&#xff0c;手机、平板、PC自适应匹配。 自定义模型——自定义内容模型、自定义字段、自定义表单。 付费阅读——支持企业支付宝、企业微信支付、余额支付无缝整合。 微信小程序端——微信小程序CMS客户端和服务端全部源…

【Linux】Docker 搭建 Jenkins

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; 目录一、Jenkins到底是什么&#xff1f;二、持…

微服务框架 SpringCloud微服务架构 26 数据聚合 26.3 DSL 实现Metrics 聚合

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构26 数据聚合26.3 DSL 实现Metrics 聚合26.3.1 DSL 实现Metrics 聚合26 数据…

ADI DSP的JTAG设计规范(提供JTAG标准设计原理图)

早就想写点这方面内容了&#xff0c;14PIN的JTAG设计&#xff0c;是ADI从2000年至今一直延续下来的一个JTAG标准设计&#xff0c;很多兄弟在做硬件设计的时候&#xff0c;最常问的一个问题就是&#xff1a;JTAG接口定义是什么&#xff1f;更多的只知道抄原厂评估板的参考设计&a…

Nginx 反向代理与负载均衡

什么是Nginx Nginx 是一款高性能的 http 服务器和反向代理服务器&#xff0c;官方测试 nginx 能够支支撑 5 万并发链接&#xff0c;并且 cpu、内存等资源消耗却非常低&#xff0c;运行非常稳定。 Nginx 应用场景 http 服务器&#xff1a;Nginx 是一个 http 服务可以独立提供…

web前端期末大作业:HTML+CSS+JavaScript绿色的盆栽花店网站响应式模板 大学生鲜花网页设计

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

嵌入式面试问题汇总

文章目录c/c1、malloc与new的区别2、C语言内存分配的方式3、struct 与 class的区别4、const常量和#define的区别5、vector与list6、各个stl的底层实现7、动态绑定与静态绑定8、多态实现的三个条件、实现的原理9、析构函数一般写成虚函数的原因10、构造函数不能是虚函数的原因11…

把握数字化时代发展机遇,供应链协同系统驱动生物医药企业提速数字化转型升级

生物医药行业是指将基因工程、细胞工程、酶工程等现代生物技术与各种形式的新药研发、生产相结合&#xff0c;制造市场可流通药品并规模化生产的经济实体的总和。近年来&#xff0c;随着国内生物医药行业的不断扩张及竞争日益激烈&#xff0c;如何借助数字化打造生物医药企业核…

(15)点云数据处理学习——单目深度估计获得RGBD图再重建点云

1、主要参考 &#xff08;1&#xff09;大佬视频 Create Your Own Point Clouds from Depth Maps - Point Cloud Processing in Open3D_哔哩哔哩_bilibili &#xff08;2&#xff09;重要&#xff01;&#xff01;&#xff01;我前面的教程 &#xff08;7&#xff09;点云数…

配置gradle :将properties文件转换为扩展属性

配置gradle 为了便于管理项目配置信息&#xff0c;和自动复制应用图标到资源文件夹&#xff0c;为后面的一键生成app做准备。我写了一个gradle文件。 作用 项目启动的时候自动执行以下操作 在setting.gradle中引入一次后&#xff0c;全局可用。根目录的build.gradle和各个mo…

如何理解Spring?

Spring 是包含了众多⼯具⽅法的 IoC 容器。 那何为容器呢&#xff1f;容器是用来容纳某种东西的装置。比如&#xff1a;List/Map 是数据存储容器&#xff0c;Tomcat 是Web 容器等等。Spring 也是⼀个容器&#xff0c;是⼀个 IoC 容器。 那何为IoC 呢&#xff1f;IoC Inversi…

Buildroot系列开发(四)Linux工具链剖析

内容参考&#xff1a;百问网 文章目录1.什么是工具链2.什么是交叉编译工具链3.ABI4. Multilib工具链5.工具链与SDK的区别6.获得适合的交叉编译工具链7.sysroot8.Toolchain内部剖析9.根文件系统与sysroot10. 工具链组成11.整体构建过程12.自定义工具链1.什么是工具链 2.什么是交…

毕业设计-基于大数据动画电影推荐系统-python

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

面试题:三个线程按顺序打印 ABCABC

小伙伴们好呀&#xff0c;最近在重新复习&#xff0c;整理自己的知识库&#xff0c;偶然看到这道面试题&#xff1a;三个线程按顺序打印 ABCABC&#xff0c;尝试着做一下&#xff0c;才发现自己对线程还有好多地方不懂&#xff0c;蓝瘦…… &#x1f437; 思路 很明显&#xf…

Docker可视化工具Portainer安装

一、官网介绍 官方地址&#xff1a;https://www.portainer.io/ 致力于为开发者做最强大的docker管理平台二、在 Linux 上使用 Docker 安装 Portainer 官方文档地址&#xff1a;https://docs.portainer.io/start/install/server/docker/linux 1、部署前需知 &#xff08;1&a…

SautinSoft JBIG2 .Net提供了解读jb2文档的API

SautinSoft JBIG2 .Net提供了解读jb2文档的API SautinSoft的JBIG2.Net是一个独立且简单的SDK&#xff0c;为您提供了解读jb2文档的API。该部分将使您的软件能够使用3-4个C#行将JBIG2文件的任何网页转换为照片格式&#xff1a;png、Tiff、jpeg。 JBIG2.Net能给我什么 节省项目开…

PyQt中的多线程QThread示例

PyQt中的多线程一、PyQt中的多线程二、创建线程2.1 设计ui界面2.2 设计工作线程2.3 主程序设计三、运行结果示例一、PyQt中的多线程 传统的图形用户界面应用程序都只有一个执行线程&#xff0c;并且一次只执行一个操作。如果用户从用户界面中调用一个比较耗时的操作&#xff0…