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

时间:2022-04-26 18:16:46

一、多态

里氏替换原则:

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

开放封闭原则:

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

虚方法实现多态:

 using System;

 namespace Polymorphism
{
// 鸟类:父类
public class Bird
{
// 吃:虚方法
public virtual void Eat()
{
Console.WriteLine("我是一只小小鸟,我喜欢吃虫子~");
}
} // 喜鹊:子类
public class Magpie:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");
}
} // 老鹰:子类
public class Eagle:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只老鹰,我喜欢吃肉~");
}
} // 企鹅:子类
public class Penguin:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");
}
} class MainClass
{
public static void Main (string[] args)
{
//创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
Bird[] birds = {
new Bird(),
new Magpie(),
new Eagle(),
new Penguin()
};
//遍历一下birds数组
foreach (Bird bird in birds)
{
bird.Eat();
}
Console.ReadKey();
}
}
}

运行结果:

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

抽象实现多态:

 using System;

 namespace Polymorphism
{
// 鸟类:父类
public abstract class Bird
{
// 吃:虚方法
public abstract void Eat();
} // 喜鹊:子类
public class Magpie:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");
}
} // 老鹰:子类
public class Eagle:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只老鹰,我喜欢吃肉~");
}
} // 企鹅:子类
public class Penguin:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");
}
} class MainClass
{
public static void Main (string[] args)
{
//创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
Bird[] birds = {
new Magpie(),
new Eagle(),
new Penguin()
};
//遍历一下birds数组
foreach (Bird bird in birds)
{
bird.Eat();
}
Console.ReadKey();
}
}
}

运行结果:

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

接口实现多态:

 using System;

 namespace Polymorphism
{
//飞
public interface IFlyable
{
void Fly();
} // 鸟类:父类
public abstract class Bird
{
// 吃:虚方法
public abstract void Eat();
} // 喜鹊:子类
public class Magpie:Bird,IFlyable
{
public void Fly ()
{
Console.WriteLine ("我是一只喜鹊,我会飞~");
} // 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~");
}
} // 老鹰:子类
public class Eagle:Bird,IFlyable
{
public void Fly ()
{
Console.WriteLine ("我是一只老鹰,我可以飞~");
} // 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只老鹰,我喜欢吃肉~");
}
} // 企鹅:子类
public class Penguin:Bird
{
// 重写父类中Eat方法
public override void Eat()
{
Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~");
}
} class MainClass
{
public static void Main (string[] args)
{
//创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
Bird[] birds = {
new Magpie(),
new Eagle(),
new Penguin()
};
//遍历一下birds数组
foreach (Bird bird in birds)
{
bird.Eat();
} Console.WriteLine ("-----------------------"); //创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象
IFlyable[] flys = {
new Magpie(),
new Eagle()
};
//遍历一下flys数组
foreach (IFlyable fly in flys)
{
fly.Fly();
}
Console.ReadKey();
}
}
}

运行结果:

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

二、委托

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

 using System;

 namespace Delegate
{
public delegate void GreetingDelegate(string name); class People
{
public static void Speak(string name,GreetingDelegate _delegate)
{
_delegate (name);
}
}
class Language
{
public static void EnglishGreeting(string name)
{
Console.WriteLine ("Good Morning,"+name);
}
public static void ChineseGreeting(string name)
{
Console.WriteLine ("早上好,"+name);
}
} class MainClass
{
public static void Main (string[] args)
{
GreetingDelegate greetingDelegate;
greetingDelegate = Language.EnglishGreeting ;//委托第一次绑定时,须用“=”
People.Speak("Jason",greetingDelegate);
greetingDelegate -= Language.EnglishGreeting;
greetingDelegate += Language.ChineseGreeting ;
People.Speak("杰森",greetingDelegate);
}
}
}

运行结果:

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

三、事件

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

 using System;

 namespace Delegate
{
public delegate void GreetingDelegate(string name); class People
{
public static event GreetingDelegate greetingEvent;
public static void Speak(string name)
{
greetingEvent(name);
}
}
class Language
{
public static void EnglishGreeting(string name)
{
Console.WriteLine ("Good Morning,"+name);
}
public static void ChineseGreeting(string name)
{
Console.WriteLine ("早上好,"+name);
}
} class MainClass
{
public static void Main (string[] args)
{
People.greetingEvent += Language.EnglishGreeting;
People.Speak ("Jason");
People.greetingEvent -= Language.EnglishGreeting;
People.greetingEvent += Language.ChineseGreeting;
People.Speak ("杰森");
}
}
}

运行结果:

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

四、匿名委托

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

 using System;

 namespace Delegate
{
public delegate void GreetingDelegate(string name);
class People
{
public static void Speak(string name,GreetingDelegate _delegate)
{
_delegate (name);
}
} class MainClass
{
public static void Main (string[] args)
{
GreetingDelegate greetingDelegate = delegate(string name) {
Console.WriteLine ("Good Morning,"+name);
};
People.Speak ("Jason",greetingDelegate); GreetingDelegate greetingDelegate_1 = delegate(string name) {
Console.WriteLine ("早上好,"+name);
};
People.Speak ("杰森",greetingDelegate_1);
}
}
}

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

