什么叫委托
委托就是只想一个函数的指针,使用委托可以让方法的引用封装在委托对象内,例如我是老板,需要以后我渴了的时候让小蜜给我打杯水,饿了就让他给我打水,门上安装个门铃,一按就让她给我打水和送吃的。这样我就可以将委托,将引用方法(打水)封装到委托对象(小蜜),以后我一按门铃,那么就是告诉我小我要喝水了,要吃东西了,小蜜就给我打水,至于门铃到底代表了什么,不管,我只是我说我又饿又渴,哈哈哈,我是不是太懒了。
委托实现
代码实现
其实学习.net的大家应该都知道有这么一个东西,那么我们就先看一下,这个家伙怎么用。例如一个简短的例子:
<span style="font-size:14px;">class Program
{
//定义一个委托类型的saySomething,参数是name,返回值是void
public delegate void saySomething(string name);
static void Main(string[] args)
{
//调用委托方法
saySomething ss = new saySomething(saySome.sayHelloToChinese);
ss += new saySomething(saySome.sayHelloToEnglish);
ss("孟海滨");
ss("平晓微");
ss.Invoke("孟海滨");
Console.ReadLine();
}
}
public class saySome
{
/// <summary>
/// 一个静态方法,简单的打印一句话
/// </summary>
/// <param name="name">一个姓名的参数</param>
public static void sayHelloToChinese(string name)
{
Console.WriteLine(name + ":你好");
}
/// <summary>
/// 一个静态方法,简单的打印一句话
/// </summary>
/// <param name="name">一个姓名的参数</param>
public static void sayHelloToEnglish(string name)
{
Console.WriteLine(name + ":hello");
}
}</span>
看一下运行结果
分析代码
1.public delegate void saySomething(string name); 这里申明了一个Delegate的类型,名称为saySomething,返回值是void,参数是string
2.为什么在最开始我说是一个函数的指针呢,大家看这行代码: ss += new saySomething(saySome.sayHelloToEnglish);他代表的就是指向saySome.sayHelloToEnglish这个函数。当然他和C++的函数指针还是有区别的,首先他可以搭载多个函数,而C++只能搭载一个,委托是安全的,面向对象的。
3.Delegate在搭载多个方法时,可以通过+=增加搭载的函数,也可以通过-=来去掉Delegate中的某个函数。
什么时候用
加入有这么一个需求,汽车开车,当开到一定的距离的时候,报警器报警,就是是一次开到太多了,现在是汽车是一个实体,而报警器也是一个实体,如果用委托,他们可以这样实现。大家先看代码:
汽车实体
<span style="font-size:14px;">public class Car
{
//定义委托类型,返回值是void,参数是int
public delegate void Notify(int value);
//定义一个事件
public event Notify notifiers;
//定义一个汽油的变量
private int petorl;
//汽油变量的set,get方法,在设置汽油数值的时候,判断汽油量是否充足
public int Petorl
{
get { return petorl; }
set {
petorl = value;
//如果汽油量少于10
if (petorl < 10)
{
//如果委托的对象不为空
if (notifiers != null)
{
//执行委托的放方法,委托的是什么?在这里不体现。
notifiers.Invoke(Petorl);
}
}
}
}
//构造函数,参数为汽油量(单位 :/L)
public Car(int pertorl) {
Petorl = pertorl;
}
//汽车启动的方法
public void run(int speed) {
//行走公里变量,单位(km/h)
int distance = 0;
//根据汽油量进行循环
while (Petorl > 0)
{
//加上500ms跑speed公里
Thread.Sleep(500);
//汽油逐渐减少
Petorl--;
//行走公里数增加
distance += speed;
Console.WriteLine("汽车当前跑的公里数是" + distance.ToString());
}
}
}</span>
报警器
<span style="font-size:14px;">public class Alerter
{
//构造函数,将“显示汽油量不足的信息”的引用添加到汽车的委托中
public Alerter(Car car)
{
//为car.notifiers 添加NotEnoughPetorl的引用
car.notifiers += new Car.Notify(NotEnoughPetorl);
}
//显示汽油量不足的信息
public void NotEnoughPetorl(int value)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("汽油量不足了" + value.ToString());
Console.ResetColor();
}
}</span>
客户端
<span style="font-size:14px;"> class Program
{
static void Main(string[] args)
{
//新建一个汽车,初始化的汽油量是15L
Car car = new Car(15);
//实例化报警器,将新建的气喘告诉他,让他添加一个油量不足的引用
new Alerter(car);
//奔跑吧汽车
car.run(120);
}
}</span>
看到上边的代码,有的朋友就会说了,我不用再汽车(Car)类里边用委托,直接实例化Alerter也可以呀,直接实例化,如果汽油量少于10,我就实例化一个报警器,然后去执行油量不足的提醒,也可以呀!
是的,确实可以,但是看看如果我用了委托,我再汽车中有关于警报器的说法吗,是不是解耦合了,假如改天我的汽车改成烧气 的了,怎么办,我需要新加一个方法(提示天然气不足的),这个本来没什么,有了新的需求,增加代码本来就是应该的,但是我如果实例化报警器的话,那么我就需要修改汽车的类了,如果是委托呢,我执行要在报警器的类中做一定的扩充就可以,以前的代码完全不用改。这样看的话,是不是感觉委托更加牛了呢。
Delegate和event
大家可能看到上边有那么两句代码
//定义委托类型,返回值是void,参数是int
public delegate void Notify(int value);
//定义一个事件
public event Notify notifiers;
这个事件是什么鬼,为什么我在第一个代码示例中就可以实现委托的功能,却要假一个事件,event与纯粹的delegate变量的最大区别就是增加了封装性。让delegate的触发权完全由对象控制,而delegate所委托的实际函数则由订阅者决定。event就是要执行一种“什么时候发生我说了算,发生的时候做什么事你说了算“的效果。而纯粹的delegate变量则在可访问的范围内同时给与指定委托函数与触发的权限。
invoke和BeginInvoke的区别
在第一个例子我用到了ss("孟海滨"),ss.invoke("孟海滨"),为什么要用invoke,他是个什么鬼invoke和BeginInvoke有详细的解释,大家可以看一下,这里我就不解释了。
委托小结
当我们在方法中需要函数指针等类似的东西的时候,当我们需要使用观察者模式的时候,当我们需要回掉函数的时候,可以考虑一下我们的委托,让我们降低类之间的耦合