C#设计模式之18——中介者模式

随着越来越多的类在程序中被开发出来,这些类之间的通信问题变得越来越复杂。每个类需要知道其他类的方法越多,类的结构就容易变得混乱,这使得程序不易于阅读和维护。另外,对程序的修改也变得困难起来,因为任何修改都会影响到其他多个类的代码。中介者模式通过促进这些类之间更加松散的耦合来解决这一问题。中介者实现这样一做法的方式是,成为唯一一个详细了解其他类的方法的类,其他的类在改变发生的时候通知中介者,中介者把这些变动传递给其他任何需要被通知的类。

我们的例子中,是这样的一个程序,用户界面如图所示:

当程序启动的时候,两个按钮都被禁用,当有选手被选中的时候copy按钮可以使用,当右侧列表有信息了以后clear按钮可用,clear以后两个按钮都不可用。

这样在这里可视化空间的交互非常复杂,交互关系图:

中介者模式简化了这一系统,方法是其作为唯一知晓系统内的其他的类的类存在。每个与中介者通信的空间都成为同事,每个同时在接收到某些用户事件以后通知中介者,接着中介者决定应该向其他哪些类通知该事件。

中介者的优点很明显,踏实唯一了解其他类的类,因此,如果其他类中的某一个发生了变化,或者添加了其他的界面控件类,中介者就是唯一休要修改的类。

这个例程中还是用了命令模式将按钮的事件和要处理的代码分离开来。

定义一个命令模式中要使用的共同接口:

using System;
using CsharpPats;

namespace Mediate
{
	/// <summary>
	/// Command interface
	/// </summary>
	public interface Command
	{
		void Execute();
	}
}


先是构建了一个复制按钮类:CpyButton

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Mediate
{
	/// <summary>
	/// Button command passes its click to the mediator
	/// </summary>
	public class CpyButton : System.Windows.Forms.Button, Command 	{
		private Container components = null;
		private Mediator med;
		//-----
		public CpyButton() 		{
			InitializeComponent();
		}
		//-----
		public void setMediator(Mediator md) {
			med = md;
		}
		//-----
		public void Execute() {
			med.copyClicked ();
		}
		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			components = new System.ComponentModel.Container();
		}
		#endregion
	}
}


这里的执行函数通过中介者来实现。

其他按钮的定义:

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Mediate
{
	/// <summary>
	/// Summary description for ClrButton.
	/// </summary>
	public class ClrButton : System.Windows.Forms.Button , Command
	{
		/// <summary> 
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;
		private Mediator med;
		//-----
		public ClrButton() 		{
			InitializeComponent();
		}
		//-----
		public void setMediator(Mediator md) {
			med = md;
		}
		//-----
		public void Execute() {
			med.clearClicked ();
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			components = new System.ComponentModel.Container();
		}
		#endregion
	}
}


这里还用到了上一节介绍的迭代器模式,用来迭代游泳选手的数据。

然后定义了一个KidList列表控件:

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Mediate
{
	/// <summary>
	/// Summary description for KidList.
	/// </summary>
	public class KidList : System.Windows.Forms.ListBox, Command
	{
		private System.ComponentModel.Container components = null;
		private Mediator med;
		//-----
		public KidList() 		{
			InitializeComponent();
		}
		//-----
		public void Execute() {
			med.kidPicked ();
		}
		//-----
		public void setMediator(Mediator md) {
			med = md;
		}
		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			components = new System.ComponentModel.Container();
		}
		#endregion
	}
}


然后我们就开始构造中介者了,中介者需要给他传递中介者需要调节的所有控件的引用:

using System;
using System.Windows.Forms;
namespace Mediate
{
	/// <summary>
	/// Receives all command actions from buttons and lists
	/// and sends commands to all the relevant controls
	/// </summary>
	public class Mediator 	{
		private CpyButton cpButton;		//buttons
		private ClrButton clrButton;
		private TextBox txKids;			//text box
		private ListBox pkList;			//list boxes
		private KidList klist;
		private KidData kds;			//list of data from file

