zoukankan      html  css  js  c++  java
  • 也谈事件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(
    "CryCry");
                
    //调用委托时进行null检查
                if (Cry != null)
                {
                    Cry();
                }
                Console.WriteLine(
    "CroonCroon");
                
    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准备食物");
            }
            
    public void baby_Croon()
            {
                Console.WriteLine(
    "妈妈抱起baby嘘嘘");
            }
        }

        看看有什么问题,没曾想宝宝还有个小妹妹。
        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(
    "CryCry");
                OnCry(
    new CryEventArgs("小强","男孩","哭了两声"));
                Console.WriteLine(
    "CroonCroon");
                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准备食物");
                Console.WriteLine(
    "如果您不是Mom的熟人,你会这样分析:" + e.Sex + e.Voice);
                Console.WriteLine(
    "您开始给baby准备食物");
            }
            
    private void baby_Croon(object sender, Baby2.CroonEventArgs e)
            {
                Console.WriteLine(
    "如果您是Mom的熟人,你会这样分析:" + e.Name +e.Hmm);
                Console.WriteLine(
    "您抱起baby嘘嘘");
                Console.WriteLine(
    "如果您不是Mom的熟人,你会这样分析:" + e.Sex + e.Hmm);
                Console.WriteLine(
    "您抱起baby嘘嘘");
            }
        }

    故事到这里还没有结束,因为还会有下面的这种情况出现:
     三、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(
    "CryCry");
                OnCry(
    new CryEventArgs("小强""男孩""哭了两声"));
                Console.WriteLine(
    "CroonCroon");
                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准备食物");
                Console.WriteLine(
    "如果您不是Mom的熟人,你会这样分析:" + e.Sex + e.Voice);
                Console.WriteLine(
    "您开始给baby准备食物");
            }
            
    private void baby_Croon(object sender, Baby3.CroonEventArgs e)
            {
                Console.WriteLine(
    "如果您是Mom的熟人,你会这样分析:" + e.Name + e.Hmm);
                Console.WriteLine(
    "您抱起baby嘘嘘");
                Console.WriteLine(
    "如果您不是Mom的熟人,你会这样分析:" + e.Sex + e.Hmm);
                Console.WriteLine(
    "您抱起baby嘘嘘");
            }
        }

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

    下面是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(
    "CryCry");
                b.Cry(
    "小强""男孩""哭了两声");
                Console.WriteLine(
    "CroonCroon");
                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准备食物");
                    Console.WriteLine(
    "如果您不是Mom的熟人,你会这样分析:" + sex + voice);
                    Console.WriteLine(
    "您开始给baby准备食物");
                }
                
    public override void Croon(string name, string sex, string hmm)
                {
                    Console.WriteLine(
    "如果您是Mom的熟人,你会这样分析:" + name + hmm);
                    Console.WriteLine(
    "您抱起baby嘘嘘");
                    Console.WriteLine(
    "如果您不是Mom的熟人,你会这样分析:" + sex + hmm);
                    Console.WriteLine(
    "您抱起baby嘘嘘");
                }
            }
            
    public void Action()
            {
                Baby4 baby 
    = new Baby4(new MyBaby());
                baby.Action();
            }
        }
    看一下结果:

  • 相关阅读:
    warning C4018: “<”: 有符号/无符号不匹配
    安装VS提示系统找不到指定路径
    C#调用非托管dll
    指针转引用
    C语言文件操作fclose在NDK引起的BUG
    ADT开发AndroidManifest.xml file missing错误
    利用Visual GDB在Visual Studio中进行Android开发
    OpenCv实现两幅图像的拼接
    C++读取文件夹中所有的文件或者是特定后缀的文件
    WORD2007多级列表
  • 原文地址:https://www.cnblogs.com/tenghoo/p/mom_baby_and_you.html
Copyright © 2011-2022 走看看