也谈事件---Mom,Baby and you[一,二,三,四]

    朋友家有一个宝宝饿的时候总是喜欢哭闹,想尿尿的时候就开始哼哼唧唧或是手舞足蹈。
    如果大人够细致,就能分辨出宝宝的这种哭闹是饿了,这可以叫做饥饿性哭闹。
    同理,这种哼哼唧唧或是手舞足蹈也是在通知大人他想尿尿了。
    上面的这两个过程就是我要说的事件应用场景,咱们慢慢模拟这一场景:
    一、Mom忙碌的一天
    最简单的思路,当孩子哭闹和哼哼唧唧的时候,妈妈要有响应,那么我们可能要定义下面这几项:
    (1)事件委托,名称为:事件名+EventHandler。
    (2)事件成员,名称为前面的委托名去掉EventHandler。
    于是乎我们写出来下面的Baby:

  public   class  Baby
    {
        
// (1)定义事件委托
         public   delegate   void  CryEventHandler();
        
public   delegate   void  CroonEventHandler();
        
// (2)定义事件成员
         public   event  CryEventHandler Cry; // 饥饿性哭闹
         public   event  CroonEventHandler Croon; // 哼哼唧唧
         public   void  Action()
        {
            Console.WriteLine(
" Crydot.gifCrydot.gif " );
            
// 调用委托时进行null检查
             if  (Cry  !=   null )
            {
                Cry();
            }
            Console.WriteLine(
" Croondot.gifCroondot.gif " );
            
if  (Croon  !=   null )
            {
                Croon();
            }
        }
    }

    和下面的Mom:

       
public   class  Mom
    {
        
public   void  Action()
        {
            Baby baby 
=   new  Baby();
            baby.Cry 
+=   new  Baby.CryEventHandler(baby_Cry);
            baby.Croon 
+=   new  Baby.CroonEventHandler(baby_Croon);
            baby.Action();
        }
        
public   void  baby_Cry()
        {
            Console.WriteLine(
" 妈妈开始给baby准备食物dot.gif " );
        }
        
public   void  baby_Croon()
        {
            Console.WriteLine(
" 妈妈抱起baby嘘嘘dot.gif " );
        }
    }

 

 

    看看有什么问题,没曾想宝宝还有个小妹妹。
    YES!他们是双胞胎^_^。上面写的东西肯定是不满足了。
    因为我们分辨不出是哪个宝宝在哭闹或想嘘嘘。
    二、你和两个Baby
    前面说了,这个Mom有两个Baby。我们前面的实现太粗糙了。
    假设您现在正在这位Mom家里做客,这个时候Mom正在为您准备一顿大餐。
    照顾小孩的责任一下落在了您的头上。如果您和Mom一家很熟,Mom可能会告诉您
    “小强哭两声就是饿了。小丽哭一声就是饿了。
    小强哼哼两声就是要嘘嘘了,小丽哼哼一声就是要嘘嘘了”
    如果您和Mom一家不是很熟,Mom可能会告诉您
     “男孩哭两声就是饿了。女孩哭一声就是饿了。
    男孩哼哼两声就是要嘘嘘了,女孩哼哼一声就是要嘘嘘了”
    我想,您已经明白Mom的意思了。
    通过参考委托和事件的定义规范我们总结出这么几条:

     (1)事件委托名称应以 EventHandler 结尾。
     (2)事件委托应该有两个参数:
        第一个是 object 类型的 sender,代表发出事件通知的对象。
        第二个参数 e,应该是 EventArgs 或其派生类型。
    (3)事件参数类型,应从 EventArgs 继承,名称应以 EventArgs 结尾。应将所有想通过事件传达到外界的信息都放在事件参数 e 中。
     (4)应该为每个事件提供一个 protected  virtual的 OnXxxx 方法:方法名称为 On 加上事件的名称;只有一个事件参数 e;
        并在该方法中进行 null 判断。 在需要发出事件通知的地方,调用OnXxxx 方法。
     于是有了下面的Baby

     public   class  Baby2
    {
        
// Cry事件参数
         public   class  CryEventArgs : EventArgs
        {
            
private   string  _name  =   string .Empty;
            
private   string  _sex  =   string .Empty;
            
private   string  _voice  =   string .Empty; 
            
public   string  Name
            {
                
get  {  return  _name; }
                
set  { _name  =  value; }
            }
            
public   string  Sex
            {
                
get  {  return  _sex; }
                
set  { _sex  =  value; }
            }
            
public   string  Voice
            {
                
get  {  return  _voice; }
                
set  { _voice  =  value; }
            }
            
public  CryEventArgs( string  name, string  sex, string  voice)
            {
                _name 
=  name;
                _sex 
=  sex;
                _voice 
=  voice;
            }
        }
        
// Croon事件参数
         public   class  CroonEventArgs : EventArgs
        {
            
private   string  _name  =   string .Empty;
            
private   string  _sex  =   string .Empty;
            
private   string  _hmm  =   string .Empty;
            
public   string  Name
            {
                
get  {  return  _name; }
                
set  { _name  =  value; }
            }
            
public   string  Sex
            {
                
get  {  return  _sex; }
                
set  { _sex  =  value; }
            }
            
public   string  Hmm
            {
                
get  {  return  _hmm; }
                
set  { _hmm  =  value; }
            }
            
public  CroonEventArgs( string  name,  string  sex,  string  hmm)
            {
                _name 
=  name;
                _sex 
=  sex;
                _hmm 
=  hmm;
            }
        }
        
// 定义事件委托
         public   delegate   void  CryEventHandler( object  sender, CryEventArgs e);
        
public   delegate   void  CroonEventHandler( object  sender, CroonEventArgs e);
        
// 定义事件成员
         public   event  CryEventHandler Cry;
        
public   event  CroonEventHandler Croon;
        
// 受保护虚方法
         protected   virtual   void  OnCry(CryEventArgs e)
        {
            
if  (Cry  !=   null )
            {
                Cry(
this , e);
            }
        }
        
protected   virtual   void  OnCroon(CroonEventArgs e)
        {
            
if  (Croon  !=   null )
            {
                Croon(
this , e);
            }
        }
        
public   void  Action()
        {
            Console.WriteLine(
" Crydot.gifCrydot.gif " );
            OnCry(
new  CryEventArgs( " 小强 " , " 男孩 " , " 哭了两声 " ));
            Console.WriteLine(
" Croondot.gifCroondot.gif " );
            OnCroon(
new  CroonEventArgs( " 小强 " " 男孩 " " 哼哼了两声 " ));
        }
    }

 和下面的您:

 
