JAVA SCRIPT设计模式--行为型--设计模式之Command命令模式(14)

news2024/11/18 23:25:06

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


一、UML类图

参与者:

1.1 Command 

  • 声明执行操作的接口。

1.2 ConcreteCommand(PasteCommand,OpenCommand)

  • 将一个接收者对象绑定于一个动作。
  • 调用接收者相应的操作,以实现Execute。
  • 如果可处理该请求,就处理之;否则将该请求转发给它的后继者。

1.3 Client

  • 创建一个具体命令对象并设定它的接收者。

1.4 Invoker(MenuItem)

  • 要求该命令执行这个请求。

1.5 Receiver(Document,Application)

  • 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

二、意图

     将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

三、适用性 

  1. 像MenuItem对象那样,抽象出待执行的动作以参数化某对象。你可用过程语言中的回调(callback)函数表达这种参数化机制。所谓回调函数是指函数先在某处
    注册,而它将在稍后某个需要的时候被调用。Command模式是回调机制的一个面向对象的替代品。
  2. 在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
  3. 支持取消操作。Command的Excute操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command接口必须添加一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消”和“重做”。
  4. 支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。
  5. 用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务(transaction)的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。

四、示例代码

4.1  动机

      有时必须向某对象提交请求,但并不知道关于被请求的操作或请求的接受者的任何信息。例如,用户界面工具箱包括按钮和菜单这样的对象,它们执行请求响应用户输入。但工具箱 不能显式的在按钮或菜单中实现该请求,因为只有使用工具箱的应用知道该由哪个对象做哪 个操作。而工具箱的设计者无法知道请求的接受者或执行的操作。

      命令模式通过将请求本身变成一个对象来使工具箱对象可向未指定的应用对象提出请求。这个对象可被存储并像其他的对象一样被传递。这一模式的关键是一个抽象的Command类,它定义了一个执行操作的接口。其最简单的形式是一个抽象的Execute操作。具体的Command子类将接收者作为其一个实例变量,并实现Execute操作,指定接收者采取的动作。而接收者有执行该请求所需的具体信息。

        用Command对象可很容易的实现菜单(Menu),每一菜单中的选项都是一个菜单项(MenuItem)类的实例。一个Application类创建这些菜单和它们的菜单项以及其余的用户界面。该Application类还跟踪用户已打开的Document对象。该应用为每一个菜单项配置一个具体的Command子类的实例。当用户选择了一个菜单项时,该MenuItem对象调用它的Command对象的Execute方法,而Execute执行相应操作。MenuItem对象并不知道它们使用的是Command的哪一个子类。Command子类里存放着请求的接收者,而Excute操作将调用该接收者的一个或多个操作。

4.2  示例UML

目录结构:

4.1 Command 

  • 声明执行操作的接口。
export default  class Command {
	 state;
    constructor( ) {
		 
    }
    Execute() {   
		 
    }
  }

4.2 ConcreteCommand(PasteCommand,OpenCommand)

  • 将一个接收者对象绑定于一个动作。
  • 调用接收者相应的操作,以实现Execute。
  • 如果可处理该请求,就处理之;否则将该请求转发给它的后继者。
import Command  from '../Command.js'; 
import WordDocument  from '../../Document/impl/WordDocument.js'; 

export default  class OpenCommand extends Command {
     application
	constructor(application ) {
	 super();
	 this.application=application;
	}
   
	Execute() {
		console.log(` ask user select file  `);
		let doc=new WordDocument();
		this.application.Add(doc);
		doc.Open(); 
	}
  } 
import Command  from '../Command.js'; 
export default  class PasteCommand extends Command {
     application
	constructor(application ) {
	 super();
	 this.application=application;
	}
   
	Execute() {
		this.application.doc.Paste(); 
	}
  }

4.3 Client/Application

  • 创建一个具体命令对象并设定它的接收者。
import Menu  from './Menu/Menu.js';
import MenuItem  from './Menu/MenuItem.js'; 
import OpenCommand  from './Command/impl/OpenCommand.js'; 
import PasteCommand  from './Command/impl/PasteCommand.js'; 
import MyDocument  from './Document/impl/MyDocument.js'; 

export default class Application{
    menu;
	doc;
	zooRect;
    constructor(ctx,zooRect) {
    	this.ctx=ctx;
		this.zooRect=zooRect;
		this.doc=new MyDocument();
		this.createMenu(ctx);
		this.Draw();
    }
    Add(document)
    {
		this.doc=document;
    }
	Draw()
	{
		this.ctx.clearRect(this.zooRect.startx,this.zooRect.starty,this.zooRect.width,this.zooRect.height);
		this.menu.Draw();
	}
	onmousedown(e)
	{
		  this.menu.onmousedown(e);
		  this.Draw();
	}
	onmousemove(e)
	{
		  this.menu.onmousemove(e);
		  this.Draw();
	}
  
