• 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相关的问题!

  • 相关阅读:
    007_在线解析json工具
    009_python魔法函数
    008_python列表的传值与传址
    008_python内置语法
    007_Python中的__init__,__call__,__new__
    006_Python 异常处理
    匹配网络设计
    Bessel函数
    system generator 卷积编码器快速设计
    关于非稳恒的电流激励电场
  • 原文地址:https://www.cnblogs.com/Jason-c/p/6647541.html
Copyright © 2020-2023  润新知