質問

Delphi(およびおそらく他の多くの言語)にはクラスヘルパーがあります。これらは、既存のクラスに追加のメソッドを追加する方法を提供します。サブクラスを作成しません。

では、クラスヘルパーの良い用途は何ですか?

役に立ちましたか?

解決

私はそれらを使用しています:

他のヒント

最初は、クラスヘルパーに懐疑的でした。しかし、その後、興味深いブログエントリそして今、私はそれらが本当に役立つと確信しています。

たとえば、既存のインスタンスクラスに追加の機能が必要な場合、何らかの理由で既存のソースを変更することはできません。クラスヘルパーを作成して、この機能を追加できます。

例:

type
  TStringsHelper = class helper for TStrings
  public
    function IsEmpty: Boolean;
  end;

function TStringsHelper.IsEmpty: Boolean;
begin
  Result := Count = 0;
end;

常に、TStrings(のサブクラス)のインスタンスを使用し、TStringsHelperはスコープ内にあります。メソッドIsEmptyにアクセスできます。

例:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Memo1.Lines.IsEmpty then
    Button1.Caption := 'Empty'
  else
    Button1.Caption := 'Filled';
end;

注:

  • クラスヘルパーは別のユニットに格納できるため、独自の気の利いたクラスヘルパーを追加できます。これらのユニットには、ClassesユニットのヘルパーにClassesHelpersなどの覚えやすい名前を付けてください。
  • レコードヘルパーもあります。
  • スコープ内に複数のクラスヘルパーが存在する場合、いくつかの問題を想定して、使用できるヘルパーは1つだけです。

これは、C#3(およびVB9)の拡張メソッドに非常によく似ています。私が彼らのために見た中で最も良い使用法は、LINQが任意のシーケンスに対して動作できるようにするIEnumerable<T>(およびIQueryable<T>)の拡張です:

var query = someOriginalSequence.Where(person => person.Age > 18)
                                .OrderBy(person => person.Name)
                                .Select(person => person.Job);

(またはもちろん、何でも)。拡張メソッドを使用すると、返されるのと同じ型を取る静的メソッドへの呼び出しを効果的に連結できるため、これはすべて実行可能です。

これらはプラグインに非常に便利です。たとえば、プロジェクトで特定のデータ構造を定義し、特定の方法でディスクに保存するとします。しかし、他のプログラムは非常によく似た処理を行いますが、データファイルは異なります。しかし、多くのユーザーが使用する必要のない機能のために、大量のインポートコードでEXEを肥大化させたくありません。プラグインフレームワークを使用して、インポーターを次のように機能するプラグインに配置できます。

type
   TCompetitionToMyClass = class helper for TMyClass
   public
      constructor Convert(base: TCompetition);
   end;

そして、コンバーターを定義します。 1つの注意点:クラス helper はクラス friend ではありません。この手法は、パブリックメソッドとプロパティを通じて新しいTMyClassオブジェクトを完全にセットアップできる場合にのみ機能します。しかし、可能であれば、それは本当にうまくいきます。

あなたが何を呼んでいるのかを初めて覚えた<!> quot; class helpers <!> quot; Objective Cを学んでいたとき。Cocoa(AppleのObjective Cフレームワーク)は、<!> quot; Categories。<!> quot;

と呼ばれるものを使用します。

カテゴリを使用すると、サブクラス化せずに独自のメソッドを追加して、既存のクラスを拡張できます。実際、Cocoaは可能な限りサブクラス化を避けることをお勧めします。サブクラスを作成することは理にかなっていますが、多くの場合、カテゴリを使用して回避できます。

Cocoaでカテゴリを使用する良い例は、<!> quot; Key Value Code(KVC)<!> quot;と呼ばれるものです。および<!> quot; Key Value Observing(KVO)。<!> quot;

このシステムは、2つのカテゴリ(NSKeyValueCodingおよびNSKeyValueObserving)を使用して実装されます。これらのカテゴリは、必要なクラスに追加できるメソッドを定義および実装します。たとえば、Cocoaは<!> quot; conformance <!> quot;を追加します。これらのカテゴリを使用して次のようなメソッドをNSArrayに追加することにより、KVC / KVOに追加します。

