zoukankan      html  css  js  c++  java
  • Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

    一、多态

    里氏替换原则:

    任何能用基类的地方,可以用子类代替,反过来不行。子类能够在基类的基础上增加新的行为。面向对象设计的基本原则之一。

    开放封闭原则:

    对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。关键是抽象,将一个功能的通用部分和实现细节部分清晰的分离开来。所有面向对象原则的核心。

    虚方法实现多态:

     1 using System;
     2 
     3 namespace Polymorphism
     4 {
     5     // 鸟类:父类
     6     public class Bird
     7     {
     8         // 吃:虚方法
     9         public virtual void Eat()
    10         {
    11             Console.WriteLine("我是一只小小鸟,我喜欢吃虫子~");
    12         }
    13     }
    14         
    15     // 喜鹊:子类
    16     public  class Magpie:Bird
    17     {
    18         // 重写父类中Eat方法
    19         public override void Eat()
    20         {
    21             Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");
    22         }
    23     }
    24         
    25     // 老鹰:子类
    26     public  class Eagle:Bird
    27     {
    28         // 重写父类中Eat方法
    29         public override void Eat()
    30         {
    31             Console.WriteLine("我是一只老鹰,我喜欢吃肉~");
    32         }
    33     }
    34         
    35     // 企鹅:子类
    36     public  class Penguin:Bird
    37     {
    38         // 重写父类中Eat方法
    39         public override void Eat()
    40         {
    41             Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");
    42         }
    43     }
    44 
    45     class MainClass
    46     {
    47         public static void Main (string[] args)
    48         {
    49             //创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
    50             Bird[] birds = { 
    51                 new Bird(),
    52                 new Magpie(),
    53                 new Eagle(),
    54                 new Penguin()
    55             };
    56             //遍历一下birds数组
    57             foreach (Bird bird in birds)
    58             {
    59                 bird.Eat();
    60             }
    61             Console.ReadKey();
    62         }
    63     }
    64 }

    运行结果:

    抽象实现多态:

     1 using System;
     2 
     3 namespace Polymorphism
     4 {
     5     // 鸟类:父类
     6     public abstract class Bird
     7     {
     8         // 吃:虚方法
     9         public abstract void Eat();
    10     }
    11         
    12     // 喜鹊:子类
    13     public  class Magpie:Bird
    14     {
    15         // 重写父类中Eat方法
    16         public override void Eat()
    17         {
    18             Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");
    19         }
    20     }
    21         
    22     // 老鹰:子类
    23     public  class Eagle:Bird
    24     {
    25         // 重写父类中Eat方法
    26         public override void Eat()
    27         {
    28             Console.WriteLine("我是一只老鹰,我喜欢吃肉~");
    29         }
    30     }
    31         
    32     // 企鹅:子类
    33     public  class Penguin:Bird
    34     {
    35         // 重写父类中Eat方法
    36         public override void Eat()
    37         {
    38             Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");
    39         }
    40     }
    41 
    42     class MainClass
    43     {
    44         public static void Main (string[] args)
    45         {
    46             //创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
    47             Bird[] birds = { 
    48                 new Magpie(),
    49                 new Eagle(),
    50                 new Penguin()
    51             };
    52             //遍历一下birds数组
    53             foreach (Bird bird in birds)
    54             {
    55                 bird.Eat();
    56             }
    57             Console.ReadKey();
    58         }
    59     }
    60 }

    运行结果:

    接口实现多态:

     1 using System;
     2 
     3 namespace Polymorphism
     4 {
     5     //
     6     public interface IFlyable
     7     {
     8         void Fly();
     9     }
    10 
    11     // 鸟类:父类
    12     public abstract class Bird
    13     {
    14         // 吃:虚方法
    15         public abstract void Eat();
    16     }
    17 
    18     // 喜鹊:子类
    19     public  class Magpie:Bird,IFlyable
    20     {
    21         public void Fly ()
    22         {
    23             Console.WriteLine ("我是一只喜鹊,我会飞~");
    24         }
    25 
    26         // 重写父类中Eat方法
    27         public override void Eat()
    28         {
    29             Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");
    30         }
    31     }
    32 
    33     // 老鹰:子类
    34     public  class Eagle:Bird,IFlyable
    35     {
    36         public void Fly ()
    37         {
    38             Console.WriteLine ("我是一只老鹰,我可以飞~");
    39         }
    40 
    41         // 重写父类中Eat方法
    42         public override void Eat()
    43         {
    44             Console.WriteLine("我是一只老鹰,我喜欢吃肉~");
    45         }
    46     }
    47 
    48     // 企鹅:子类
    49     public  class Penguin:Bird
    50     {
    51         // 重写父类中Eat方法
    52         public override void Eat()
    53         {
    54             Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");
    55         }
    56     }
    57 
    58     class MainClass
    59     {
    60         public static void Main (string[] args)
    61         {
    62             //创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
    63             Bird[] birds = { 
    64                 new Magpie(),
    65                 new Eagle(),
    66                 new Penguin()
    67             };
    68             //遍历一下birds数组
    69             foreach (Bird bird in birds)
    70             {
    71                 bird.Eat();
    72             }
    73 
    74             Console.WriteLine ("-----------------------");
    75 
    76             //创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象
    77             IFlyable[] flys = { 
    78                 new Magpie(),
    79                 new Eagle()
    80             };
    81             //遍历一下flys数组
    82             foreach (IFlyable fly in flys)
    83             {
    84                 fly.Fly();
    85             }
    86             Console.ReadKey();
    87         }
    88     }
    89 }

    运行结果:

     二、委托

    委托:将方法作为参数传递。

     1 using System;
     2 
     3 namespace Delegate
     4 {
     5     public delegate void GreetingDelegate(string name);
     6 
     7     class People
     8     {
     9         public static void Speak(string name,GreetingDelegate _delegate)
    10         {
    11             _delegate (name);
    12         }
    13     }
    14     class Language
    15     {
    16         public static void EnglishGreeting(string name)
    17         {
    18             Console.WriteLine ("Good Morning,"+name);
    19         }
    20         public static void ChineseGreeting(string name)
    21         {
    22             Console.WriteLine ("早上好,"+name);
    23         }
    24     }
    25 
    26     class MainClass
    27     {
    28         public static void Main (string[] args)
    29         {
    30             GreetingDelegate greetingDelegate;
    31             greetingDelegate = Language.EnglishGreeting ;//委托第一次绑定时,须用“=”
    32             People.Speak("Jason",greetingDelegate);
    33             greetingDelegate -= Language.EnglishGreeting;
    34             greetingDelegate += Language.ChineseGreeting ;
    35             People.Speak("杰森",greetingDelegate);
    36         }
    37     }
    38 }

    运行结果:

    三、事件

    事件:对委托类型的变量的封装;在类的内部,不管你声明的事件是public还是protected,它总是private的;在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。

     1 using System;
     2 
     3 namespace Delegate
     4 {
     5     public delegate void GreetingDelegate(string name);
     6 
     7     class People
     8     {
     9         public static event GreetingDelegate greetingEvent;
    10         public static void Speak(string name)
    11         {
    12             greetingEvent(name);
    13         }
    14     }
    15     class Language
    16     {
    17         public static void EnglishGreeting(string name)
    18         {
    19             Console.WriteLine ("Good Morning,"+name);
    20         }
    21         public static void ChineseGreeting(string name)
    22         {
    23             Console.WriteLine ("早上好,"+name);
    24         }
    25     }
    26 
    27     class MainClass
    28     {
    29         public static void Main (string[] args)
    30         {
    31             People.greetingEvent += Language.EnglishGreeting;
    32             People.Speak ("Jason");
    33             People.greetingEvent -= Language.EnglishGreeting;
    34             People.greetingEvent += Language.ChineseGreeting;
    35             People.Speak ("杰森");
    36         }
    37     }
    38 }

    运行结果:

    四、匿名委托

    匿名委托:也叫匿名方法,将代码块当做参数传递,因为不需要创建单独的方法,因此减少了实例化委托所需要的开销;

     1 using System;
     2 
     3 namespace Delegate
     4 {
     5     public delegate void GreetingDelegate(string name);
     6     class People
     7     {
     8         public static void Speak(string name,GreetingDelegate _delegate)
     9         {
    10             _delegate (name);
    11         }
    12     }
    13 
    14     class MainClass
    15     {
    16         public static void Main (string[] args)
    17         {
    18             GreetingDelegate greetingDelegate = delegate(string name) {
    19                 Console.WriteLine ("Good Morning,"+name);
    20             };
    21             People.Speak ("Jason",greetingDelegate);
    22 
    23             GreetingDelegate greetingDelegate_1 = delegate(string name) {
    24                 Console.WriteLine ("早上好,"+name);
    25             };
    26             People.Speak ("杰森",greetingDelegate_1);
    27         }
    28     }
    29 }

    在使用匿名方法时候,要注意不能使用跳转语句跳转到该匿名方法的外部,同样不能用跳转语句从外部跳转到匿名方法内部,匿名方法中不能访问不安全代码(unsafe),也不能访问在匿名方法外部使用的ref和out参数。在实际问题中可能遇到的问题要比上面的代码复杂得多,在匿名方法中捕获变量就是难点之一。

    运行结果:

    五、Lambda表达式

    Lambda表达式:比匿名委托代码更加简洁,运算符"()=>",

     1 using System;
     2 
     3 namespace Delegate
     4 {
     5     public delegate void GreetingDelegate(string name);
     6     class People
     7     {
     8         public static void Speak(string name,GreetingDelegate _delegate)
     9         {
    10             _delegate (name);
    11         }
    12     }
    13 
    14     class MainClass
    15     {
    16         public static void Main (string[] args)
    17         {
    18             GreetingDelegate greetingDelegate = (string name) => 
    19                 Console.WriteLine ("Good Morning,"+name);
    20             People.Speak ("Jason",greetingDelegate);
    21 
    22             GreetingDelegate greetingDelegate_1 = (string name) => {
    23                 Console.WriteLine ("早上好," + name);
    24             };
    25             People.Speak ("杰森",greetingDelegate_1);
    26         }
    27     }
    28 }

    运行结果:

     六、观察者模式

    观察者模式:有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式;观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

    实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式:

    1、观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。

    2、被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。

    3、观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

    实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

     1 using System;
     2 
     3 namespace Delegate
     4 {
     5     public class Heater
     6     {
     7         private int temperature;
     8         public delegate void BoilHandler(int param);
     9         public event BoilHandler BoilEvent;
    10         public void BoilWater()
    11         {
    12             for (int i = 0; i <= 100; i++)
    13             {
    14                 temperature = i;
    15                 if (temperature > 95)
    16                 {
    17                     if (BoilEvent != null)
    18                     { 
    19                         BoilEvent(temperature); // 调用所有注册对象的方法
    20                     }
    21                 }
    22             }
    23         }
    24     }
    25     public class Alarm
    26     {
    27         public void MakeAlert(int param)
    28         {
    29             Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
    30         }
    31     }
    32     public class Display
    33     {
    34         public static void ShowMsg(int param) // 静态方法
    35         { 
    36             Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
    37         }
    38     }
    39     class Program
    40     {
    41         static void Main()
    42         {
    43             Heater heater = new Heater();
    44             Alarm alarm = new Alarm();
    45             heater.BoilEvent += alarm.MakeAlert; // 注册方法
    46             heater.BoilEvent += (new Alarm()).MakeAlert; // 给匿名对象注册方法
    47             heater.BoilEvent += Display.ShowMsg; // 注册静态方法
    48             heater.BoilWater(); // 烧水,会自动调用注册过对象的方法
    49         }
    50     }
    51 }

    运行结果:

    七、.NET 框架中的委托和事件

    .NET Framework 的编码规范:

    1. 委托类型的名称都应该以 EventHandler 结束。

    2. 委托的原型定义:有一个void 返回值,并接受两个输入参数:一个Object 类型,一个EventArgs 类型(或继承自EventArgs)。

    3. 事件的命名为委托去掉 EventHandler 之后剩余的部分。

    4. 继承自 EventArgs 的类型应该以EventArgs 结尾。

    补充说明:

    1. 委托声明原型中的Object 类型的参数代表了Subject,也就是监视对象。

    2. EventArgs 对象包含了Observer 所感兴趣的数据。

     1 using System;
     2 
     3 namespace Delegate
     4 {
     5     public class Heater
     6     {
     7         private int temperature;
     8         public string type = "RealFire 001"; // 添加型号作为演示
     9         public string area = "China Xian"; // 添加产地作为演示
    10 
    11         public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
    12 
    13         public event BoiledEventHandler Boiled; // 声明事件
    14 
    15         // 定义 BoiledEventArgs 类,传递给 Observer 所感兴趣的信息
    16         public class BoiledEventArgs : EventArgs
    17         {
    18             public readonly int temperature;
    19             public BoiledEventArgs(int temperature)
    20             {
    21                 this.temperature = temperature;
    22             }
    23         }
    24         // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
    25         protected virtual void OnBoiled(BoiledEventArgs e)
    26         {
    27             if (Boiled != null)
    28             {
    29                 Boiled(this, e); // 调用所有注册对象的方法
    30             }
    31         }
    32 
    33         public void BoilWater()
    34         {
    35             for (int i = 0; i <= 100; i++)
    36             {
    37                 temperature = i;
    38                 if (temperature > 95)
    39                 {
    40                     // 建立BoiledEventArgs 对象。
    41                     BoiledEventArgs e = new BoiledEventArgs(temperature);
    42                     OnBoiled(e); // 调用 OnBolied 方法
    43                 }
    44             }
    45         }
    46 
    47         public class Alarm
    48         {
    49             public void MakeAlert(Object sender, Heater.BoiledEventArgs e)
    50             {
    51                 Heater heater = (Heater)sender; // 这里是不是很熟悉呢?
    52 
    53                 // 访问 sender 中的公共字段
    54                 Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
    55                 Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
    56             }
    57         }
    58         public class Display
    59         {
    60             public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) // 静态方法
    61             {
    62                 Heater heater = (Heater)sender;
    63                 Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
    64                 Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
    65             }
    66         }
    67 
    68         class Program
    69         {
    70             static void Main()
    71             {
    72                 Heater heater = new Heater();
    73                 Alarm alarm = new Alarm();
    74                 heater.Boiled += alarm.MakeAlert; //注册方法
    75                 heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
    76                 heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
    77                 heater.Boiled += Display.ShowMsg; //注册静态方法
    78                 heater.BoilWater(); //烧水,会自动调用注册过对象的方法
    79             }
    80         }
    81     }
    82 }

    运行结果:

    文章参考自:http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html

    附加观察者模板:

      1 using System;
      2 using System.Collections.Generic;
      3 
      4 namespace Delegate
      5 {
      6     /// <summary>
      7     /// 抽象主题类
      8     /// </summary>
      9     public abstract class Subject
     10     {
     11         private IList<Observer> observers = new List<Observer>();
     12 
     13         /// <summary>
     14         /// 增加观察者
     15         /// </summary>
     16         /// <param name="observer"></param>
     17         public void Attach(Observer observer)
     18         {
     19             observers.Add(observer);
     20         }
     21 
     22         /// <summary>
     23         /// 移除观察者
     24         /// </summary>
     25         /// <param name="observer"></param>
     26         public void Detach(Observer observer)
     27         {
     28             observers.Remove(observer);
     29         }
     30 
     31         /// <summary>
     32         /// 向观察者(们)发出通知
     33         /// </summary>
     34         public void Notify()
     35         {
     36             foreach (Observer o in observers)
     37             {
     38                 o.Update();
     39             }
     40         }
     41     }
     42 
     43     /// <summary>
     44     /// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
     45     /// </summary>
     46     public abstract class Observer
     47     {
     48         public abstract void Update();
     49     }
     50 
     51     /// <summary>
     52     /// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
     53     /// </summary>
     54     public class ConcreteSubject : Subject
     55     {
     56         private string subjectState;
     57 
     58         /// <summary>
     59         /// 具体观察者的状态
     60         /// </summary>
     61         public string SubjectState
     62         {
     63             get { return subjectState; }
     64             set { subjectState = value; }
     65         }
     66     }
     67 
     68     /// <summary>
     69     /// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调
     70     /// </summary>
     71     public class ConcreteObserver : Observer
     72     {
     73         private string observerState;
     74         private string name;
     75         private ConcreteSubject subject;
     76 
     77         /// <summary>
     78         /// 具体观察者用一个具体主题来实现
     79         /// </summary>
     80         public ConcreteSubject Subject
     81         {
     82             get { return subject; }
     83             set { subject = value; }
     84         }
     85 
     86         public ConcreteObserver(ConcreteSubject subject, string name)
     87         {
     88             this.subject = subject;
     89             this.name = name;
     90         }
     91 
     92         /// <summary>
     93         /// 实现抽象观察者中的更新操作
     94         /// </summary>
     95         public override void Update()
     96         {
     97             observerState = subject.SubjectState;
     98             Console.WriteLine("The observer's state of {0} is {1}", name, observerState);
     99         }
    100     }
    101         class Program
    102         {
    103         static void Main()
    104         {
    105             // 具体主题角色通常用具体自来来实现
    106             ConcreteSubject subject = new ConcreteSubject ();
    107 
    108             subject.Attach (new ConcreteObserver (subject, "Observer A"));
    109             subject.Attach (new ConcreteObserver (subject, "Observer B"));
    110             subject.Attach (new ConcreteObserver (subject, "Observer C"));
    111 
    112             subject.SubjectState = "Ready";
    113             subject.Notify ();
    114 
    115             Console.Read ();
    116         }
    117     }
    118 }

    运行结果:

    博客园Jason_C技术交流群

    扫描二维码加入qq群:623307256,共同探讨工作中遇到的Unity相关的问题!

  • 相关阅读:
    免费的视频、音频转文本
    Errors are values
    Codebase Refactoring (with help from Go)
    Golang中的坑二
    Cleaner, more elegant, and wrong(msdn blog)
    Cleaner, more elegant, and wrong(翻译)
    Cleaner, more elegant, and harder to recognize(翻译)
    vue控制父子组件渲染顺序
    computed 和 watch 组合使用,监听数据全局数据状态
    webstorm破解方法
  • 原文地址:https://www.cnblogs.com/Jason-c/p/6647541.html
Copyright © 2011-2022 走看看