深入浅出话窗体(一)——窗体事件模型(上)

news/2024/7/3 12:18:47

 深入浅出话窗体(一)

——窗体事件模型(上)

 作者:CSDN 刘铁猛

   

小序:
   
        工作中最大的挑战并不是那些Mission Impossible,而是你需要一边保持安静、平衡的心态以专注于工作,一边对抗公司体制、社会经济和人际环境对这种心态的破坏——这是对儿永远也解不开的矛盾。
     
   
正文:
   
        记得我在前面一篇文章里提到过:垒砖头垒多少年也成不了建筑师——仍然只会砌墙。同样,堆控件堆多少年也成不了程序员——仍然只会拼凑窗体。成为建筑师的关键在于学习建筑的结构,成为程序员的关键则在于了解程序的结构。今天,就让我们告别在窗体上堆控件,剖析一下窗体与窗体上控件关系——特别是事件的由来以及事件激发(Event Fire)与事件响应(Event Handling)之间的联系。
    
      
事件的由来
   
        传统的面向对象概念中是没有事件(Event)这个东西的,有的只是值域(Field)和方法(Method)。那么事件又是怎么来的呢?在传统的面向对象编程中,如果一个类想调用另一个类的方法,程序员有两种方法:
   
1.         在一个类的方法里通过另一个类的方法名进行直接调用,看上去会是这样:
    
#include  < iostream >

class  A
{
public :
         
void  Method()
         {
                   std::cout
<< " This is A. " << std::endl;
         }
};

class  B
{
public  :
         
void  Method(A arg)
         {
                   arg.Method();           
//  B与A紧密耦合在一起
         }
};

int  main( int  argc,  char   * argv[])
{
         A a;
         B b;
         b.Method(a);
         
return   0 ;
}
   
这样做的好处在于程序结构相当简单,但为这种“简单”所付出的代价就是——类与类之间耦合过于紧密,而使程序几乎不具有弹性和可伸缩性——于是有了另一种方法。
   
2.         在主调类里保有一个函数指针,并将这个指针指向一个函数,在这个函数里再调用其它类的方法。喔~~~你可能会问:“干吗不让这个指针直接指向其它类的方法,还要再借助一个中间函数做跳板呢?”呵呵,答案是:函数指针是不能指向类的成员函数的——《C++必知必会》里有详细解释,如果想再深挖一些,还可以看《深入探索C++对象模型》。这也就是我们常说的“间接引用”或者闻名遐迩的“回调函数”啦:D 大概的样子如下:
    
#include  < iostream >

class  A
{
public :
         
void  Method()
         {
                   std::cout
<< " This is A. " << std::endl;
         }
};

typedef 
void  ( * FunctionPointer)();           //  把函数指针定义成一种“类型”

class  B
{
public  :
         FunctionPointer funPointer;             
//  声明一个函数指针成员,必需与将被调用的方法类型保持一致
          void  Method()
         {
                   funPointer();                              
//  通过函数指针来调用目标方法,B类不与任何类明确耦合
         }
};

void  Function()                                             //  将被间接调用的函数
{
         A a;
         a.Method();
}

