一个初学者对事件和Observer模式的理解

本文从初学者的角度解释事件和Observer设计模式。事件被比喻为“出了点事情”,涉及事件触发者和受影响者。Observer模式,即发布-订阅模式,允许观察者在事件发生时立即作出反应。通过炒股的例子,展示了如何实现Observer模式,甲跟随炒股专家,乙跟随甲,事件作为信息传递者。附带了一个简单的炒股操作代码示例。

什么是事件?他和Observer设计模式有什么关系?

对于这两个概念专业书有正规的解释,我不想照抄概念。

我站在一个初学者的角度谈一下自己的理解,“事件”大白话就是“出了点事情”或者说是“发生了一些事情”,既然发生了事情,那肯定涉及到人或物,这件事是谁导致的,有谁受了影响,造成了什么后果。Observe模式又叫做发布-订阅模式(Publish/Subscribe),Observer中文意思是观察者,故名思意就是——某件事如果发生会对我有影响,那我就盯着这件事看他发生了立马调整自己的战略,或者想办法让自己能够在发生这件事的第一时间知道,立马做出反应,事件就是那个我们一直关注某件事一旦发生立马反应的一个信息传递者,它就像是个监视器一直偷偷地帮你看着某个角落一旦发生事情立马就通知你做出反应。我就拿炒股来举个例子,有人胆子很大去炒股,但是他自己又不太会看股市行情,恰巧他有个朋友炒股很厉害,于是他就跟着他的朋友一起炒,他朋友买啥股票他也立马买,他朋友出手股份他也立马出手,٩(๑❛ᴗ❛๑)۶听着像不像跟风炒股啊。

我以炒股写了个demo, 甲跟着炒股专家操作,乙跟着甲操作,事件起到了通知的作用,话不多说,上代码,可能一不小心写得有点多,也是为了尽量考虑周到,能够运行测试是否符合情形,嘻嘻 b( ̄▽ ̄)d

using System;
using System.Collections.Generic;

namespace InvestInStocks_improve
{
	public enum Sex{
		male,
		female
	}
	public enum StockType{
		京东方A=1,
		东华软件=2,
		大华股份=3,
	}
	class MainClass
	{
		public static void Main (string[] args)
		{
			//调整控制台窗口大小
			Console.WindowWidth = 110;
			Console.WindowHeight = 30;
			//输出程序标题
			Console.WriteLine ("Observer Pattern --InvestInStocks example !");

			// 创建三个Investor
			Investors fm = new Investors ("炒股专家", Sex.male,true);	//第三个参数表示是否被人跟随,true表示被人跟随,false表示不被人跟随,其实这个参数是为了区分是否被人跟随,无关紧要,这样可能还有点不符合OO
			Investors fol1 = new Investors ("\"跟着炒股专家操作的懵懂甲\"", Sex.male, false);
			Investors fol2 = new Investors ("\"跟着懵懂甲操作的菜鸟乙\"", Sex.female, false);

			//将甲和乙的跟随方法添加到目标人物的事件中
			fm.follow += fol1.FollowBuyOrSell;
			fol1.follow += fol2.FollowBuyOrSell;
			fol1.BeFollowed = true;
			//将三人放入数组以待轮流阐述,见EverySay()方法
			Investors[] investors = new Investors[]{ fm,fol1,fol2};

			string str;
			string[] info;
			//指令:比如说输入 "买 2 200" 就代表买入东华软件200
			Console.WriteLine ("现在由您替炒股专家做决策,指令格式为\n<买|卖> <1|2|3> <int>\t 1 == {0}, 2 == {1}, 3 == {2} , int 买入或卖出数量,是个整数\n比如输入\"买 2 100\"表示买入东华软件100",StockType.京东方A,StockType.东华软件,StockType.大华股份);
			//输入"exit"结束循环,指令输入不符合格式将结束程序或者报错!
			while ((str = Console.ReadLine ()) != "exit") {
			
				//调用String的方法按空格将str切分,得到一个字符串数组
				info = str.Trim().Split ();

				// 读取策略信息完成买股或者卖股操作
				switch (info[0]) {
				case "买":
					fm.BuyStock ((StockType)Enum.ToObject (typeof(StockType), int.Parse (info [1])), int.Parse (info [2]));
					EverySay (investors);
					break;
				case "卖":
					fm.SellStock ((StockType)Enum.ToObject (typeof(StockType), int.Parse (info [1])), int.Parse (info [2]));
					EverySay (investors);
					break;
				default:
					return;
				}

			}
				
		}

		//轮流阐述手头的股票及数额
		internal static void EverySay(Investors[] invs){
			Console.WriteLine ();
			foreach (Investors item in invs) {
				item.Say ();
				Console.WriteLine ();
			}
		}

	}

	//炒股者类
	public class Investors{
		private string name;
		private Sex sex;
		private Dictionary<string,int> stocks;	//Dictionary<TKey,TValue>类对象存储手头的股票信息

