JAVA SCRIPT设计模式--行为型--设计模式之Mediator中介者模式(17)

news2024/11/17 23:34:50

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


一、UML类图

参与者:

1.1 Mediator(中介者,如DialogDirector)

  • 中介者定义一个接口用于与各同事(Colleague)对象通信

1.2 ConcreteMediator(具体中介者,如FontDialogDirector)

  • 具体中介者通过协调各同事对象实现协作行为。 
  • 了解并维护它的各个同事。

1.3 Colleagueclass(同事类,如ListBox,EntryField)

  • 每一个同事类都知道它的中介者对象。 
  • 每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。

二、意图

     用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从 而使其耦合松散,而且可以独立地改变它们之间的交互。

三、适用性 

  1. 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
  2. 一个对象引用其他很多对象并且直接与这些对象通信 ,导致难以复用该对象。
  3. 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

四、优点和缺点

  1. 减少了子类生成Mediator将原本分布于多个对象间的行为集中在一起。改变这些行为只需生成Meditator的子类即可。这样各个Colleague类可被重用
  2. 它将各Colleague解耦Mediator有利于各Colleague间的松耦合.你可以独立的改变和复用各Colleague类和Mediator类。
  3. 它简化了对象协议用Mediator和各Colleague间的一对多的交互来代替多对多的交互。一对多的关系更易于理解、维护和扩展
  4. 它对对象如何协作进行了抽象将中介作为一个独立的概念并将其封装在一个对象中,使你将注意力从对象各自本身的行为转移到它们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。
  5. 它使控制集中化中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装了协议,它可能变得比任一个Colleague都复杂。这可能使得中介者自身成为一个难于维护的庞然大物。

五、示例代码

5.1  动机

        面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。 在最坏的情况下,每一个对象都知道其他所有对象。

        虽然将一个系统分割成许多对象通常可以增强可复用性 , 但是对象间相互连接的激增又会降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作 —系统表现为一个不可分割的整体。而且 ,对系统的行为进行任何较大的改动都十分困难, 因为行为被分布在许多对象中。结果是 , 你可能不得不定义很多子类以定制系统的行为。

        例如,考虑一个图形用户界面中对话框的实现。对话框使用一个窗口来展现一系列的窗 口组件, 如按钮、菜单和输入域等, 如下图所示。


        通常对话框中的窗口组件间存在依赖关系。例如 , 当一个特定的输入域为空时 , 某个按钮不能使用;在称为列表框的一列选项中选择一个表目可能会改变一个输入域的内容;反过来,在输入域中输入正文可能会自动的选择一个或多个列表框中相应的表目;一旦正文出现在输 入域中, 其他一些按钮可能就变得能够使用了,这些按钮允许用户做一些操作 , 比如改变或删 除这些正文所指的东西。

        不同的对话框会有不同的窗口组件间的依赖关系。因此即使对话框显示相同类型的窗口 组件, 也不能简单地直接重用已有的窗口组件类 ; 而必须定制它们以反映特定对话框的依赖关 系。由于涉及很多个类,用逐个生成子类的办法来定制它们会很冗长。

        可以通过将集体行为封装在一个单独的中介者(Mediator )对象中以避免这个问题。中介者 负责控制和协调一组对象间的交互。中介者充当一个中介以使组中的对象不再相互显式引用。 这些对象仅知道中介者, 从而减少了相互连接的数目。 

5.2  示例UML

        例如,FontDialogDirector可作为一个对话框中的窗口组件间的中介者。FontDialogDirector对象知道对话框中的各窗口组件,并协调它们之间的交互。它充当窗口组件间通信的中转中心,
如下图所示。

         下面的交互图说明了各对象如何协作处理一个列表框中选项的变化。

         DialogDirector是一个抽象类,它定义了一个对话框的总体行为。客户调用ShowDialog操作将对话框显示在屏幕上。CreateWidgets是创建一个对话框的窗口组件的抽象操作。WidgetChanged是另一个抽象操作;窗口组件调用它来通知它的导控者它们被改变了。DialogDirector的子类将重定义CreateWidgets以创建正确的窗口组件,并重定义WidgetChanged以处理其变化。

目录结构:

5.3 Mediator(中介者,如DialogDirector)

  • 中介者定义一个接口用于与各同事(Colleague)对象通信

export default  class DialogDirector {
    widgetChildrens=[];
	