int  main( int  argc,  char   * argv[])
{
         B b;
         b.funPointer 
=  Function;                   //  成员指针与函数绑定,不存在类与类耦合的问题
         b.Method();                                         //  主调函数-->跳板函数-->被调函数
          return   0 ;
}
   
        这个模型真的非常不错!而且在C/C++世界广为流传。然而,时过境迁,随着.NET时代的来临和指针的不安全性(程序crash和内存泄漏之母:p)日益为人诟病,C#最终放弃了指针——确切地讲是“囚禁”了指针。虽然放弃了指针,但C#并没有放弃这种通过间接调用而降低类间耦合度的模型。微软是怎样做到的呢?原来,微软为.NET Framework添加了一种新的数据类型——委托(Delegate)。
   
        作为一种新的引用型数据类型,委托是一种类。既然是类,就没办法直接当作类的成员来使咯,所以能当作类成员来使用的只能是委托的实例(听起来真的是废话~~但很多初学的朋友就是在这里卡壳)。作为类的成员,委托的实例用起来的确很像函数指针,所以,我不得不再纠正一个流传甚广的谬误——有人说委托是函数指针的升级或委托是“超级函数指针”——实际上应该说委托的实例是函数指针的升级、委托的实例是“超级函数指针”。
    
        对于“超级函数指针”这个title,委托的实例是当之无愧的。它除了可以像函数指针那样“挂接”一个方法(函数被封装在类里之后就称之为“方法”了)外,功能大大超越了函数指针,这体现在:
  • 每个函数指针只能挂接一个目标函数,而委托的实例可以使用重载了的+=操作符肆意挂接N多方法,并美其名曰“多播委托”。
  • 函数指针具有指针的多种“通病”,而委托作为一种.NET托管类变得非常安全而驯服。
  • 函数指针不能指向类的成员函数,委托却可以指向类的成员函数——这倒不是委托的功劳,根本原因在于C#是完全面向对象的语言,所有函数都必须封装在类里变成成员函数(不再有散落在类之外的全局函数),如果委托不能指向成员函数,那委托还有什么用呢:p
        如果阁下想对委托探个究竟,我推荐你去阅读在下的掘文《深入浅出话委托》。
   
        OK,被C#粉饰一新的间接调用模型看上去会是这样:
    
// = <水之真谛> =出品, http://blog.csdn.net/FantasiaX
using  System;

delegate   void  MyDelegate();            //  声明委托这种类的方法与声明常规类不太一样
                                                             
//  它看上去更像是在声明“一个函数指针”,这也正是我上面说的混淆之源。
                                                             
//  从语义上讲,这句与上面C++代码中使用typedef把函数指针定义为一种类型是一致的

class  A
{
         
public   void  Method( string  name)
         {
                   Console.WriteLine(
" Hello, {0}! " , name);
         }
}

class  B
{
         
public  MyDelegate deleInstance;                   //  声明一个MyDelegate作为成员
          public   void  Method()
         {
                   
if  ( this .deleInstance  !=   null )                   //  安全检验,这是函数指针做不到的
                   {
                            
this .deleInstance();
                   }
         }
}

class  Program
{
         
static   void  Function()                                        //  作为跳板的函数,将被挂接在委托的实例上
         {
                   A a 
=   new  A();
                   a.Method(
" Tim " );
         }

         
static   void  Main( string [] args)
         {
                   B b 
=   new  B();
                   b.deleInstance 
+=   new  MyDelegate(Function);              //  创建实例,同时绑定。被绑定的函数返回值和参数类型必须与委托完全一致
                   b.Method();
         }
}
   
        你可能会问:干吗不把委托设计成与A的Method方法类型一致、再到B类中声明一个实例呢?这样不就可以抛开那个什么“当作跳板的函数”、直接调用A类实例的Method方法了吗?
   
        主意不错!但请你考虑这样一个问题:根据客户需求和业务逻辑的需要,A类可能具有几百个参数和返回值类型千奇百怪的方法,那么,你打算专门针对A类开发出几百种委托类型吗?就算你开发出来了,B类的设计人员就乐意为B类声明上如此一大摞专门针对A类的委托实例吗?如果创建B类的程序员接纳了针对A类的几百个委托,那么从针对C到Z这些类的委托呢——要不要也接纳进来?不接纳——除非A和B是两口子;接纳——那B类的代码长度估计不会低于央视大楼!况且,A类、B类以及其它类的设计人员可能根本就不在一个公司、不在一起工作,怎么可能“串通”起来做这种把类耦合在一起的浩大工程呢:p
    
        说了半天光说委托了,事件呢?其实,事件是微软对委托这个概念的进一步升级。就代码而言,事件仅仅是在委托的基础上向前迈进了一小步,但是从程序逻辑的角度上观察,事件却是在思想上向前迈进了一大步!为什么这样讲呢?且听下回分解。
    