	createMenu(ctx)
	{
		this.menu=new Menu(ctx);
		let fileItem=new MenuItem(ctx,'文件(F)',null);
		this.menu.Add(fileItem);
		let newItem=new MenuItem(ctx,'新建(N)',null);
		fileItem.Add(newItem);
		
		
		let openCommand=new OpenCommand(this);
		let openItem=new MenuItem(ctx,'打开(O)',openCommand);
		fileItem.Add(openItem);
		
		let pasteCommand=new PasteCommand(this);
		let pasteItem=new MenuItem(ctx,'粘贴(P)',pasteCommand);
		fileItem.Add(pasteItem);
		
		
		let editItem=new MenuItem(ctx,'编辑(E)',null);
		this.menu.Add(editItem);
		
		
		let helpItem=new MenuItem(ctx,'帮助(H)',null);
		this.menu.Add(helpItem);
	}
   
 }

4.4 Invoker(MenuItem)

  • 要求该命令执行这个请求。
export default  class MenuItem {
	ctx;
	name;
	command;
	isleaf=true;
	isclicked=false;
	isMouseIn=false;
	menuItemChildrens=[];
	menuZooChildrens=[];
	menuItemZoo={startx:10,starty:50,width:0,height:40};
    constructor(ctx,name,command) {
		this.ctx=ctx;
		this.name=name;
		this.command=command;
    }
	Draw(startx,starty,width,height)
	{
		this.menuItemZoo={startx:startx,starty:starty,width:width,height:height};
		this.ctx.strokeRect(startx,starty,width,height);
		if(this.isMouseIn){
			this.ctx.save();
			this.ctx.fillStyle="red";
			this.ctx.fillRect(startx,starty,width,height);
			this.ctx.restore();
		}
		this.ctx.textAlign="center";
		this.ctx.fillText(this.name,startx+width/2,starty+3*height/4);
		if(this.isclicked)
		 this.DrawItem()
	}
	DrawItem( )
	{
		this.menuZooChildrens=[];
		if(!this.isleaf)
		{
			let x=this.menuItemZoo.startx;
			let y=this.menuItemZoo.starty;
			this.ctx.font="20px Arial";
			
			for(let n=0;n<this.menuItemChildrens.length;n++)
			{
				let menuItem=this.menuItemChildrens[n];
				menuItem.Draw(x,y+this.menuItemZoo.height,150,this.menuItemZoo.height);
				let zooChild={startx:x,starty:y+this.menuItemZoo.height,width:150,height:this.menuItemZoo.height};
				this.menuZooChildrens.push(zooChild);
				y=y+this.menuItemZoo.height;
			}
			this.menuItemZoo.height= y;
		}
	}
	Add(menuItem){
		this.isleaf=false;
		this.menuItemChildrens.push(menuItem);
	}
	Clicked()
	{
		if(this.isleaf&&this.command!=null)
		  this.command.Execute();
	 
	}
	SetIsClicked(isClicked)
	{
		this.isclicked=isClicked;
		if(isClicked)
		{
			this.Clicked();
		}
			
		 
	}
	SetIsMouseIn(isMouseIn)
	{
		this.isMouseIn=isMouseIn;
	}
	
	onmousedown(e)
	{
		let selectN=this.GetActiveItem(e);
		if(selectN>-1)
		{
			for(let n=0;n<this.menuItemChildrens.length;n++)
			{
				let menuItem=this.menuItemChildrens[n];
			    if(n==selectN)
					menuItem.SetIsClicked(true);
				else 
				    menuItem.SetIsClicked(false);
			}
			// this.Draw()	 
		}
	}
	onmousemove(e)
	{
		 let selectN=this.GetActiveItem(e);
		 if(selectN>-1)
		 {
			 for(let n=0;n<this.menuItemChildrens.length;n++)
			 {
			 	let menuItem=this.menuItemChildrens[n];
			     if(n==selectN)
			 		menuItem.SetIsMouseIn(true);
			 	else 
			 	    menuItem.SetIsMouseIn(false);
			 }
		 }
	}
	GetActiveItem(e)
	{
		 var x = e.clientX;
		 var y = e.clientY;
		 if(x>this.menuItemZoo.startx&&x<this.menuItemZoo.startx+this.menuItemZoo.width
		 &&y>this.menuItemZoo.starty&&y<this.menuItemZoo.starty+this.menuItemZoo.height )
		 {
		 	 for(let n=0;n<this.menuZooChildrens.length;n++)
		 	 {
		 	 	 let zooChild=this.menuZooChildrens[n];
		 	 	 if(x>zooChild.startx&&x<zooChild.startx+zooChild.width
		 	 	 &&y>zooChild.starty&&y<zooChild.starty+zooChild.height )
				 {
					 return  n;
				 }
		 	 }
		 } 
		 else
		 return -1;
	}
  }

