面向对象_9_委托

Posted yigegaozhongsheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象_9_委托相关的知识,希望对你有一定的参考价值。

 

委托

委托这个词的意思,是指把自已的事件托付给别人或者别的机构来办理。比如:委托律师、委托中介、委托保姆。

委托不一定只是被委托一件事,而是有可能同时被很多人委托很多事件。

 class Program
    {
            static void Main(string[] args)
            {
                夫人 老妈 = new 夫人();
                老爷 老爸 = new 老爷();
                少爷 小明 = new 少爷();
                大小姐 小红 = new 大小姐();
                保姆 翠花 = new 保姆(老妈.做饭);
                翠花 += 老爸.洗碗;
                翠花 += 小明.洗衣服;
                翠花 += 小红.溜狗;
                翠花 += 老妈.做饭;
                翠花();
            }
    }
        public delegate void 保姆();
        class 老爷
        {
            public void 洗碗()
            {
                Console.WriteLine("洗洗碗");
            }
        }
        class 夫人
        {
            public void 做饭()
            {
                Console.WriteLine("做做饭");
            }
        }
        class 少爷
        {
            public void 洗衣服()
            {
                Console.WriteLine("洗洗衣");
            }
        }
        class 大小姐
        {
            public void 溜狗()
            {
                Console.WriteLine("溜溜狗");
            }
        }

从上例中我们可以看出,委托的作用就是让由另一个对象执行的方法,去交给一个委托来执行。

语法:

声明委托需要使用delegate关键字:

[访问修饰符] delegate 返回类型 委托名(参数列表);

比如:

public delegate int MyDelegate(int i, int j);

其中,委托中声明的返回类型和参数列表的意思是指,该委托只能接受与它传入参数和返回类型一致的方法。

比如上例中的委托,只能接受传入两个int并返回一个int参数的方法。

 方法的形态:

在委托中将方法名后面的括号去掉,让它像变量一样可以进行赋值和加减运算的形态,我们自封其为“方法变量形态”。

 当方法具有括号,可以被执行的形态,我们自封其为”方法的函数形态”。

委托与其中的方法的参数类型必须一致

static void Main(string[] args)
    {
        Test class1 = new Test();
        MyDelegate dlgt1;
        //委托需要实例化,但是它实例化的时候可以不使用构造函数的形式。
        dlgt1 = class1.Func2;
        //直接向委托之中"赋值"(方法的变量形态),因为传入与返回参数的类型和个数一致
        //dlgt1 += class1.Func1; //报错,返回类型与委托不一致
        //dlgt1 += class1.Func3; //报错,传入参数的个数不一致
        dlgt1 += Test.Func4; //只要类型一致,静态方法也可以加入委托
        dlgt1(1, 2); //在委托的括号中传入方法所需要的参数
    }
    public delegate int MyDelegate(int i, int j);
    class Test
    {
        public void Func1(int i, int j) { }
        public int Func2(int n, int j) { Console.WriteLine(n + j); return n + j; }
        public int Func3(int n) { return n; }
        public static int Func4(int k, int age) { return age; }
    }

委托的实例化

委托与类的级别是一致的,它可以声明在类的外面。

如果要使用委托的话,需要首先创建委托的实例。

实例化委托有两种写法

[访问修饰符] 委托名 委托实例的名称 = new 委托名(方法);

其中构造函数中必须得存在一个(签名一致的变量形态的)方法,不能为空。

[访问修饰符] 委托名 委托实例的名称;

委托实例的名称 = 方法;

其中的方法是变量形态的

委托的执行

委托在”变量形态”之下可以对它包含的方法进行加减,但是当委托需要执行它所包含的方法时,就需要转换为“函数形态”了,就是在委托实例的后面加上圆括号。

委托中方法增减

加法就相当于是向委托的“任务清单”中添加一个方法作为“要被执行的任务”,减法就是从“任务清单”中删除一条任务。

 示例:

 public delegate int MyDelegate(int a);
    public delegate void EH();
    class Program
    {
        public int F1(int i) { Console.WriteLine("调用实例方法F1"); return i; }
        public static int F2(int i) { Console.WriteLine("调用静态方法F2"); return i; }
        static void Main(string[] args)
        {
            Program p = new Program();
            //以下是几种向委托的实例赋值的方法:
            MyDelegate d1 = new MyDelegate(p.F1);
            MyDelegate d2 = Program.F2;
            MyDelegate d3 = d2; //用另外一个委托的实例来赋值
            d3 += p.F1; //可以加方法
            d3 += d1; //还可以加同类的委托
            d3 -= d1; //减去了同类型的委托
            MyDelegate d4 = d1 + d2 + d3;
            //就好像几个"任务清单"合并为了一个"任务清单"
            MyDelegate d5 = d3 - d2;
            MyDelegate[] dd = new MyDelegate[2] { d1, d2 };
            dd[0](11);
            dd[1](22);
        }
    }