TO BE CONTINUE

   

敬请关注:深入浅出话窗体(二)——窗体事件模型(下)

   

 

 

 

法律声明: 本文章受到知识产权法保护,任何单位或个人若需要转载此文,必需保证文章的完整性(未经作者许可的任何删节或改动将视为侵权行为)。若您需要转载,请务必注明文章出处为 CSDN 以保障网站的权益;请务必注明文章作者为 刘铁猛 http://blog.csdn.net/FantasiaX ),并向no_sound@hotmail.com 发送邮件,标明文章位置及用途。转载时必须将此法律声明一并转载。保护知识产权,人人有责,谢谢!




http://www.niftyadmin.cn/n/3658046.html

相关文章

NLP学习笔记(6)

我们希望把多个单词组成的短语同样在词向量的空间中找到对应的向量&#xff0c;当然你也可以在不同的空间中&#xff0c;但是如果在同一空间中是有好处的 &#xff0c;我可以利用该空间捕捉到短语与单词之间意思的相似度&#xff0c;比如the man on the snowboard 和 snowboard…

Programming C# 4th. Edition 中文/英文版对照阅读体验

Programming C# 4th Edition 中文版/英文版 对照阅读体验大概是耐心所至的缘故&#xff0c;我那几篇冠以“深入浅出C#”的文章在网络里被广泛转载——这当然是好事&#xff01;有更多的朋友通过我的介绍认识并喜欢上了C#这门可爱的语言。广泛转载的Side Effect就是我的邮箱时常…

C# 3.0 语言定义文档(微软官方版)正式发布!

C# 3.0 语言定义文档&#xff08;微软官方版&#xff09;正式发布如果想精通一门编程语言&#xff0c;你就需要像律师研究法律条款一样来研究这门语言的定义文档&#xff08;Language Specification&#xff0c;简称LangSpec&#xff09;。静悄悄地&#xff0c;C# 3.0语言定义文…

NLP学习笔记(8)

这节课的内容看得太快而且有点难&#xff0c;所以这里只是做一下记录&#xff0c;并不详细&#xff0c;作为一个内容的索引&#xff0c;事后需要自己取搜论文了解细节 这是一个想改进tree LSTM的模型 有人用基于字符的模型&#xff0c;也有人用基于单词的模型&#xff0c;还有…

进程编程1 – Unix环境高级编程7章读书笔记

Process Environment1 Process Termination进程的终止有些下面的方法&#xff1a;1. 从main函数return2. 调用exit&#xff1a;exit属于ISO C标准中定义的函数&#xff0c;会执行清理工作。包括关闭IO库中所有打开的文件流&#xff08;这会导致所有的文件buffer都被flu…

NLP学习笔记(7)

QA系统 希望一个QA系统能同时完成&#xff1a;回答问题、语义分析、词性标注三个任务有两个难点&#xff0c;一个是在这三个任务上各自表现效果好的模型不同&#xff0c;也就是说没有一个模型能同时很好地完成者三个任务&#xff1b;第二个是&#xff0c;在NLP中并没有发现在一…

WPF/E简介

WPF/E是微软下一代Web平台的核心技术&#xff0c;跨平台&#xff08;支持Windows和Mac&#xff09;&#xff0c;可以在多种浏览器中运行&#xff0c;会自动下载一个很小只有数M的客户端来运行WPF/E代码&#xff1a;WPF/E简介&#xff1a;http://msdn2.microsoft.com/en-us/libr…

NLP学习笔记(9)

目前深度学习的NLP存在一些局限性&#xff0c;比如通过自监督学习学得一个很好的模型真正理解语言的奥义&#xff08;需要大量的标注信息&#xff09; 第一个难题就是没有一个模型可以在所有的任务上取得好效果&#xff0c;之前提到的dynamic memory network就是为了来解决 这…