public   class  You
    {
        
public   void  Action()
        {
            Baby2 baby 
=   new  Baby2();
            baby.Cry 
+=   new  Baby2.CryEventHandler(baby_Cry);
            baby.Croon 
+=   new  Baby2.CroonEventHandler(baby_Croon);
            baby.Action();
        }
        
private   void  baby_Cry( object  sender, Baby2.CryEventArgs e)
        {
            Console.WriteLine(
" 如果您是Mom的熟人,你会这样分析: "   +  e.Name  + e.Voice);
            Console.WriteLine(
" 您开始给baby准备食物dot.gif " );
            Console.WriteLine(
" 如果您不是Mom的熟人,你会这样分析: "   +  e.Sex  +  e.Voice);
            Console.WriteLine(
" 您开始给baby准备食物dot.gif " );
        }
        
private   void  baby_Croon( object  sender, Baby2.CroonEventArgs e)
        {
            Console.WriteLine(
" 如果您是Mom的熟人,你会这样分析: "   +  e.Name  + e.Hmm);
            Console.WriteLine(
" 您抱起baby嘘嘘dot.gif " );
            Console.WriteLine(
" 如果您不是Mom的熟人,你会这样分析: "   +  e.Sex  +  e.Hmm);
            Console.WriteLine(
" 您抱起baby嘘嘘dot.gif " );
        }
    }

