这个问题令我很困惑
这样设计的类并不少见:TXXXObject = class
  private
    FData: Datatype;
  public
    property Data: Datatype read FData write FData(或SetData);
end;它实际没有(或几乎没有)实现任何封装,这种设计令我觉得十分别扭:
    我不把数据放到private域,便无法实现任何封装;把它放到private后,又要提供办法让别人访问它,绕了一圈后发现(几乎)什么都没做。有谁能告诉我这样设计有何意义?还有一个问题:在类的方法中使用自己的特性是否是不好的做法?以上面的类为例,我的意思是当我在TXXXObject的其它方法中访问FData时,不应该通过Data而应该直接使用FData或SetData,我总觉得使用特性Data是不好的,却又说不清为什么。

解决方案 »

  1.   

    lovendll:
        当我提供的接口可以对“封装”在对象中的数据做任何访问时,那跟没有封装是不是没有区别了?何不把数据放到public域?
        好像大家都是:
        宁肯这样:
    TXXXObject = class(TObject)
    private
      FData: DataType;
    public
      property Data: DataType read FData write FData;
    end;
        宁死也不这样:
    TXXXObject = class(TObject)
    public
      FData: DataType;
    end;    我看不出两种做法的差别,甚至觉得第二种做法更清楚:FData就是给外界用的。
      

  2.   

    没有什么特别的地方,主要防止对数据地址的直接访问
    假设声明为
    tobjectx= ..
    public
      data: integer;
    end;对于上面的声明,可能会出现这样的应用:
    procedure SomeOtherProc(var a: integer); //or procedure SomeOtherProc(out a: integer);
    begin
      a := ...;
    end;
    x: tobjectx;
    SomeOtherProc(x.data);或者
    x: tobjectx;
    pint: ^Integer;pint := @(x.data)
    pint^ := 1;到后来发现需要一个setdata的逻辑时,就为时已晚,因为其他代码可能存在大量的指针应用,这样会涉及大量的变更如果声明为property则表明该字段不一定驻存在内存里(保留了read/write都是函数的可能性),从而防止了指针的应用,并且不会有时间空间性能上的额外开销
      

  3.   

    对于简单变量看起来意义不大。
    但考虑到对以后的扩展:
    你以后假如write FData时希望同时做某个操作怎么办?
    例如,write FData;时希望同时对数据进行校验,那么可以这样:procedure SetData(Value:Integer);
    begin
      if Value<0 then Value :=0;
      FData := Value;
    end;
      

  4.   

    我认为这样设计是为了继承考虑的,继承类可以定义同名的Data属性并因此隐藏掉父类的Data, 如果定义成public的变量就做不到这点了。
      

  5.   

    alphax: 说得很对,我没考虑到指针的问题。windindance:我现在想到的是:TXXXObject1 = class
    public
      Data: integer;
    end;TXXXObject2 = class
    private
      FData: integer;
    public
      property Data: integer read FData write FData;
    end;    当我使用这两个类后,
        对于TXXXObject2,若以后我要向外界对Data的访问加以限制,有可能只在TXXXObject2的类定义中对特性Data的声明做修改(比如改 read FData 为 read GetData(),再在GetData()中给出限制),而程序的其他地方不必做大的改动。
        对于TXXXObject1,若以后我要向外界对Data的访问加以限制,修改将十分困难,除非把它彻底改成TXXXObject2的模式,但若程序中涉及到Data的指针,就很麻烦了,不能把成员Data改为特性。Idle_:我初学不久,没做过多少程序,请问在派生类中用同名属性隐藏父类属性是常用的做法吗?能否举一例。我更倾向于使用虚方法,比如这样:TFathar = class(TSomeObject)
    private
      …
      procedure GetMember1(): integer;virtual;
    public
      property Member1: integer read GetMember1;
    end;TDerive = class(TFather)
    private
      …
      procedure GetMember1(): integer;override;
    end;    我觉得如果使用同名属性隐藏父类属性而不是用虚方法的话,
        似乎是不太合理不太安全的做法,
        对于一个派生类对象ADerive,
        ADerive.Member1、TFather(ADerive).Member1将给出不同的值,
        而程序常常会把  派生类对象作为父类对象使用 (这情况是合理的,因为派生类‘是’父类),比如这样:procedure Dosomething(AFather: TFather);
    begin

    end;

    Dosomething(ADerive);    于是很可能在想调用TDerive.Member1的时候,却调用了TFather.Member1。
        具体的例子我现在想不到。
      

  6.   

    TXXXObject = class
      private
        FData: Datatype;
      public
        property Data: Datatype read FData write FData(或SetData);
    end;property这个概念出现的重大价值是将对象方法中对成员变量访问的方法同其它功能方法
    不仅从概念上,而且从语法层次上独立出来.这样做property访问封装,大致有几个用途:1,访问成员的控制2,成员属性类型抽象化
      property的Datatype可以是抽象类或者接口,private 成员则可以是DataType的实现类.3,成员属性位置抽象化
      A,property的数据不必是对象自己的私有数据,有可能是另一个对象的属性值
      B,多个property可以指定同一个私有成员,而体现形式同内容关系.4,增加事件触发扩展点
      在编写类库的时候,property的Get或Set方法常是很有必要的事件触发扩展点,可以在
    这些点上增加OnSetxxx,OnGetxxx等事件点
      

  7.   

    TXXXObject = class
      private
        FData: Datatype;
      published
        property Data: Datatype read FData write FData(或SetData);
    end;//因为这样可以用rtti
      

  8.   

    sorry,忘了继承TPersistent
    TXXXObject = class(TPersistent)
      private
        FData: Datatype;
      published
        property Data: Datatype read FData write FData(或SetData);
    end;