    constructor( ) {
		 
    }
    ShowDialog() {   
		this.ctx.clearRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
		this.ctx.strokeRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
		for(let n=0;n<this.widgetChildrens.length;n++)
		{
			let widge=this.widgetChildrens[n];
			widge.Draw();
		} 
    }
	
	CreateWidgets() {
		 
	}
	WidgetChanged(widget) {
		 
	}
	
	 
  }

5.4 ConcreteMediator(具体中介者,如FontDialogDirector)

  • 具体中介者通过协调各同事对象实现协作行为。 
  • 了解并维护它的各个同事。
import DialogDirector from '../DialogDirector.js';
import Button from '../../Widget/impl/Button.js';
import ListBox from '../../Widget/impl/ListBox.js';
import AntryField from '../../Widget/impl/AntryField.js';

export default class FontDialogDirector extends DialogDirector {
    ctx;
	rect;
	zooChildrens=[];
	  fontListBox ;
	  cancelButton ;
	  confirmButton ;
	  antryField ;
	
	constructor(ctx,rect) {
		super();
		this.ctx=ctx;
		this.rect=rect;
		this.CreateWidgets();
	}
	CreateWidgets() {
        this.zooChildrens=[];
		this.widgetChildrens=[];
		this.ctx.strokeRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
		let fontList = ['黑体:SimHei',
			'宋体:SimSun ',
			'新宋体:NSimSun',
			'仿宋:FangSong',
			'楷体:KaiTi ',
			'微软雅黑体:Microsoft YaHei'
		];
		let fontListZoo={startx:10,starty:10,width:180,height:200};
		let cancelBuZoo={startx:100,starty:220,width:40,height:25};
		let confirmBu={startx:150,starty:220,width:40,height:25};
		let antryFieldZoo={startx:10,starty:250,width:180,height:25};
		this.zooChildrens.push(fontListZoo);
		this.zooChildrens.push(cancelBuZoo);
		this.zooChildrens.push(confirmBu);
		this.zooChildrens.push(antryFieldZoo);
		
		this.fontListBox = new ListBox(this.ctx,fontList, this,fontListZoo);
		this.cancelButton = new Button(this.ctx,'取消', this,cancelBuZoo);
		this.confirmButton = new Button(this.ctx,'确定', this,confirmBu );
		this.antryField =new AntryField(this.ctx,'', this,antryFieldZoo );
		this.widgetChildrens.push(this.fontListBox);
		this.widgetChildrens.push(this.cancelButton);
		this.widgetChildrens.push(this.confirmButton);
		this.widgetChildrens.push(this.antryField);
		
	}

	WidgetChanged(widget) {
		let text=this.fontListBox.GetSelection();
		this.antryField.SetText(text);
	}
	
	onmousedown(e)
	{
		 let selectN=this.GetActiveItem(e);
		 if(selectN>-1)
		 {
		 	for(let n=0;n<this.widgetChildrens.length;n++)
		 	{
		 		let widget=this.widgetChildrens[n];
		 	    if(n==selectN)
		 			widget.SetIsClicked(true,e);
		 		else 
		 		    widget.SetIsClicked(false,e);
		 	}
		 }
	}
	onmousemove(e)
	{
		  let selectN=this.GetActiveItem(e);
		  if(selectN>-1)
		  {
		  	for(let n=0;n<this.widgetChildrens.length;n++)
		  	{
		  		let widget=this.widgetChildrens[n];
		  	    if(n==selectN)
		  			widget.SetIsMouseIn(true,e);
		  		else 
		  		    widget.SetIsMouseIn(false,e);
		  	}
		  }
	}
	
	GetActiveItem(e)
	{
		 var x = e.clientX;
		 var y = e.clientY;
		 if(x>this.rect.startx&&x<this.rect.startx+this.rect.width
		 &&y>this.rect.starty&&y<this.rect.starty+this.rect.height )
		 {
		 	 for(let n=0;n<this.zooChildrens.length;n++)
		 	 {
		 	 	 let zooChild=this.zooChildrens[n];
		 	 	 if(x>zooChild.startx&&x<zooChild.startx+zooChild.width
		 	 	 &&y>zooChild.starty&&y<zooChild.starty+zooChild.height )
				 {
					 return  n;
				 }
		 	 }
		 } 
		 else
		 return -1;
	}


}

5.5 Colleagueclass(同事类,如ListBox,EntryField)

  • 每一个同事类都知道它的中介者对象。 
  • 每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。
import Widget  from '../Widget.js';