故事到这里还没有结束,因为还会有下面的这种情况出现:
 三、Baby的无奈
    前面事件声明时,无论是否有事件处理程序挂接,它都会占用一定的内存空间。
    也就是说,小强哭闹以后,您给他吃东西了。他吃完东西又要嘘嘘了。
    但这个时候您也去嘘嘘了,您不在小强的身边,所以小强要嘘嘘的动作没有人来响应。
    使用下面的方法。在Baby类中将不创建Croon事件,就是说不让小强哼哼了,因为哼哼了也没用^_^
    所以我们提供类似属性的事件声明,事件声明使用add,remove访问器:
       public event [委托类型] [事件名称]
       {
          add { .... }
          remove { .... }
       }
   修改Baby类如下:

 
  public   class  Baby3
    {
        
// Cry事件参数
         public   class  CryEventArgs : EventArgs
        {
            
private   string  _name  =   string .Empty;
            
private   string  _sex  =   string .Empty;
            
private   string  _voice  =   string .Empty;
            
public   string  Name
            {
                
get  {  return  _name; }
                
set  { _name  =  value; }
            }
            
public   string  Sex
            {
                
get  {  return  _sex; }
                
set  { _sex  =  value; }
            }
            
public   string  Voice
            {
                
get  {  return  _voice; }
                
set  { _voice  =  value; }
            }
            
public  CryEventArgs( string  name,  string  sex,  string  voice)
            {
                _name 
=  name;
                _sex 
=  sex;
                _voice 
=  voice;
            }
        }
        
// Croon事件参数
         public   class  CroonEventArgs : EventArgs
        {
            
private   string  _name  =   string .Empty;
            
private   string  _sex  =   string .Empty;
            
private   string  _hmm  =   string .Empty;
            
public   string  Name
            {
                
get  {  return  _name; }
                
set  { _name  =  value; }
            }
            
public   string  Sex
            {
                
get  {  return  _sex; }
                
set  { _sex  =  value; }
            }
            
public   string  Hmm
            {
                
get  {  return  _hmm; }
                
set  { _hmm  =  value; }
            }
            
public  CroonEventArgs( string  name,  string  sex,  string  hmm)
            {
                _name 
=  name;
                _sex 
=  sex;
                _hmm 
=  hmm;
            }
        }
        
///   <summary>
        
///  定义事件委托
        
///   </summary>
        
///   <param name="sender"></param>
        
///   <param name="e"></param>
         public   delegate   void  CryEventHandler( object  sender, CryEventArgs e);
        
public   delegate   void  CroonEventHandler( object  sender, CroonEventArgs e);
        
//  为每种事件生成一个唯一的 object 作为键
         static   readonly   object  CryEventKey  =   new   object ();
        
static   readonly   object  CroonEventKey  =   new   object ();
        
// 存储事件处理程序
         protected  Dictionary < object , Delegate >  dict  =   new  Dictionary < object , Delegate > ();
        
// private Hashtable dict = new Hashtable();

        
// 向dict中添加事件
         protected   void  AddEventHandler( object  eventKey, Delegate handler)
        {
            
lock  ( this )
            {
                
if  ( ! dict.ContainsKey(eventKey))
                {
                    dict.Add(eventKey, handler);
                }
                
else
                {
                    dict[eventKey] 
=  handler;
                }
            }
        }
        
// 从dict中移除事件
         protected   void  RemoveEventHandler( object  eventKey)
        {
            
lock  ( this )
            {
                dict.Remove(eventKey);
            }
        }
        
// 从dict中获得事件
         protected  Delegate GetEventHandler( object  eventKey)
        {
            
if  ( ! dict.ContainsKey(eventKey))
                
return   null ;
            
else
                
return  (Delegate)dict[eventKey];
        }
        
// 定义事件成员
         public   event  CryEventHandler Cry
        {
            add { AddEventHandler(CryEventKey, value); }
            remove { RemoveEventHandler(CryEventKey); }
        }
        
public   event  CroonEventHandler Croon
        {
            add { AddEventHandler(CroonEventKey, value); }
            remove { RemoveEventHandler(CroonEventKey); }
        }
        
// 受保护虚方法
         protected   virtual   void  OnCry(CryEventArgs e)
        {
            CryEventHandler Cry 
=  (CryEventHandler)GetEventHandler(CryEventKey);
            
if  (Cry  !=   null )
            {
                Cry(
this , e);
            }
        }
        
protected   virtual   void  OnCroon(CroonEventArgs e)
        {
            CroonEventHandler Croon 
=  (CroonEventHandler)GetEventHandler(CroonEventKey);
            
if  (Croon  !=   null )
            {
                Croon(
this , e);
            }
        }
        
public   void  Action()
        {
            Console.WriteLine(
" Crydot.gifCrydot.gif " );
            OnCry(
new  CryEventArgs( " 小强 " " 男孩 " " 哭了两声 " ));
            Console.WriteLine(
" Croondot.gifCroondot.gif " );
            OnCroon(
new  CroonEventArgs( " 小强 " " 男孩 " " 哼哼了两声 " ));
        }
    }