委托的注意事项

委托隶属于System.Delagate,但是不能从特殊类型Delagate中继承。

执行委托的时候,所执行的是委托的实例,而且执行时必须加括号。

委托不能添加static关键字

委托中的方法的执行顺序就是添加的顺序。

委托可以定义类之外,也可以定义在类之内,但是不能定义在方法内。

 小练习

1、假设有一家房产中介(委托),去带客户看房(客户.看房() 委托给中介带他去执行)。客户A(对象),和客户B(对象),(房间是一个类)分别去看房间1(显示面积、几室几厅等信息)、房间2、房间3、房间4。期间客户B,突然有事,决定不再按照原计划去看后面的两个房间(也就是房间3、房间4)。

2、定义委托并实例化四个实例wt1、wt2、wt3、wt4,签名都是返回一个string,传入一个int。这四个委托中各包含一个相应的方法,将他们放入一个数组,并且用循环来依次执行这四个委托。

3、定义委托并实例化四个实例gt1、gt2、gt3、gt4,签名都是没有传入参数和返回值。gt1、gt2各包含一个相应的方法,gt3是gt1和gt2相加,gt4是前三者相加。接受用户键盘输入,如果输入的是1、2、3、4中的某个值,则执行对应的委托,否则提示用户输入错误。

4、定义一个委托ct,和五个签名相匹配的方法,无限循环接受用户键盘输入,如果输入的是1、2、3、4、5中的某个值,则将对应的方法加入委托,然后执行(委托中一次只能执行一个方法),否则提示用户输入错误。

5、用委托的形式来设计一个聊天机器人,机器人有sayHello(),sayName(),sayAge()三个方法,然后无限循环接受用户键盘输入的话,如果话语中包括“你好”,则向委托中加入sayHello()方法并执行,如果包括“名字”则加入sayName()并执行,包括"几岁"或"多少岁"执行sayAge()。

事件

事件就是指由用户的某种操作或代码的某种状态所触发的一系列程序的执行。

事件的原理,是建立在委托的基础之上的。

事件Event的语法与用法

[访问修饰符] event 委托类型 事件实例名称

事件实例名称 = 方法;

 或

[访问修饰符] event 委托类型 事件实例名称 = new 委托类型(方法);

如果只看针对方法的增减和存储、执行等操作的话,事件与委托在使用时是一样的。

比如:

public delegate void ForEvent(int i);
    public event ForEvent event1 = new ForEvent(Form1.showInt);
    event1 += Form1.showInt22;
event1(12);
    public static void showInt(int j)
    {
        MessageBox.Show(j.ToString());
    }
    public static void showInt22(int j)
    {
        MessageBox.Show("22222");
    }

事件机制

事件是实现上它是一种机制,而不是一个单一的语法,它是通过三个类的相互协作而完成的,一个是被监视的类,一个是监视的类,还有一个类是用来判断是否需要执行事件的类。

事件定义与执行的几个步骤

事件是类和对象向外界发出的消息,事件的执行是通过委托的方式,来调用我们准备好的方法。如果要让代码响应用某个事件并针对对该事件执行我们指定的方法,需要以下几下步骤:

声明事件的委托类型。

声明事件。

添加要被事件所触发的方法。

添加事件的处理程序。(响应事件的方法)

将指定的事件处理程序绑定到事件上,这个步骤称为”订阅事件”

通过用户执行某种操作或软件运行过程中某种状态的改变,触发事件(调用事件触发方法)。

通过事件委托的回调,执行我们需要的事件处理程序。

事件示例,当员工上班打游戏时触发事件:

class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("场景开始...");
            员工类 小张 = new 员工类("小张");
            经理类 王经理 = new 经理类("王经理");
            //绑定事件
            小张.ep += 王经理.人赃俱获;
            Random rand = new Random();
            while (小张.Money > 0)
            {
                if (rand.Next(6) == 5)
                    小张.play();
                else
                    Console.WriteLine("...正常上班工作中...");
            }
            Console.WriteLine("工作被丢了,没有饭碗了。这是真的Game over了");
        }
    }
    public delegate void 游戏控制(员工类 员工);
    public class 员工类
    {
        public event 游戏控制 ep;
        public string Name { get; set; }
        public int Money { get; set; }
        public 员工类() { }
        public 员工类(string name)
        {
            this.Name = name;
            this.Money = 1500;
        }
        public void play()
        {
            Console.WriteLine(Name + ":开始玩游戏了...");
            Console.WriteLine(Name + ":我打遍天下无敌手,哇哈哈。。");
            if (this.ep != null) //判断当前事件中是否包含方法。
                ep(this);
        }
    }
    public class 经理类
    {
        public string Name { get; set; }
        public 经理类(string name)
        {
            this.Name = name;
        }
        public void 人赃俱获(员工类 xz)
        {
            Console.WriteLine(this.Name + ":竟敢在上班时间玩游戏。罚款,重罚。");
            Console.WriteLine(xz.Name + "这个月还有" + xz.Money + "元,开始扣钱");
            xz.Money -= 300;
            Console.WriteLine("这个月还有" + xz.Money + "");
        }
    }

示例2:

class 公司场景
    {
        static void Main()
        {
            //创建事件源对象
            员工类 es = new 员工类();
            es.Money = 2000;
            //创建监视者对象
            视察者 eld = new 视察者();
            //订阅事件
            eld.颁布监视制度(es);
            Console.WriteLine("输入一个字符,再按回车键");
            string s = Console.ReadLine();
            //得到字符串的第一个字符,作为事件参数传入事件中
            es.被看到了(s.ToCharArray()[0]);
            //取消订阅事件
            eld.取消监视制度(es);
            //引发事件
            Console.WriteLine("输入一个字符,再按回车键");
            s = Console.ReadLine();
            //得到字符串的第一个字符,作为事件参数传入事件中
            es.被看到了(s.ToCharArray()[0]);
        }
    }
    //发布事件的类
    public class 员工类
    {
        //定义一个内部类,事件参数类,是EventArgs的子类
        public class TestEventArgs : EventArgs
        {
            public readonly char KeyToRaiseEvent;
            public TestEventArgs(char KeyToRaiseEvent)
            {
                this.KeyToRaiseEvent = KeyToRaiseEvent;
            }
        }
        public float Money { get; set; } //本月工资
        //定义委托,其中sender是触发事件的对象, e是向事件中传递的参数

        public delegate void 游戏控制委托(object sender, TestEventArgs e);
        //用event关键字声明事件对象
        public event 游戏控制委托 员工玩游戏事件;
        //触发事件的方法
        protected virtual void On当被抓住(TestEventArgs e)
        {
            if (员工玩游戏事件 != null)//如果事件不为空就执行该事件
                员工玩游戏事件(this, e);
        }
        //引发事件
        public void 被看到了(char keyToRaiseEvent)
        {
            //实例化事件参数内部类
            TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
            On当被抓住(e);
        }
    }
    //监听事件的类
    //它提供了事件处理程序,并实现了事件处理程序和事件对象的绑定
    public class 视察者
    {
        //定义处理事件的方法,他与声明事件的delegate具有相同的参数与返回值。 就是事件触发时所要执行的操作
        public void 处理并罚款(object sender, 员工类.TestEventArgs e)
        {
            //如果输入的是Y,就说明打游戏被抓到了,否则就说明没有玩游戏,或者没有被抓到
            员工类 某员工 = (员工类)sender;
            if (e.KeyToRaiseEvent == Y)
            {
                某员工.Money -= 500;
                Console.WriteLine("工资扣除500元,还剩下{0}元", 某员工.Money);
            }
            else
                Console.WriteLine("正常工作中");
        }
        //订阅事件
        public void 颁布监视制度(员工类 eventSourec)
        {
            eventSourec.员工玩游戏事件 += new 员工类.游戏控制委托(处理并罚款);
        }
        //取消订阅事件
        public void 取消监视制度(员工类 eventSourec)
        {
            eventSourec.员工玩游戏事件 -= new 员工类.游戏控制委托(处理并罚款);
        }
    }

以上是关于面向对象_9_委托的主要内容,如果未能解决你的问题,请参考以下文章

js_面向对象设计和行为委托设计模式

python之路之前没搞明白4面向对象(封装)

9 面向对象(类) --python

9.1.面向对象:静态方法类方法属性方法

学习 Python 之 面向对象

学习 Python 之 面向对象