http://expert.csdn.net/Expert/topic/2198/2198971.xml上面那个帖子里,ZyxIp (绝望中...) 指出他可以说抵制全局变量。他的阐述:象第二个问题,我现在编程中就不用全局变量,也不会在一个窗体中直接去读写另一个窗体的控件都是通过给窗体添加属性来实现。用了全局变量就破坏了整个系统的完整,整个系统都应是一个类。  刚开始学DELPHI的时候认为实现的最小单位是过程和函数,也只是想知道这个控件如何用那个控件如何用,学了一段时间也会定义类,也知道控件只不过是看得到的类,但我觉得更深刻理解OOP是一天在看别人的代码,突然发现他给窗体添加了 Published ,加了一个属性,以前自己也这样做过,但一直好象不将窗体做为一个类,只是将它当做一个放控件的平台桌面。从那以后我就不用全局变量了,每新添加一个窗体时将DELPHI自动添加的 var form1:Tform;都删除掉。  我的程序也不用数据绑定,如数据库支持存储过程,则在程序中不会出现语句,只是调用存储过程,我的程序只有一个ADOConnection ,很少有ADOQuer放在界面上,都是动态创建后将数据读到StringGrid或ListView中后就释放。我的玩笑回答:唉,怎么这样呢?有必要吗?就在全局变量上较真。那是你的理解,何不开个帖子咱们来讨论一下全局变量的优势呢?别一棍子打死,封装自有封装的好处。封装背后还有其他的东西。另外,类似:var 
  form1: TForm;删除它又咋?不删除又咋?我不删除,就留着。但是你不说,嘿嘿,尽管定义了,我发现我几乎不用这个form1,form2。好像用得很少。如果有全局变量,我会弄到一个文件里面。如果不是类的出现,全局变量就是面向过程编程的一个重要环节。
他的玩笑回答:  嘿嘿,不过要是让我管理项目,我就是不让用全局变量。var form1: TForm;也一定要定义到打开它的过程中去,自动添加的一定要删除。
不知道这样做 reallike(认真学习Cpp用Cpp考虑delphi) 老兄会不会和我打架,气的吐血。
  我的一次阐述:哦,这就算我对第一个问题的回答吧。尽管使用了申哥的代码。如果我应聘我就会写我的代码的。生活中有关多态的例子太多了。好,回答第二个问题。全局变量,顾名思义,谁都可以用它。任何人都可以访问。尽管有悖于面向对象里面的数据封装。面向对象可以用类来描述任何事物。不过也是需要的。据个例子,(胡闹的,玩玩而已嘻嘻。):T中国人 = class
protected
  身份证: 证件类型;
  户口本: 证件类型;
  //有点简单。可以扩充
end;T我 = class(T中国人)
private
  工资: 货币;
  伞: 雨具; //我突出说这个伞
  procedure 私生活;
public
  procedure 吃饭;
  procedure 睡觉;
end;T你 = class(T中国人)
private
  工资: 货币;
  procedure 你的私生活;
  //而你没有伞
public
  procedure 吃饭;
  procedure 睡觉;
end;如果有个procedure 下雨();出现你咋办?你没有伞啊,我做到了未雨绸缪了。你会骂:谁闲着没事天天拿着把伞,你小子就是一傻逼。:〉所以,还不如定义一个全局变量  var
  伞: 雨具;也就是说,这个是公共雨伞,是在大厦前,商场前,或者其他地方,不过你用了记得要归还。如果不归还…… 那你私人占有,那就另说了。其实数据封装就是如此,防止不规范,不道德,不正确的访问。如果这些都排出,并不是一些重要数据,你设立成全局变量会减少一些工作量。比如说伞这个,如果人人都做到规范的使用,我也不会天天带伞满大街的跑。随手就有伞用,那多好?