		public Mediator(CpyButton cp, ClrButton clr, KidList kl, ListBox pk) 		{
			cpButton = cp;			//copy in buttons
			clrButton = clr;
			klist = kl;				//copy in list boxes
			pkList = pk;
			kds = new KidData ("50free.txt");	//create data list class
			clearClicked();				//clear all controls
			KidIterator kiter = kds.getIterator ();
			while(kiter.MoveNext () ) {		//load list box
				Kid kd = (Kid) kiter.Current ;
				klist.Items .Add (kd.getFrname() +" "+kd.getLname ());
			}
		}
		//-----
		//get text box reference
			public void setText(TextBox tx) {
				txKids = tx;
			}
		//-----
		//clear lists and set buttons to disabled
		public void clearClicked() {
			//disable buttons and clear list
			cpButton.Enabled = false;
			clrButton.Enabled = false;
			pkList.Items.Clear();
		}
		//-----
		//copy data from text box to list box
		public void copyClicked() {
			 //copy name to picked list
			pkList.Items.Add(txKids.Text);
			//clear button enabled
			clrButton.Enabled = true;
			klist.SelectedIndex = -1;
		}
		//-----
		//copy selected kid to text box
		//enable copy button
		public void kidPicked() {
			//copy text from list to textbox
			txKids.Text = klist.Text;
			//copy button enabled
			cpButton.Enabled = true;
		}
	}
}


这里的中介者中包含了所有的控件(就是我们这里所谓的同事)将来发送给中介者的事件,然后中介者对事件做出对应的响应。

在中介者里包含了左侧游泳选手列表的构造。

然后就是处理界面按钮事件,因为我们使用了命令模式,所以可以将用户按钮都指定到一个事件句柄中,提供统一的处理接口。

private Mediate.KidList lsKids;
		private Mediate.CpyButton btCopy;
		private Mediate.ClrButton btClear;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;
		private Mediator med;
		public Form1() 		{
			InitializeComponent();
			init();
		}
		//-----
		private void init() {
			//set up mediator and pass in referencs to controls
			med = new Mediator (btCopy, btClear, lsKids, lsSelected);
			btCopy.setMediator (med);	//set mediator ref in each control
			btClear.setMediator (med);
			lsKids.setMediator (med);
			med.setText (txName);		//tell mediator about text box
			//create event handler for all command objects
			EventHandler evh = new EventHandler (clickHandler);
			btClear.Click += evh;
			btCopy.Click += evh;
			lsKids.SelectedIndexChanged += evh;
		}


public void clickHandler(object obj, EventArgs e) {
			Command comd = (Command)obj;	//get command object
			comd.Execute ();				//and execute command
		}

我们最好把各个控件的初始化操作委托给中介者,这样中介者可以初始化所有的需要控制的控件的状态:

//clear lists and set buttons to disabled
		public void clearClicked() {
			//disable buttons and clear list
			cpButton.Enabled = false;
			clrButton.Enabled = false;
			pkList.Items.Clear();
		}

中介者避免了类之间的纠缠不清,使得修改程序变得更加容易。可以轻松的添加其他的控件或者其他类,然而如果中介者需要服务的同事类太多的话,那么中介者无疑需要会包含非常多的处理代码,可能会让中介者这个类的可读性非常差,不易于理解。

这里我们可以看到,现在的例程中,我们包含了越来越多的设计模式,在这个中介者模式中,还使用了迭代器模式,命令模式两种模式,以后的例子中可能会经常需要更多的模式合作来完成,这在应用程序开发的过程中很常见,也更加符合OOP的思想。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
原型模式是一种创建型设计模式,其提供了一种复制已有对象的方法来生成新对象的能力,而不必通过实例化的方式来创建对象。原型模式是通过克隆(浅复制或深复制)已有对象来创建新对象的,从而可以避免对象创建时的复杂过程。 在C#中,可以通过实现ICloneable接口来实现原型模式。ICloneable接口定义了Clone方法,该方法用于复制当前对象并返回一个新对象。需要注意的是,Clone方法返回的是Object类型,需要进行强制类型转换才能得到复制后的对象。 以下是一个简单的示例代码: ```csharp public class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public object Clone() { return MemberwiseClone(); } } // 使用示例 var person1 = new Person { Name = "Tom", Age = 20 }; var person2 = (Person)person1.Clone(); person2.Name = "Jerry"; Console.WriteLine(person1.Name); // 输出 "Tom" Console.WriteLine(person2.Name); // 输出 "Jerry" ``` 在上面的示例代码中,实现了一个Person类,并实现了ICloneable接口中的Clone方法来实现原型模式。复制对象时,使用MemberwiseClone方法进行浅复制,即只复制值类型的字段和引用类型字段的引用,而不复制引用类型字段所引用的对象。在使用示例中,首先创建一个Person对象person1,然后通过Clone方法复制一个新的对象person2,修改person2的Name属性后,输出person1和person2的Name属性,可以看到person1的Name属性并没有改变,说明person2是一个全新的对象。 需要注意的是,如果要实现深复制,即复制引用类型字段所引用的对象,需要在Clone方法中手动将引用类型字段复制一份。另外,使用原型模式时,需要注意复制后的对象和原对象之间的关系,如果复制后的对象修改了原对象的状态,可能会对系统产生意想不到的影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值