4.5 Receiver(Document)

  • 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
import Document  from '../Document.js';

export default  class MyDocument extends Document {
    constructor() {
		 super();
    }
    Open() {  
		 console.log(` MyDocument Open `);
    }
    Close() {     
		 console.log(` MyDocument Close `);
    }
	Save() {
		 console.log(` MyDocument Save `);
	}
	Revert() {
		 console.log(` MyDocument Revert `);
	}
	Paste(){
		console.log(` MyDocument Paste `);
	}
  } 

4.6 测试HTML

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">


		<script type="module">
			import Application from './Application.js';
			var canvas = document.getElementById("mycanvas")
			var ctx = canvas.getContext("2d") //create 2d object
			let cl = new Application(ctx,{startx:0,starty:0,width:900,height:900});
			canvas.onmousedown = (e) => {
				cl.onmousedown(e);
			};
			canvas.onmousemove = (e) => {
				cl.onmousemove(e);
			};
		 
		</script>
	</head>
	<body>
		<canvas id="mycanvas" width=900px height=900px></canvas>

	</body>
</html>

测试结果:

MyDocument.js:20  MyDocument Paste 
OpenCommand.js:12  ask user select file  
WordDocument.js:8  WordDocument Open 
WordDocument.js:20  WordDocument Paste 

五、源代码下载

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

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

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

相关文章

服务器硬件规格常用查看命令——CPU相关命令

使用lscpu 命令可以从sysfs和/proc/cpuinfo中收集CPU体系结构信息&#xff0c;并解析优化为易阅读的格式。该信息包括&#xff1a;CPU的线程、核心、套接字数量和非一致内存访问&#xff08;NUMA&#xff09;节点的数量&#xff0c;以及CPU缓存、共享缓存、系列、型号等信息。 …

英文写作—Grammarly安装及下载

Grammarly是一款在线语法纠正和校对工具&#xff0c;支持Windows、Mac、iOS和Android等多个平台。 主要功能包括检查单词拼写、纠正标点符号、修正语法错误、调整语气以及给出风格建议等&#xff1b;对学术写作来说&#xff0c;Grammarly还可以帮助查重。 登陆界面&#xff1a…

每日一题:折半查找法,二分查找法

每日一题&#xff1a;折半查找法&#xff0c;二分查找法每日一题&#xff1a;折半查找法&#xff0c;二分查找法二分查找法定义&#xff1a;代码1&#xff1a;代码2&#xff1a;每日一题&#xff1a;折半查找法&#xff0c;二分查找法 ​ &#x1f496;&#x1f496;个人博客:比…

SpringBoot之自定义注解

目录 1.java注解简介 1.1.java注解分类 1.1.1.JDK基本注解 1.1.2.JDK元注解 1.1.3.自定义注解 1.1.4 在这里如何自定义注解&#xff1f; 2、自定义注解 3.Aop应用自定义注解 1.java注解简介 Java注解是附加在代码中的一些元信息&#xff0c;用于一些工具在编译、运行时进行解…

可靠性udp传输大文件

高级计算机网络大作业-可靠性udp传输大文件实验数据zstd压缩1G文件&#xff08;延迟100ms、丢包1%&#xff09;0.1G文件&#xff08;延迟100ms、丢包1%&#xff09;0.01G文件&#xff08;延迟100ms、丢包1%&#xff09;多线程lzma压缩1G文件&#xff08;延迟100ms、丢包1%&…

N子棋(外加双人对战)详解!推荐!!!

文章目录准备工作创建菜单进入游戏初始化棋盘、打印棋盘玩家下棋、电脑下棋、生成随机数判断输赢大家好&#xff01;时隔多天&#xff0c;我终于写博客了&#xff0c;真的是开心&#xff01;这一次带来的是N子棋有双人对战和单人下棋&#xff0c;请认真看下去&#xff0c;我会竭…

虚拟人纷纷「出道」,社交泛娱乐场景如何迎接新顶流?

⬆️“政企数智办公行业研究报告及融云新品发布会”明天直播&#xff01; 本月 12 日&#xff0c;花房集团即将于香港上市。关注【融云全球互联网通信云】回复【融云】抽取高颜值大容量高端可乐保温杯哦~ 中国政企数智办公平台 在带货直播平台的赫赫之名下&#xff0c;娱乐直播…

Git —— 那些在工作中日常使用的操作