解决方案 »

  1.   

    To reallike(认真学习Cpp用Cpp考虑delphi) 关于你的第二个例子,伞的问题。  如果我实际也要伞的话我就会在中国人类中定义,当然如果说有的人就是不用伞我会在 T中国人 下定义一个子类 T有伞的中国人 ,T没有伞的中国人。  当然那一种方法也没有错,其实要分优劣也不容易。我追求的是尽量保证对象封装的完整性,整个程序都是一个一个的对象组成,要是出现这种贯穿全局的变量就成了不和谐的音符。 在一个项目开发过程中,大家都会尽量用同样的风格开发,比如说可以用全局变量,而我在我做的模块中就不用全局变量,也没有破坏风格。而如果项目不让用全局变量,而你的编程习惯是用全局变量,你在实现的时候就会比较别扭,也更容易出错。我的回答:嗬嗬,为了一把小小的雨伞而定一两个多余的类这不是多此一举?只要不影响吃饭睡觉,不影响到你的身份证户口,大不了叫procedure 下雨;给淋透了,回去洗个澡就得了。世界上没有完美的东西,防患于未然。孰轻孰重要分清楚,要不会捡了芝麻丢了西瓜。如果是雨衣呢?你会不会定义一个T没有雨衣的中国人?如果定义我们的街道,我们的公园,你是不是也封装到T城市里没有公园的中国人?把重要的防起来,不要被别人看到,没有必要的放在一起,大家都看。生活中我们就需要许多公共的东西,TObject ----> TApplication才几个类?更好的例子就是Var 
      垃圾堆: 未知类型;这个你要不设成公共,那就……或许按照你的做法会T垃圾堆 = class但是有必要吗?这样所定义的类和record没有区别,还不如record效率高为什么不用全局变量或者record呢?每一个人都像一个被封装好了的对象。但是人之间的联系大多数都是在一些公共的地方。老是通过它的父类,先祖联系,那就太局限了。T中国人,如果是T美国人,那T我和T你如果和这个T他: T美国人联系呢?通过它的public里面提供的?我们的public提供的?那会失去效率。我知道你会说,我会通过T人,来联系。我不多说了
      

  2.   

    但 现实是所做的系统 应都是可用类描述的,还不至于象 reallike(认真学习Cpp用Cpp考虑delphi) 老兄说得那样有太多的可变性。  生活可能用对象描述比较困难,但一个具体的功能我看还是可很的。  不用 record 而用类来做,是考虑到用Record 就有可能用到 ^,@ 显式使用指针,分配内存,出错的可能性要比较高。
     
      就象给TreeNode.Data 我从来就是建一个TMyNodeInfo=Class的类而不是TMyNodeInfo=Record  至于效率的问题,除非是大量数据等比较少的情况,大多数时候还是考虑代码风格的统一性,将来的可维护性,程序实现方式的统一性。
    我的回答:嘿嘿,record不一定用指针的,我的意思就是做一个存储数据集。使用类,就要使用类的效率,使用类的效果,如果你理解构造函数的定义,类如何建立的,这些底层的事情其实你就不会随便使用类了。其实任何事情都不能泛滥,好东西也会变质。好像我大哥的文章我还没有删除,你可以看看。http://www.reallysoft.com.cn/op.chm现实所作的系统,你是没有做过太多可变性的,所以你才提出了重构。而我几乎不会考虑这个。我会考虑扩容,其他事情。嘿嘿,就这个,咱们再继续讨论。大哥的这篇文章是描述Object类创建的时候做了些什么。都知道Tobject = class 是Vcl最原始的类。在类的使用上是不是酌量?而record就不一样了,并且灵活。别为了一些所谓的隐患而放弃一些优势。指针有许多隐患,但是灵活多变,优势明显。这种无谓的猜疑就像吃饭怕噎死,喝水怕呛死一样无聊。(可能例子不太恰当)
      

  3.   

    To reallike(认真学习Cpp用Cpp考虑delphi)   http://www.reallysoft.com.cn/op.chm   这文章偶以前也看过。  我觉得我们俩讨论的问题好象有点偏差了,说的不是同一个问题的话讨论也就没有了意义。  当然计算机程序所有的东西归根到底都是有汇编语言(也可说是机器语言的)在地层。  高级语言不论用什么样的方式说到底对于计算机来说只是分配内存,读写磁盘,交给处理器调度执行。机器语言和汇编语言就不可能是用OOP的方式去实现和操作的。  OOP讲的是封装,而封装是为什么???就是为了将一些杂乱的过程给一个统一的外衣。封装是对外封装,内部可不是什么OOP的东西还是面向过程的。  对OOP我的理解是对过去面向过程的开发的一种封装,在DOS下的程序都是一个个的过程和函数,大家编程考虑的是过程函数的层次。现在程序你看它运行的还是过程和函数,但我们是站在包装了过程和函数的类的基础上看问题。大家设计出类觉得就完成了,单个的过程和函数谁都会写。
      
      在这样的角度下为了程序的统一而不Record 所造成的“损失”是微不足道的。
     
      以现在的计算机运行我想你用10万个Record 操作和我用10万个Class 操作造成的差别我想不会很大(我没有测试过) 。  我现在做的系统大多是MIS,一些应用级的程序。要是让我去做一些系统级的,开发操作系统一类(偶不会C只学过TC,也不会汇编,只学过一学期)的程序,肯定是要仔细计算效率问题的   现在我们统一了讨论的范围,可能更容易让对方理解自己的想法和看法。
      

  4.   

    我是很讲效率的,我说这些是因为我也在做Mis,Erp之类的。我手头的两个Mis都不讲效率。乱用OO,乱用类,并不大的Mis,每次启动需要10秒,甚至更长的时间。里面有TBaseForm 其实就比TForm加了一行代码,TShareForm,无聊的一个东西,完全可以用record代替,就是放一些共享的数据。还有其他的一些就不多举例了,就这两个就足以说明了。你对OOP的理解如果是披着外衣的面向过程,那还有有些浅显,我现在看厚达1260页的 Object oriented software construction如果你要搞软件设计,建议你也去买一本,英文影印版。仅仅是对全局变量来说,上面说的仅仅是一些抽象的实例,具体而言,对于设立一些共享数据来说这个是很有必要的。比如上面我的例子,那仅仅是把伞而已,如果仅仅是伞可以设成常量。但是不仅仅是伞,还有其他的可能性,不能排除。对于全局变量来讲,乱用当然有弊。不过使用它做一些穿针引线事情是很有益的。并且可以结合set record这样的,提高效率会很明显。
      

  5.   

    我的程序也不用数据绑定,如数据库支持存储过程,则在程序中不会出现语句,只是调用存储过程,我的程序只有一个ADOConnection ,很少有ADOQuer放在界面上,都是动态创建后将数据读到StringGrid或ListView中后就释放。=================================================================================
    我的程序一般不用数据绑定,如数据库支持存储过程,在程序中也会有一些SQL语句,而不仅仅是调用存储过程,我的程序只有一个ADOConnection ,一般会有一个ADOQuer放在界面上。
    然后写一个过程
    procedure ExecSQL(aQuery:TADOQuery;aSQL: String; aExecMode: boolean);
    begin
      aQuery.SQL.Clear;
      aQuery.SQL.Add(aSQL);
      if aExecMode then
        aQuery.Open
      else
        aQuery.ExecSQL;
    end;
    需要的都调用它。这样做是不是不大符合规范?
      

  6.   

    “你对OOP的理解如果是披着外衣的面向过程,那还有有些浅显,我现在看厚达1260页的 Object oriented software construction如果你要搞软件设计,建议你也去买一本,英文影印版。”是不是太尖锐了一点?
      

  7.   

    惭愧,惭愧,俺的英语实在是.........555555现在偶不知是不是走的有点极端,不过在现在的项目中也没有发现什么问题,可能问题还没有显现。我去年也报了高程,可考试的时候在青海。今年也没报。明年在看吧。偶也没看什么纯理论方面的书,就是市面上现在见到的一些DELPHI资料。不过人总会犯这样的错误:如是你手中有的把锤子,就会将所有的东西都看成钉子。
      

  8.   

    很SORRY,没有看完,就来说2句,太长了,没有心情看完不使用全局变量
    ?
    我倒
    ================使用全局变量与面向对象不会有冲突
    面向对象编程,写类,你没有必要一定不使用全局变量
    有时候这样做会很累的写作起来方便,维护起来方便也要考虑一下
      

  9.   

    To PrettyMurphy(土豆) 我很少在界面上放ADOQuery ;如要查询我就动态创建。function FindUserName(Const AUserID:Integer):String;
    var
      ADO_Q:TADOQuery;
    begin
      ADO_Q:=TADOQuery.Create(nil);
      ADO_Q.Connection:=Connecton;//给窗体添加的属性
      查找  ADO_Q.Free;
        end;
      

  10.   

    Ok,咱们暂停一下。发现这个代码有意思:function FindUserName(Const AUserID:Integer):String;
    var
      ADO_Q:TADOQuery;
    begin
      ADO_Q:=TADOQuery.Create(nil);
      ADO_Q.Connection:=Connecton;
      ADO_Q.Free;
        
    end;这里的connection是哪里的?
      

  11.   

    引用 ZyxIp(绝望中...) “我的程序只有一个ADOConnection ”应该就是Connecton吧。TADOQuery有Connection吧Connection property (TCustomADODataSet)
    Specifies the ADO connection component to use.Delphi syntax:property Connection: TADOConnection;C++ syntax:__property TADOConnection* Connection = {read=GetConnection, write=SetConnection};DescriptionUse Connection to specify an ADO connection object to use to connect to an ADO data store.At design-time, select from the list of available TADOConnection objects (if any have been added to the application) invoked from the Object Inspector.At runtime, set Connection to reference an existing TADOConnection object.ADOTable1.Connection := ADOConnection1;
    ADOTable1->Connection = ADOConnection1;Note: a connection to an ADO database can be established either using a separate TADOConnection object (configured to connect to the database) or directly with a valid entry in the ConnectionString property.动态创建的不会有么?不知道哦?
      

  12.   

    这个不难想象,那函数是TFormX的成员函数,每个TFormX是从BaseForm继承的,BaseForm有个
    property Connection: TADOConnection read FConnection write FConnection;不过,我觉得无此必要。
    即然是MIS程序,那基本上可以说是每个FORM都会与DB打交道,所以,而又不想放DataSet上去到FORM里面,最好的方法是动态生成。
    而动态生成又是经常性的Create, Free,所以,可以专门写个DataSet Pool来管理这些使用的DataSet,节俭一点,而且,不必再将Connection放到BaseForm中,让DataSet Pool去管理吧全局变量,OOP,其实偶觉得很简单,也很复杂,因为,偶的全局变量怎么不会像VCL的全局变量那么有用?可以影响整个APP,偶现在写的全局变量影响力不够,所以,写来写去,偶只能写成OOP,或没法子,乱定义一个全局变量,凑合着给程序使用:(
      

  13.   

    Tfrom1=Class(Tform) ...
     published
      property Connection :TADOConnection Read FConnection write FConnection;end;  @_@ 。
      

  14.   

    我习惯下面的:
        with TADOQuery.Create(nil) do
        begin
            ConnectionString := g_ADOConnectionStr; //g_ADOConnectionStr全局变量
            Sql.Add('SQL语句');
            try 
                Open;
                //操作数据
                Close;
            finally
                Free;
            end;
        end;
      

  15.   

    Connection 是我自己加的。
    那你平时怎么用连接字符串?
      

  16.   


    我只能同意你们两人上人的想法了:)全部变量要[用好]!!!!(我公司以前写的一个程序至少100个程序级变量,我真不敢相信那是人写的)也要加一点OO思想.重要,不只是考虑在当前的项目中重用.也要考虑到将来的项目的重用!(说错了不要怪了).至于ZyxIp(绝望中...)的:
    ---------------------------------------------------------------------------
    >>我的程序也不用数据绑定,如数据库支持存储过程,则在程序中不会出现语句,
    >>只是调用存储过程,我的程序只有一个ADOConnection ,很少有ADOQuer放在界面上,
    >>都是动态创建后将数据读到StringGrid或ListView中后就释放。
    --------------------------------------------------------------------------- 如果公司是我的,我不会让我的程序这样做!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!那几个小Dataset对程序的性能的影响是不会太大的!而那样的话,做起来可能会慢很多.如果影响太大,我宁愿让客户升级硬件.什么年代了,还用P3啊?哈哈.如果可能,应该自己做一些通用工具/或开发工具!
      

  17.   

    呵呵,看看这种大讨论真是长见识!
    老实说我对oo一直理解的不够深刻,直到最近学了编写组建,才有了新的认识。不过看了高手们的讨论,觉得还是差的太远,虚心学习呀。
    to ZyxIp(绝望中...):
    Tfrom1=Class(Tform)
     ...
     published
       property Connection :TADOConnection Read FConnection write FConnection;
    end;
    什么意思呢?添加了这个属性后,是不是要在设计期或运行期指定一个TADOConnection给TForm1.Connection呢?那这个TADOConnection是设计期时就设置好并放在TForm1中的了?如果是这样,为什么不直接把动态生成的TADOQuery.Connection设成TADOConnection呢?因为有很多TADOQuery都共用一个Connection?那我更改TADOConnection属性也和重新设置TForm1.Connection效果一样呀。to  copy_paste(木石三):
    DataSet Pool类似的概念我在学习midas时也遇到过,一直没有搞清楚。你能具体说说:就此问题,如何建立和使用这个连接池呢?谢谢。请大家继续积极讨论!受益匪浅呀。huhu
      

  18.   

    系统启动时就在注册表或一个配置文件中去读安装时确定的连接字符串。系统主窗体上就有ADOCOnnection,调用其它窗体就将对应窗体赋值。有些事情是实现的效果一样可看起来的效果不一样。为了统一就舍弃了一些方便性,而非要多写两行代码。
      ADO_Q.Connection:=Connection;