运行结果:

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

五、Lambda表达式

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

 using System;

 namespace Delegate
{
public delegate void GreetingDelegate(string name);
class People
{
public static void Speak(string name,GreetingDelegate _delegate)
{
_delegate (name);
}
} class MainClass
{
public static void Main (string[] args)
{
GreetingDelegate greetingDelegate = (string name) =>
Console.WriteLine ("Good Morning,"+name);
People.Speak ("Jason",greetingDelegate); GreetingDelegate greetingDelegate_1 = (string name) => {
Console.WriteLine ("早上好," + name);
};
People.Speak ("杰森",greetingDelegate_1);
}
}
}

运行结果:

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

六、观察者模式

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

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

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

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

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

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

 using System;

 namespace Delegate
{
public class Heater
{
private int temperature;
public delegate void BoilHandler(int param);
public event BoilHandler BoilEvent;
public void BoilWater()
{
for (int i = ; i <= ; i++)
{
temperature = i;
if (temperature > )
{
if (BoilEvent != null)
{
BoilEvent(temperature); // 调用所有注册对象的方法
}
}
}
}
}
public class Alarm
{
public void MakeAlert(int param)
{
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
}
public class Display
{
public static void ShowMsg(int param) // 静态方法
{
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
}
class Program
{
static void Main()
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.BoilEvent += alarm.MakeAlert; // 注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; // 给匿名对象注册方法
heater.BoilEvent += Display.ShowMsg; // 注册静态方法
heater.BoilWater(); // 烧水,会自动调用注册过对象的方法
}
}
}

运行结果:

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 所感兴趣的数据。

 using System;

 namespace Delegate
{
public class Heater
{
private int temperature;
public string type = "RealFire 001"; // 添加型号作为演示
public string area = "China Xian"; // 添加产地作为演示 public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e); public event BoiledEventHandler Boiled; // 声明事件 // 定义 BoiledEventArgs 类,传递给 Observer 所感兴趣的信息
public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
}
// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBoiled(BoiledEventArgs e)
{
if (Boiled != null)
{
Boiled(this, e); // 调用所有注册对象的方法
}
} public void BoilWater()
{
for (int i = ; i <= ; i++)
{
temperature = i;
if (temperature > )
{
// 建立BoiledEventArgs 对象。
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnBoiled(e); // 调用 OnBolied 方法
}
}
} public class Alarm
{
public void MakeAlert(Object sender, Heater.BoiledEventArgs e)
{
Heater heater = (Heater)sender; // 这里是不是很熟悉呢? // 访问 sender 中的公共字段
Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
}
}
public class Display
{
public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) // 静态方法
{
Heater heater = (Heater)sender;
Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
}
} class Program
{
static void Main()
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.Boiled += alarm.MakeAlert; //注册方法
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
heater.Boiled += Display.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
}

运行结果:

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

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

附加观察者模板:

 using System;
using System.Collections.Generic; namespace Delegate
{
/// <summary>
/// 抽象主题类
/// </summary>
public abstract class Subject
{
private IList<Observer> observers = new List<Observer>(); /// <summary>
/// 增加观察者
/// </summary>
/// <param name="observer"></param>
public void Attach(Observer observer)
{
observers.Add(observer);
} /// <summary>
/// 移除观察者
/// </summary>
/// <param name="observer"></param>
public void Detach(Observer observer)
{
observers.Remove(observer);
} /// <summary>
/// 向观察者(们)发出通知
/// </summary>
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
} /// <summary>
/// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
/// </summary>
public abstract class Observer
{
public abstract void Update();
} /// <summary>
/// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
/// </summary>
public class ConcreteSubject : Subject
{
private string subjectState; /// <summary>
/// 具体观察者的状态
/// </summary>
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
} /// <summary>
/// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调
/// </summary>
public class ConcreteObserver : Observer
{
private string observerState;
private string name;
private ConcreteSubject subject; /// <summary>
/// 具体观察者用一个具体主题来实现
/// </summary>
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
} public ConcreteObserver(ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
} /// <summary>
/// 实现抽象观察者中的更新操作
/// </summary>
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("The observer's state of {0} is {1}", name, observerState);
}
}
class Program
{
static void Main()
{
// 具体主题角色通常用具体自来来实现
ConcreteSubject subject = new ConcreteSubject (); subject.Attach (new ConcreteObserver (subject, "Observer A"));
subject.Attach (new ConcreteObserver (subject, "Observer B"));
subject.Attach (new ConcreteObserver (subject, "Observer C")); subject.SubjectState = "Ready";
subject.Notify (); Console.Read ();
}
}
}

运行结果:

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