Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件
一、多态
里氏替换原则:
任何能用基类的地方,可以用子类代替,反过来不行。子类能够在基类的基础上增加新的行为。面向对象设计的基本原则之一。
开放封闭原则:
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。关键是抽象,将一个功能的通用部分和实现细节部分清晰的分离开来。所有面向对象原则的核心。
虚方法实现多态:
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();
}
}
}
运行结果:

抽象实现多态:
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();
}
}
}
运行结果:

接口实现多态:
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();
}
}
}
运行结果:

二、委托
委托:将方法作为参数传递。
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);
}
}
}
运行结果:

三、事件
事件:对委托类型的变量的封装;在类的内部,不管你声明的事件是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 ("杰森");
}
}
}
运行结果:

四、匿名委托
匿名委托:也叫匿名方法,将代码块当做参数传递,因为不需要创建单独的方法,因此减少了实例化委托所需要的开销;
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参数。在实际问题中可能遇到的问题要比上面的代码复杂得多,在匿名方法中捕获变量就是难点之一。
运行结果:

五、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);
}
}
}
运行结果:

六、观察者模式
观察者模式:有时又被称为发布(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(); // 烧水,会自动调用注册过对象的方法
}
}
}
运行结果:

七、.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(); //烧水,会自动调用注册过对象的方法
}
}
}
}
运行结果:

文章参考自: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 框架中的委托和事件的更多相关文章
- C#委托总结-匿名方法&Lambda表达式
1,匿名方法 匿名方法可以在声明委托变量时初始化表达式,语法如下 之前写过这么一段代码: delegate void MyDel(string value); class Program { void ...
- 委托delegate 泛型委托action<> 返回值泛型委托Func<> 匿名方法 lambda表达式 的理解
1.使用简单委托 namespace 简单委托 { class Program { //委托方法签名 delegate void MyBookDel(int a); //定义委托 static MyB ...
- 【转载】C# 中的委托和事件(详解:简单易懂的讲解)
本文转载自http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html C# 中的委托和事件(详解) C# 中的委托和事件 委托和事件在 ...
- C# 中的委托和事件(详解)
C# 中的委托和事件 委托和事件在 .NET Framework 中的应用非常广泛,然而,较好地理解委托和事件对很多接触 C# 时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太 ...
- 【转载】C# 中的委托和事件(详解)
<div class="postbody"> <div id="cnblogs_post_body" class="blogpost ...
- 第3章 C#中的委托和事件
.NET框架中的委托和事件 using System; using System.Collections.Generic; using System.Linq; using System.Text; ...
- .NET之美——C#中的委托和事件(续)
C#中的委托和事件(续) 引言 如果你看过了 C#中的委托和事件 一文,我想你对委托和事件已经有了一个基本的认识.但那些远不是委托和事件的全部内容,还有很多的地方没有涉及.本文将讨论委托和事件一些更为 ...
- [转]C#中的委托和事件(续)
源码下载:http://www.tracefact.net/SourceCode/MoreDelegate.rar C#中的委托和事件(续) 引言 如果你看过了 C#中的委托和事件 一文,我想你对委托 ...
- 委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底
本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function&l ...
随机推荐
- jQuery的ajax详解
很多朋友都喜欢用JQ 而ajax更是JQ里必不可少的 下面为大家详细介绍一下JQ的ajax 首先 什么是ajax: AJAX = 异步 JavaScript 和 XML(Asynchronous Ja ...
- [vijosP1303]导弹拦截(最长上升子序列转LCS)
描述 某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭 ...
- 阶乘运算——ACM
大数阶乘 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 我们都知道如何计算一个数的阶乘,可是,如果这个数很大呢,我们该如何去计算它并输出它? 输入 输入一个整数 ...
- volatile关键字和synchronized关键字
volatile关键字: 可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性. synchron ...
- 深入浅出数据结构C语言版(5)——链表的操作
上一次我们从什么是表一直讲到了链表该怎么实现的想法上:http://www.cnblogs.com/mm93/p/6574912.html 而这一次我们就要实现所说的承诺,即实现链表应有的操作(至于游 ...
- nmap安装过程
nmap是一个网络扫描和主机检测工具. 功能:1.扫描目标主机开放的端口 2.扫描目标主机特定端口是否关闭 3.路由跟踪(到目标主机所经过的网络节点及其通过时间) 4.扫描一个网段下的所有IP 5.探 ...
- reactjs Uncaught TypeError: Cannot read property 'location' of undefined
reactjs Uncaught TypeError: Cannot read property 'location' of undefined reactjs 路由配置 怎么跳转 不成功 国内搜索引 ...
- c#XML操作类的方法总结
using System.Xml;using System.Data; namespace DotNet.Utilities{ /// <summary> /// Xml的操作 ...
- 什么是https
我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取.所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议. HTTPS简介 HTTPS其实是有两部分组成:HTTP + SSL ...
- MVC学习笔记1-MVC家族间的区别
ASP.NET下的MVC从原始的1.0走到2.0,再到3.0,现在走到4.0,也许明年5.0就问世了,先不管那些,那说说这些MVC在ASP.NET是如何变化发展的.对于.net编程人员来说可能会很熟悉 ...