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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

抽象实现多态:

 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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

接口实现多态:

 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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

 二、委托

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

 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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

三、事件

事件:对委托类型的变量的封装;在类的内部,不管你声明的事件是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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

四、匿名委托

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

 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参数。在实际问题中可能遇到的问题要比上面的代码复杂得多,在匿名方法中捕获变量就是难点之一。

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

五、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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

 六、观察者模式

观察者模式:有时又被称为发布(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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

七、.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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

文章参考自: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 }

运行结果:

Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件