export default  class AntryField extends Widget {
	text;
	rect;
	ctx;
    constructor(ctx,text,director,rect) {
		 super(director);
		 this.text=text;
		 this.rect=rect;
		 this.ctx=ctx;
    }
    Draw()
    {
		this.ctx.strokeRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
		if(this.isMouseIn){
			this.ctx.save();
			this.ctx.fillStyle="red";
			this.ctx.fillRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
			this.ctx.restore();
		}
    	this.ctx.textAlign="center";
    	this.ctx.fillText(this.text,this.rect.startx+this.rect.width/2,this.rect.starty+3*this.rect.height/4);
    } 
	Clicked()
	{
		 console.log(this.name+` Clicked `); 
	}
	SetText(text)
	{
		this.text=text;
		this.Draw();
	}
	
} 
import Widget  from '../Widget.js';

export default  class Button extends Widget {
	name;
	rect;
	ctx;
    constructor(ctx,name,director,rect) {
		 super(director);
		 this.name=name;
		 this.rect=rect;
		 this.ctx=ctx;
    }
    Draw()
    {
		this.ctx.strokeRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
		if(this.isMouseIn){
			this.ctx.save();
			this.ctx.fillStyle="red";
			this.ctx.fillRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
			this.ctx.restore();
		}
    	this.ctx.textAlign="center";
    	this.ctx.fillText(this.name,this.rect.startx+this.rect.width/2,this.rect.starty+3*this.rect.height/4);
    } 
	Clicked()
	{
		console.log(this.name+` Clicked `); 
	}
	
} 

import Widget  from '../Widget.js';

export default  class ListBox extends Widget {
	 
	nameList=[];
	rect;
	itemHeight=20;
	ctx;
	zooChildrens=[];
	selectN=-1;
    constructor(ctx,nameList,director,rect) {
		 super(ctx,director);
		 this.nameList=[];
		 this.nameList=nameList;
		 this.rect=rect;
		 this.ctx=ctx;
    }
   Draw()
   {
	   this.zooChildrens=[];
   	  this.ctx.strokeRect(this.rect.startx,this.rect.starty,this.rect.width,this.rect.height);
	  let x=this.rect.startx+10;
	  let y=this.rect.starty+20;
	  for(let n=0;n<this.nameList.length;n++)
	  {
	  	let name=this.nameList[n];
		let itemRect={startx:x,starty:y,width:180,height:20};
		if(this.isMouseIn&&n==this.selectN){
			this.ctx.save();
			this.ctx.fillStyle="blue";
			this.ctx.fillRect(itemRect.startx,itemRect.starty,itemRect.width-30,itemRect.height);
			this.ctx.restore();
		}
		this.ctx.textAlign="left";
		this.ctx.fillText(name,itemRect.startx+10,itemRect.starty+3*itemRect.height/4);
		// this.ctx.fillText(name,x,y);
		this.zooChildrens.push(itemRect);
		y=y+this.itemHeight;
		if(y>this.rect.height) break;
	  }
   }  
   GetSelection()
   {
	   if(this.selectN>-1)
	    return this.nameList[this.selectN];
   }
  Clicked()
  {
  
	this.Changed();
  } 
  SetIsClicked(isClicked,e)
  {
  	this.isclicked=isClicked;
  	if(isClicked)
  	{
		this.selectN=this.GetActiveItem(e);
		if(this.selectN>-1)
  		  this.Clicked();
  	}
  }
  SetIsMouseIn(isMouseIn,e)
  {
  	this.isMouseIn=isMouseIn;
	if(isMouseIn)
	{
		this.selectN=this.GetActiveItem(e);
	}
  }
  
  GetActiveItem(e)
  {
  	 var x = e.clientX;
  	 var y = e.clientY;
  	 if(x>this.rect.startx&&x<this.rect.startx+this.rect.width
  	 &&y>this.rect.starty&&y<this.rect.starty+this.rect.height )
  	 {
  	 	 for(let n=0;n<this.zooChildrens.length;n++)
  	 	 {
  	 	 	 let zooChild=this.zooChildrens[n];
  	 	 	 if(x>zooChild.startx&&x<zooChild.startx+zooChild.width
  	 	 	 &&y>zooChild.starty&&y<zooChild.starty+zooChild.height )
  			 {
  				 return  n;
  			 }
  	 	 }
  	 } 
  	 else
  	 return -1;
  }
	
} 

5.6  Client

import FontDialogDirector  from './DialogDirector/impl/FontDialogDirector.js';
 
 