Git —— 那些在工作中日常使用的操作 《工欲善其事&#xff0c;必先利其器》—— 既然点进来了&#xff0c;麻烦你看下去&#xff0c;希望你有不一样的收获~ 一、同一项目关联不同平台的远程仓库 格式&#xff1a;git remote add 命名 仓库链接 git remote add github ssh:/…

六、排序算法介绍2

1、冒泡排序 1.1 基本介绍 冒泡排序&#xff08;Bubble Sorting&#xff09; 的基本思想是&#xff1a; 通过对待排序序列从前向后&#xff08;从下标较小的元素开始&#xff09;&#xff0c;依次比较相邻元素的值&#xff0c; 若发现逆序则交换&#xff0c; 使值较大的元素逐…

netcore接入钉钉扫码登录

netcore接入钉钉扫码登录一、首先官方文档预览二、登录钉钉开发者后台三、创建第三方登录授权应用1.新版打开方式2.旧版打开方式&#xff08;1&#xff09;先返回旧版页面&#xff08;2&#xff09;选择应用开发&#xff08;3&#xff09;编辑登录应用信息&#xff08;4&#x…

npm包是什么?如何发布npm包?

Node的组成 内置模块 自定义模块 第三方模块&#xff08;什么是包&#xff1f;&#xff09; npm包包括那些东西&#xff1f; package.json README.md 。。。.js 注册npm账号 细节 发布包 package.json README.md index.js date htmlEscape 层级结构 发布指令 N…

STC15 - C51 - Memory Models

文章目录STC15 - C51 - Memory Models概述笔记内存用量的优化思路ENDSTC15 - C51 - Memory Models 概述 在STC上测试呢, 想看看变量(不同类型的定义)被编译器分配在哪个内存范围(idata, pdata, xdata)? 同时, 总结一下降低内存用量的思路(如果像上位机那样内存管够, 就不用考…

Linux系统编程第五节——进程创建、终止、等待(通俗易懂快速上手版本)

目录 进程的创建 写时拷贝 进程的终止 进程的等待 状态参数status wait函数和waitpid函数 我们本节内容&#xff0c;主要来讲述进程控制有关的内容。 同样&#xff0c;我们会用通俗易懂、不同于教科书的讲授思路&#xff0c;来为大家讲解。 同时&#xff0c;本节内容板块…

你了解你的身体吗?- 基因社会

关于作者 本书的两位作者分别是以太•亚奈和马丁 • 菜凯尔&#xff0c;前者是哈佛大学髙级研究学者&#xff0c; 任职于纽约大学&#xff0c;是生物化学和分子药理 学的教授&#xff1b;后者是杜塞尔多夫海因西里•海 涅大学的生物信息学教授。两位作者从基 因之间合作和竞争…

[附源码]计算机毕业设计的4s店车辆管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

5款十分好用,但是没有什么知名度的软件

随着网络信息技术的发展&#xff0c;越来越多的人在办公时需要用到电脑了。如果你想提高办公效率&#xff0c;那么就少不了工具的帮忙&#xff0c;今天给大家分享5款办公必备的好软件。 1.数据可视化软件——Power BI Power BI是一款出色的业务分析软件。Power BI主要是用于在…

[Go] go基础4

1. 并发编程 1.1 并发和并行 并发: 多个线程在同个核心的CPU上运行.并发的本质是串行. 并行: 多个线程在多个核心的CPU上运行. 1.2 协程和线程 协程: 独立的栈空间,共享堆空间,调度由用户控制,本质上有点类似用户及线程,这些用户及线程的调度也是自己实现的. 线程: 一个线…

[附源码]JAVA毕业设计网络饮品销售管理系统(系统+LW)

[附源码]JAVA毕业设计网络饮品销售管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

全新社交电商模式来袭,消费增值结合共享经济完成消费升级

大家好&#xff0c;我是林工&#xff0c;不知道大家是否了解消费增值&#xff1f;这是一个消费储量为基础的理念&#xff0c;体现的是消费者的消费与回报问题&#xff0c;普遍的消费返利&#xff0c;消费全返渐渐地已经不能够满足目前的客户&#xff0c;也就有了一个满足与这部…

【嵌入式硬件芯片开发笔记】4-20mA DAC芯片AD5421配置流程

【嵌入式硬件芯片开发笔记】4-20mA DAC芯片AD5421配置流程 16位、串行输入、环路供电、4 mA至20 mA DAC 可用于HART协议相关电路 同AD5700配合使用 AD5421的SPI和普通的不一样 回读时要发两段 CS中间拉高一次 数据在SCLK上升沿逐个输出&#xff0c;而且在 SCLK下降沿有效 固CP…