实际上,我们只是用一个Dictionary 存储外部挂接上的事件处理程序。通过add和remove操作实现了事件的增加和删除。
简单的修改一下您,因为Baby Croon的时候您去嘘嘘了:

  public   class  You2
    {
        
public   void  Action()
        {
            Baby3 baby 
=   new  Baby3();
            baby.Cry 
+=   new  Baby3.CryEventHandler(baby_Cry);
            
// baby.Croon += new Baby3.CroonEventHandler(baby_Croon);
            baby.Action();
        }
        
private   void  baby_Cry( object  sender, Baby3.CryEventArgs e)
        {
            Console.WriteLine(
" 如果您是Mom的熟人,你会这样分析: "   +  e.Name  +  e.Voice);
            Console.WriteLine(
" 您开始给baby准备食物dot.gif " );
            Console.WriteLine(
" 如果您不是Mom的熟人,你会这样分析: "   +  e.Sex  +  e.Voice);
            Console.WriteLine(
" 您开始给baby准备食物dot.gif " );
        }
        
private   void  baby_Croon( object  sender, Baby3.CroonEventArgs e)
        {
            Console.WriteLine(
" 如果您是Mom的熟人,你会这样分析: "   +  e.Name  +  e.Hmm);
            Console.WriteLine(
" 您抱起baby嘘嘘dot.gif " );
            Console.WriteLine(
" 如果您不是Mom的熟人,你会这样分析: "   +  e.Sex  +  e.Hmm);
            Console.WriteLine(
" 您抱起baby嘘嘘dot.gif " );
        }
    }

四、接口实现
    再补充一个接口实现,思路是引入一个接口实现回调。

下面是Baby及接口实现:

  public   interface  IBaby
    {
        
void  Cry( string  name, string  sex, string  voice);
        
void  Croon( string  name, string  sex, string  hmm);
        
void  Other( string  name,  string  sex,  string  active);
    }
    
public   class  BabyAdapter : IBaby
    {
        
public   virtual   void  Cry( string  name,  string  sex,  string  voice) { }
        
public   virtual   void  Croon( string  name,  string  sex,  string  hmm) { }
        
public   virtual   void  Other( string  name,  string  sex,  string  active) { }
    }
    
public   class  Baby4
    {
        
private  BabyAdapter b  =   null ;
        
public  Baby4(BabyAdapter b)
        {
            
this .b  =  b;
        }
        
public   void  Action()
        {
            Console.WriteLine(
" Crydot.gifCrydot.gif " );
            b.Cry(
" 小强 " " 男孩 " " 哭了两声 " );
            Console.WriteLine(
" Croondot.gifCroondot.gif " );
            b.Croon(
" 小强 " " 男孩 " " 哼哼了两声 " );
        }
    }
上面代码Baby继承自adapter类,由外界传入adapter实例实现回调。
之所以使用adapter类而不是直接继承自接口是因为外界不必实现接口中的所有方法。
下面就是YOU:
  public   class  You3
    {
        
private   class  MyBaby:BabyAdapter
        {
            
public   override   void  Cry( string  name, string  sex, string  voice)
            {
                Console.WriteLine(
" 如果您是Mom的熟人,你会这样分析: "   +  name  +  voice);
                Console.WriteLine(
" 您开始给baby准备食物dot.gif " );
                Console.WriteLine(
" 如果您不是Mom的熟人,你会这样分析: "   +  sex  +  voice);
                Console.WriteLine(
" 您开始给baby准备食物dot.gif " );
            }
            
public   override   void  Croon( string  name,  string  sex,  string  hmm)
            {
                Console.WriteLine(
" 如果您是Mom的熟人,你会这样分析: "   +  name  +  hmm);
                Console.WriteLine(
" 您抱起baby嘘嘘dot.gif " );
                Console.WriteLine(
" 如果您不是Mom的熟人,你会这样分析: "   +  sex  +  hmm);
                Console.WriteLine(
" 您抱起baby嘘嘘dot.gif " );
            }
        }
        
public   void  Action()
        {
            Baby4 baby 
=   new  Baby4( new  MyBaby());
            baby.Action();
        }
    }
看一下结果:
2009080416525839.jpg

转载于:https://www.cnblogs.com/tenghoo/archive/2009/08/04/mom_baby_and_you.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值