		/********重点********
		 * 使用System提供的EventHandler<TEventArgs>委托来定义一个follow事件
		 * EventHandler<TEventArgs>委托接收两个参数(object sender, TEventArgs e)
		 * System提供的EventArgs类不传递数据,而我们需要给事件传递炒股专家的操作信息,
		 * 所以我们从EventArgs派生了一个类FollowInfoArgs来存储数据(见最后一个类FollowInfoArgs)
		 */
		public event EventHandler<FollowInfoArgs> follow;

		//一些属性访问器
		public string Name{
			get{ return name;}
		}
		public string GetSex{
			get{ return sex.ToString ();}
		}
		protected Dictionary<string,int> StocksOnHand{
			get{ return stocks;}
		}
		public bool BeFollowed {
			get;
			set;
		}

		// *买股方法
		internal virtual void BuyStock(StockType sto,int num){
			int value = -1;
			/*
			 * Dictionary<TKey,TValue>中有个TryGetValue方法
			 * public bool TryGetValue (TKey key, out TValue value);
			 * 如果查到Key对应的值将返回true,同时以输出型参数的形式将这个值提供出来,
			 * 如果字典里没有这个key,返回false, value不改变
			 */
			try {
				if(stocks.TryGetValue (sto.ToString(), out value)){
					if (value <= 0)
						return;
					value += num;
					ChangeValueByKey(sto.ToString(),value);
				}
				else{
					stocks.Add (sto.ToString(), num);
				}
				Console.WriteLine ("{0}成功买入{1} -- {2}",name,sto,num);

				// *******买股成功,触发事件!
				if(BeFollowed && follow != null)
					follow (this, new FollowInfoArgs (sto, num, true));
				
			} catch (Exception ex) {
				Console.WriteLine (ex.Message);
			}
			
		}

		/*
		 * 卖股方法
		 * 思路与买股方法相同
		 */
		internal virtual void SellStock(StockType sto,int num){
			int value = -1;
			try {
				if(stocks.TryGetValue(sto.ToString(),out value))
				{
					if(value-num<0)
						Console.WriteLine ("{0}当前{1}不足{2}",name,sto,num);
					else if(value == num){
						stocks.Remove(sto.ToString());
						Console.WriteLine ("{0}成功卖出{1} -- {2},卖光了{1}",name,sto,num);
						if(BeFollowed&&follow!=null)
							follow (this, new FollowInfoArgs (sto, num, false));
					}else
					{
						value -= num;
						ChangeValueByKey(sto.ToString(),value);
						Console.WriteLine ("{0}成功卖出{1} -- {2}",name,sto,num);
						if(BeFollowed&&follow!=null)
							follow (this, new FollowInfoArgs (sto, num, false));
					}
				}
				else{
					Console.WriteLine ("{0}当前手头无{1}",name,sto);
				}
			} catch (Exception ex) {
				Console.WriteLine (ex.Message);
			}

		}


		//	待加入被跟随者对象的follow事件中的事件处理程序
		//	跟随方法,以FollowInfoArgs类对象中的 BuyOrSell 布尔型属性区分是买还是卖,Sto和Num获取股票种类和交易数量,调用买卖方法完成跟随动作
		public void FollowBuyOrSell(object obj,FollowInfoArgs info){
			Investors inv = obj as Investors;
			if (info.BuyOrSell) {
				Console.WriteLine ("{0}知道了{1}买了 {2}--{3},立马也这样买!",Name,inv.Name,info.Sto,info.Num);
				BuyStock (info.Sto, info.Num);
				return;
			}
			Console.WriteLine ("{0}知道了{1}卖了 {2}--{3},立马也这样卖!",Name,inv.Name,info.Sto,info.Num);
			SellStock (info.Sto, info.Num);
		}
		private void ChangeValueByKey(string sto,int value){
			stocks.Remove (sto);
			stocks.Add (sto, value);
		}
		internal void Say(){
			Console.WriteLine ("******我是"+name+", 我手头的股票有:");
			foreach (var item in stocks) {
				Console.WriteLine ("{0} -- {1}",item.Key,item.Value);
			}
			Console.WriteLine ("-----{0}的表述完毕-----",name);
		}

		public Investors(string name,Sex sex,bool befollowed){
			this.name = name;
			this.sex = sex;
			this.BeFollowed = befollowed;
			stocks = new Dictionary<string,int>();
		}
			
	}

	public class FollowInfoArgs:EventArgs{
		private StockType sto;	//	记录股票种类
		private int num;	//	记录交易数量
		private bool buyOrSell;	//区分买和卖
		public StockType Sto{
			get{ return sto;}
		}
		public int Num{
			get{ return num;}
		}
		public bool BuyOrSell{
			get{ return buyOrSell;}
		}
		public FollowInfoArgs(StockType sto,int num,bool befollowed){
			this.sto = sto;
			this.num = num;
			this.buyOrSell = befollowed;
		}

	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值