4

Delphiでクラスを設計する場合、通常、プライベートフィールド(メンバー)、プライベートセッターおよびゲッターメソッド、およびパブリックプロパティがあります。クラスの外部から、そのデータへのアクセスは公共の財産によってのみ行われます。クラスのユーザーは、getterメソッドが存在することすら知りません。

したがって、getterメソッドとsetterメソッドはインスタンスメンバーをカプセル化し、プロパティはgetterメソッドとsetterメソッドをカプセル化します。

ただし、インターフェイスを定義するときは、これらのメソッドを公開しています。

ICounter = interface
  // I wouldn't want to specify these 2 methods in the interface, but I'm forced to
  function GetCount: Integer;
  procedure SetCount(Value: Integer);

  property Count: Integer read GetCount write SetCount;
end;

具体的なクラスの実装:

TCounter = class(TInterfacedObject, ICounter)
private
  function GetCount: Integer;
  procedure SetCount(Value: Integer);
public
  property Count: Integer read GetCount write SetCount;
end

それを使用する:

var
  Counter: ICounter;
begin
  Counter := TCounter.Create;
  Counter.Count := 0; // Ok, that's my public property

  // The access should me made by the property, not by these methods
  Counter.SetCount(Counter.GetCount + 1);
end;

プロパティがgetter/setterプライベートメソッドをカプセル化する場合、これは違反ではありませんか?ゲッターとセッターは具象クラスの内部であり、公開されるべきではありません。

4

2 に答える 2

8

メソッドは、インターフェースと対話するための主要な方法です。インターフェイスのプロパティはDelphi固有の拡張機能です。それらは、基礎となるメソッドに構文糖衣を提供するだけです。他の言語はありませんインターフェイスのメソッドは定義上パブリックであるため、プロパティによってカプセル化されません。インターフェイスでは、プロパティは常にメソッドによってサポートされ、メソッドは常にパブリックであるため、プロパティがメソッドによってサポートされていることを示すことによって、実装の詳細を明らかにすることはありません。カプセル化は、そもそも存在していなかった場合でも違反することはできません。

あなたの例の具体的なクラスは誤解を招きます。まず、そこで定義されたプロパティは、インターフェイスで定義されたプロパティとはまったく関係がありません。読み取り専用として定義したり、データメンバーに直接アクセスしたり、プライベートにしたり、インターフェースのバージョンとは完全に削除したりするなど、他の方法で変更したりすることができます。インターフェースのユーザーには影響せず、さらに貸し出します。プロパティではなく、インターフェイスで重要なのはメソッドであるという概念の信憑性。コンパイラーは、インターフェース・プロパティーの使用を、すでに公開されている対応するインターフェース・メソッドの1つの使用に直接変換します。実装オブジェクトは、この問題について相談されることはありません。

次に、クラスの可視性指定子は無関係です。メソッドはすでにインターフェース上で公開されているため、メソッドをプライベートにする必要はありません。ただし、それらをプライベートにすることは、インターフェースを介したクラスの適切な使用を促進するため、悪い考えではありません。

インターフェイスのアクセサメソッドはプライベートにできるはずだと文句を言うかもしれませんが、それは一般にインターフェイスメソッドにプライベートにできるように要求するのと同じであり、それは意味がありません。明らかに呼び出すことができないメソッドは、インターフェースの一部ではありません。インターフェイスは、CやC ++のようにプロパティの概念がない言語でも、COMをサポートするすべての言語で使用できることを思い出してください。これらの言語は、アクセサメソッドも呼び出すことができる必要があります。メソッドが何らかの形でプライベートである場合、インターフェースはそれらの言語では機能しません。


Delphiクラスのプロパティがフィールドを参照する場合、その詳細は実際にはクラスの公開インターフェースの一部です。そのプロパティを使用するコードは、プロパティがフィールドの単なるエイリアスであることを知っています(コードの作成がそれを知らなかったとしても)。プロパティ定義を変更した場合、コンパイラがプロパティにアクセスするための新しいコードを生成できるように、そのクラスを使用するコードを再コンパイルする必要があります。

プロパティをメソッドでバックアップする必要がある場合、プロパティ定義を実際に変更することはできなくなります。変更できるのは実装のみであるため、格納されたフィールドから読み取るのではなく、オンデマンドでプロパティを計算することを選択したという理由だけで、インターフェイスのコンシューマーを再コンパイルする必要はありません。

于 2012-06-01T15:24:11.720 に答える
3

ただし、インターフェイスはGetter/Setterメソッドの使用を強制します。

インターフェイスにはインスタンスがないため、データを保存できません。

それに加えて、GetterメソッドとSetterメソッドは通常プライベートです。インターフェイスでそれらを定義すると、インターフェイスのユーザーがそれらにアクセスできるようになります。それはいくつかの混乱を引き起こします:

インターフェイスはメンバーの可視性を指定しません。表示されるプロパティとメソッド、およびそれらが誰であるか(保護または公開または公開)を定義するためのインターフェースを実装するのはクラス次第です。

独自のクラス/モジュールのみでインターフェースを使用する場合は、実装クラスの可視性を変更しても問題ありませんが、良い方法ではありません。

ここで、カウントをどのように設定しますか:Counter.Count:= 0またはCounter.SetCount(0)?これはカプセル化を破っていませんか?

countプロパティは両方の方法で設定できます。設定する場合:

Counter.Count := 0

アクセスメソッドは同じ方法で呼び出されます。そして、カプセル化は壊れていません。

編集:

何も壊れないが、異なる動作をする可能性があることを明確にするために例を挙げましょう。

ICounterインターフェースのこの実装を考えると:

  TMyCounter = class(TInterfacedObject, ICounter)
  private
    FCount: Integer;
    function GetCount: Integer;
    procedure SetCount(Value: Integer);
  public
    property Count: Integer read GetCount write SetCount;
  end;

implementation

function TMyCounter.GetCount: Integer;
begin
  Result := FCount;
end;

procedure TMyCounter.SetCount(Value: Integer);
begin
  FCount := Value;
end;

プロパティの考えられる用途は次のとおりです。

var
  c: TMyCounter;
  ic: ICounter;
begin
  c := TMyCounter.Create;
  try
    //c.SetCount(1); //won't compile, since the setter is private
    ICounter(c).SetCount(1); //it is ok, because the interface method is public
    c.Count := C.Count + 1; //it is ok, cause the SetCount acessor will be invoked
    if Supports(c, ICounter, ic) then
      ShowMessage(IntToStr(ic.GetCount));
  finally
    c := nil;
  end;

したがって、次のように結論付けることができます。

  • クラスには「アクセス指定子」があり、これは
    クラスタイプにアクセスするときに常に尊重されます。
  • インターフェイスには「アクセス指定子」がなく、インターフェイスタイプにアクセスするときにすべてのメソッドがパブリックと見なされます。
于 2012-06-01T15:33:27.703 に答える