export default class Client{
    fontDialogDirector;
    constructor(ctx,zooRect) {
    	this.fontDialogDirector=new FontDialogDirector(ctx,{startx:0,starty:0,width:300,height:300}); 
		this.fontDialogDirector.ShowDialog();
    }
	
	onmousedown(e)
	{
		  this.fontDialogDirector.onmousedown(e);
		  this.fontDialogDirector.ShowDialog();
	}
	onmousemove(e)
	{
		  this.fontDialogDirector.onmousemove(e);
		  this.fontDialogDirector.ShowDialog();
	}
    
 }

5.7 测试HTML

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


		<script type="module">
			import Client from './Client.js';
			var canvas = document.getElementById("mycanvas")
			var ctx = canvas.getContext("2d") //create 2d object
			let cl = new Client(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>

测试结果:

六、源代码下载

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

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

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

相关文章

图的初体验

最近周赛有两个差不多的题目&#xff0c;都是关于图的&#xff0c;之前也没有怎么练过关于图的题目&#xff0c;来记录一下。 T1 力扣T320周赛&#xff1a;T3&#xff1a;到达首都的最少油耗 class Solution {//结果long result ;public long minimumFuelCost(int[][] roads…

【推免攻略】四.2021年北交计算机学院夏令营、预推免保研经验

欢迎订阅本专栏&#xff1a;《北交计算机保研经验》 订阅地址&#xff1a;https://blog.csdn.net/m0_38068876/category_10779337.html 【推免攻略】一.北交计算机学院夏令营、预推免攻略【推免攻略】二.联系导师的前期准备及注意事项【推免攻略】三.2020年北交计算机学院夏令营…

如何能成为测试老大?先搞懂项目中的敏捷开发模式

1 什么是敏捷开发&#xff1f; 1、敏捷开发是以用户的需求进化为核心&#xff0c;采取迭代、循序渐进的方式来 进行软件项目的开发。 2、即将项目切分为多个子项目&#xff0c;每个子项目单独发布&#xff0c;保证软件较早可用。 3、及时收集用户反馈&#xff0c;调整未发布…

线性回归线性关系、非线性关系、常见函数导数、损失函数与优化算法、正规方程与单变量函数梯度下降、多变量函数梯度下降

一、线性回归概述 线性回归(Linear regression)&#xff1a;是利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式 特点&#xff1a;只有一个自变量的情况称为单变量回归&#xff0c;多于一个自变量情况的叫做多元回归 特征值与目…

机器学习笔记之受限玻尔兹曼机(五)基于含隐变量能量模型的对数似然梯度

机器学习笔记之受限玻尔兹曼机——基于含隐变量能量模型的对数似然梯度引言回顾&#xff1a;包含配分函数的概率分布受限玻尔兹曼机——场景构建对比散度基于含隐变量能量模型的对数似然梯度引言 上一节介绍了对比散度(Constractive Divergence)思想&#xff0c;本节将介绍基于…

制造型企业如何进行多项目管理?这篇文章说清楚了

受经济全球化与科技迅速发展的影响&#xff0c;我国很多企业早已进入了多项目管理模式。多项目管理是从企业整体出发&#xff0c;动态选择不具有类似性的项目&#xff0c;对企业所拥有的或可获得的生产要素和资源进行优化组合&#xff0c;有效、最优地分配企业资源&#xff0c;…

葡聚糖修饰金纳米颗粒(Dex-AuNps)|聚环氧氯丙烷二甲胺修饰多孔磁性葡聚糖微球

葡聚糖修饰金纳米颗粒(Dex-AuNps)|聚环氧氯丙烷二甲胺修饰多孔磁性葡聚糖微球 产品描述&#xff1a;通过特异性识别作用在表面等离子体共振传感器的金膜表面构建了伴刀豆球蛋白A/葡聚糖修饰金纳米颗粒自组装膜 中文名称&#xff1a;葡聚糖修饰金纳米颗粒 英文名称&#xff1…

CMAKE编译知识

1&#xff0c;Ubuntu安装了cmake之后&#xff0c;直接输入指令查看版本。cmake -version 我这里的版本为3.16.3 2&#xff0c;使用visual studio里面创建一个CMake项目是最快可以看到的。但是一般无法理解。所以我找了网上资料。根据网上所说和自己再试错下。初步了解了cmake…

[附源码]JAVA毕业设计微博网站(系统+LW)

[附源码]JAVA毕业设计微博网站&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xf…

IAA游戏市场规模已达百亿,如何防范游戏安全问题?

近年来&#xff0c;移动休闲游戏市场发展速度迅猛&#xff0c;伽马数据发布的《2022年休闲游戏发展报告》称&#xff0c;2022年第一季度移动游戏下载量TOP200榜单中&#xff0c;休闲类游戏占比已达45%。 2022年第一季度下载量TOP200移动游戏占比情况丨数据来源伽马数据 相比IA…

MMCV学习——基础篇4(Hook)| 八千字:从设计模式到源码解读

MMCV学习——基础篇4&#xff08;Hook&#xff09; Hook 机制在MMCV的各个开源库中应用的十分广泛&#xff0c;它主要用于管理和扩展Runner的整个生命周期。通过Hook机制在Runner的各个生命周期节点调用自定义的函数&#xff0c;可以实现丰富的定制功能。 文章目录MMCV学习——…

【C语言航路】第八站:调试(第一幕)

前言 调试的这一站&#xff0c;对于市面上大部分的书籍都是缺失的&#xff0c;然而调试这个内容是非常重要的&#xff0c;尤其是在数据结构部分&#xff0c;将会频繁的使用&#xff0c;这也为我们后面讲解数据结构做一个铺垫。同时&#xff0c;在以后未来工作的时候&#xff0…

Generative Cooperative Learning for Unsupervised Video Anomaly Detection

介绍 在现实世界中&#xff0c;基于学习的异常检测任务极具挑战性&#xff0c;这主要是因为此类事件很少发生。由于这些事件的无约束性质&#xff0c;这一挑战进一步加剧。因此&#xff0c;获取足够的异常示例是相当麻烦的&#xff0c;而人们可以安全地假设&#xff0c;将永远…

Xcode9 无证书真机调试​

写在前面​ 公司分配了新的测试机,证书99台名额已满,所以上网找教程,学习了一下如何使用Xcode无证书进行真机调试。​ 一. 创建证书​ 1. 运行Xcode&#xff0c; Xcode–》Preference–》添加账号&#xff08;能在appstore下载的账号&#xff09;​ 2. 选中刚才添加的AppleID…

光华股份在深交所上市:市值突破51亿元,前三季度收入约10亿元

12月8日&#xff0c;浙江光华科技股份有限公司&#xff08;下称“光华股份”&#xff0c;SZ:001333&#xff09;在深圳证券交易所主板上市。本次上市&#xff0c;光华股份的发行价格27.76元/股&#xff0c;发行数量为3200万股&#xff0c;募资总额约为8.88亿元&#xff0c;扣除…

JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK11特性讲解】

JDK各个版本特性讲解-JDK11特性 lecture&#xff1a;波哥 一、JAVA11 概述 2018年9月26日,Oracle官方发布JAVA11.这是JAVA大版本周期变化后的第一个长期支持版本,非常值得关注.最新发布的JAVA11将带来ZGC HttpClient等重要特性,一共17个需要我们关注的JEP,参考文档http://openj…

Docker_简介、优势、架构、常用命令

Docker简介 Docker是什么 Docker就是将环境在不消耗大量资源的情况下复制出一个一样的环境 一次镜像&#xff0c;处处运行 内核级虚拟化 基于GO语言实现的开源项目 解决运行环境和配置问题的软件容器 容器与虚拟机比较 虚拟机是模拟的整套操作系统&#xff0c;会有资源占用…

Unity Cg着色器开发教程

Unity Cg着色器开发教程 学习在 Unity 中对图形管道进行编程&#xff0c;以便为游戏对象创建独特的视觉表面 课程英文名&#xff1a;Shader Development from Scratch for Unity with Cg 此视频教程共2.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c…

代码随想录算法训练营第二天| 977.有序数组的平方, 209.长度最小的子数组, 59.螺旋矩阵II

代码随想录算法训练营第二天| 977.有序数组的平方&#xff0c; 209.长度最小的子数组&#xff0c; 59.螺旋矩阵II 题目链接: 977.有序数组的平方 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排…

ASEMI整流桥KBU610和KBP210封装参数区别

编辑-Z 很多人在选型时容易把KBU和KBP给搞混&#xff0c;这两种封装是有区别的&#xff0c;下面是整流桥KBU610和KBP210封装参数区别。 整流桥KBU610参数&#xff1a; 型号&#xff1a;KBU610 封装&#xff1a;KBU-4 最大重复峰值反向电压&#xff08;VRRM&#xff09;&…