- (id)valueForKey:(NSString *)key

NSArrayクラスには、このメソッドの宣言も実装もありません。ただし、カテゴリの使用を通じて。 NSArrayクラスでそのメソッドを呼び出すことができます。 KVC / KVOに準拠するためにNSArrayをサブクラス化する必要はありません。

NSArray *myArray = [NSArray array]; // Make a new empty array
id myValue = [myArray valueForKey:@"name"]; // Call a method defined in the category

この手法を使用すると、KVC / KVOサポートを独自のクラスに簡単に追加できます。 Javaインターフェースではメソッド宣言を追加できますが、カテゴリでは実際の実装を既存のクラスに追加することもできます。

GameCatが示すように、TStringsは入力を避けるための良い候補です。

type
  TMyObject = class
  public
    procedure DoSomething;
  end;

  TMyObjectStringsHelper = class helper for TStrings
  private
    function GetMyObject(const Name: string): TMyObject;
    procedure SetMyObject(const Name: string; const Value: TMyObject);
  public
    property MyObject[const Name: string]: TMyObject read GetMyObject write SetMyObject; default;
  end;

function TMyObjectStringsHelper.GetMyObject(const Name: string): TMyObject;
var
  idx: Integer;
begin
  idx := IndexOf(Name);
  if idx < 0 then
    result := nil
  else
    result := Objects[idx] as TMyObject;
end;

procedure TMyObjectStringsHelper.SetMyObject(const Name: string; const Value:
    TMyObject);
var
  idx: Integer;
begin
  idx := IndexOf(Name);
  if idx < 0 then
    AddObject(Name, Value)
  else
    Objects[idx] := Value;
end;

var
  lst: TStrings;
begin
  ...
  lst['MyName'] := TMyObject.Create; 
  ...
  lst['MyName'].DoSomething;
  ...
end;

レジストリ内の複数行の文字列にアクセスする必要がありましたか?

type
  TRegistryHelper = class helper for TRegistry
  public
    function ReadStrings(const ValueName: string): TStringDynArray;
  end;

function TRegistryHelper.ReadStrings(const ValueName: string): TStringDynArray;
var
  DataType: DWord;
  DataSize: DWord;
  Buf: PChar;
  P: PChar;
  Len: Integer;
  I: Integer;
begin
  result := nil;
  if RegQueryValueEx(CurrentKey, PChar(ValueName), nil, @DataType, nil, @DataSize) = ERROR_SUCCESS then begin
    if DataType = REG_MULTI_SZ then begin
      GetMem(Buf, DataSize + 2);
      try
        if RegQueryValueEx(CurrentKey, PChar(ValueName), nil, @DataType, PByte(Buf), @DataSize) = ERROR_SUCCESS then begin
          for I := 0 to 1 do begin
            if Buf[DataSize - 2] <> #0 then begin
              Buf[DataSize] := #0;
              Inc(DataSize);
            end;
          end;

          Len := 0;
          for I := 0 to DataSize - 1 do
            if Buf[I] = #0 then
              Inc(Len);
          Dec(Len);
          if Len > 0 then begin
            SetLength(result, Len);
            P := Buf;
            for I := 0 to Len - 1 do begin
              result[I] := StrPas(P);
              Inc(P, Length(P) + 1);
            end;
          end;
        end;
      finally
        FreeMem(Buf, DataSize);
      end;
    end;
  end;
end;

このコメントを読んだため、これらの使用はお勧めしません:

  

<!> quot;クラスの最大の問題   ヘルパー、それらを使用するp.o.vから   独自のアプリケーションでは、事実です   指定された唯一のクラスヘルパー   クラスはいつでもスコープ内にあります。<!> quot;   ... <!> quot;つまり、ヘルパーが2人いる場合   範囲内では、1つだけが認識されます   コンパイラによって。あなたは何も手に入れません   その他に関する警告またはヒント   隠されている可能性のあるヘルパー。<!> quot;

http://davidglassborow.blogspot.com /2006/05/class-helpers-good-or-bad.html

クラス間で一貫した利用可能なクラスメソッドを作成するためにそれらを使用したのを見ました:特定の<!> quot; type <!> quot; ActiveプロパティとVisibleプロパティだけではありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top