【DM】设计模式再回顾---委托

来源:互联网 发布:贷款那个软件好 编辑:程序博客网 时间:2024/06/05 05:45

  • 写在前面的
  • 委托
    • 概念
    • 分类
      • 假委托
      • 真委托
  • 总结

写在前面的

  • 由于专业课的关系很长时间没有在这里更新博客了~今天把最近在学习设计模式的过程中出现的一个比较基础的问题在这里再总结一下。看到题目也就知道了,那就是委托

  • 在平时的编程中,确切的说应该是我们在后期维护的时候,常常碰到这样一个问题“两个不相干的类,我们要产生联系,而且还需要达到‘开放封闭’的设计原则”,理解起来就是联这个联系两端的类“彼此之间虽不认识对方,但也需要根据某一座桥梁来实现应答机制”。有人会说用“观察者”不就好了?但是我们想想,观察者模式中的每一个类都是事先知道彼此存在的,每个类中内置了监视者,并且通过监视者来传达通知,所以严格意义上来讲并不符合“两个不相干的类实现联系”的这一要求。所以,委托就出现了。

委托

概念

  • 委托就是对函数的封装。这里我们姑且先用一句话来形容委托的含义,因为这句话非常好的体现在了代码上。

  • 其次,委托常常用在两个不经常(或者根本不)发生联系的类中。

  • 最后,委托经常伴随着事件的出现,事件是委托的一种特殊形式(而事件是观察者模式在.NET中实现方式,虽然在.NET中我们可以通过事件来解决这一问题,但并不意味着真正的“委托”就是观察者模式中“事件”的使用方式,所以这点和前文中“观察者模式并不是严格意义上的委托”的观点并不矛盾。)

分类

  • 由于对委托的字面意思有着不同的理解,所以在我们的日常使用中就赋予了“委托”两种不同的意义和用法,即“真委托”与“假委托”。

假“委托”

  • 什么是假委托?顾名思义,不符合委托概念的“委托”就是”假委托”。在“假委托”中,只是把“委托”单纯的理解为了把某件事情交给一个类去干,然后让两个类产生联系,仅此而已。这样就违背了我们概念中的第二条“不相干”的规定。

  • 在JAVA版的代码中是这样实现的:

public class Duck {    QuackBehavior quackBehavior;    public void performQuack()    {        //鸭子对象不亲自处理叫声行为,而是委托给了其他的类        quackBehavior.quack();    }}public interface QuackBehavior{    void Quack.....    ...    ...}

真“委托”

  • 而对于“真委托”而言,与前者的区别主要体现在机制的不同,后者借助了一套委托的声明与操作体系,来使得原本不相干的两个类通过这套委托机制来产生联系,从而继续维持两者之间“不相干”的状态。

  • 在C#中的代码实现是这样的:

/*首先我们来建立一个故事背景,猫来了,老鼠听到猫叫老鼠要跑。显然,猫不会事先通知老鼠“老子要来了,你快跑。”,所以这两个类之间是没有相互联系的*/public Cat{    private String name;    public Cat(string name)    {        this.name = name;    }    //声明委托 CatShoutEventHandler    public delegate void CatShoutEventHandler();    //声明事件 CatShout,它的事件类型是委托CatShoutEventHandler    public event CatShoutEventHandler CatShout;    public void Shout()    {        Console.WriteLine("喵,我是{0}",name);        if (CatShout!=null)        {        //声明当执行Shout()方法时,如果CatShout中有对象等级事件,则执行CatShout()            CatShout();        }    }}/*下面我们创建老鼠类*/public class Mouse{    private string name;    public Mouse(String name)    {        this.name = name;    }    public void Run()    {        Console.WriteLine("老猫来了,{0}快跑!",name);    }}/*其实写到这里大家就已经可以看出来了,我们并没有在这个老鼠类里面添加所谓的“监视者”,也就是表明了猫和老鼠之间并没有什么可以“调用”的联系,达到了我们定义中的第二条。*//*所以最关键的就是怎样让这两个类通过“委托机制”产生联系,下面我们看Main函数*/static void Mian(String[] args){    Cat cat = new Cat("Tom");    Mouse mouse1 = new Mouse("Jerry");    Mouse mosue2 = new Mouse("Jerry's Cousin");    /*表示将Mouse的Run方法通过实例化委托Cat.CatShoutEventHandler登记到Cat的事件CatShout当中。“+=”表示“add_CatShout”的意思,即cat.add_CatShout(new Cat.CatShoutEventHandler(mouse1.Run))*/    cat.CatShout += new Cat.CatShoutEventHandler(mouse1.Run);    cat.CatShout += new Cat.CatShoutEventHandler(mouse2.Run);    cat.Shout();    Console.Read();}
  • 最终的输出如下:
喵,我是Tom。老猫来了,Jerry快跑!老猫来了,Jerry's Cousin快跑!
  • 显然,猫和老鼠这两个“毫不相干”的两个类是通过Main函数中的委托机制来产生联系,而并不是在两者各自的类中添加“调用关系”,所以到头来还是维持着两者“不相干”的关系。

总结

  • 通过上面的对比,我们还可以非常明显的看出,在使用了“委托”后,客户端中的代码量明显要比“在两个类中产生关联,然后在Main函数中调用”的量要小很多,我们调用老鼠跑的方法只是将其登记在了委托当中,对猫叫的处理也只是登记在了委托中,所以非常好的体现了委托对函数的封装,这一关键性的概念

  • 还有一个遗留的问题便是我们在文章中举例所用到的“CatShoutEventHandler”是一个没有参数的方法,那么如果添加参数呢?我们会在用到它的时候再举例说明出来。

  • 总之,我个人认为“委托”的使用在后续维护的过程中会大大方便我们对原始类的“关联”修改,但是还不破坏原有结构,即维护了“开放封闭”原则,也避免了新的修改带来的一些不可预料的问题,理解委托的机制会非常有效的帮助我们提高对代码的维护效率。

4 0
原创粉丝点击