Domanda

Delphi (e probabilmente molti altri linguaggi) ha degli aiutanti di classe.Questi forniscono un modo per aggiungere metodi extra a una classe esistente.Senza creare una sottoclasse.

Quindi, quali sono i buoni usi per gli aiutanti di classe?

È stato utile?

Soluzione

Li sto usando:

  • A inserire enumeratori nelle classi VCL che non li implementano.
  • A migliorare Classi VCL.
  • Per aggiungere metodi alla classe TStrings in modo da poter utilizzare gli stessi metodi in le mie liste derivate e in TStringList.

    TGpStringListHelper = class helper for TStringList
    public
      function  Last: string;
      function  Contains(const s: string): boolean;
      function  FetchObject(const s: string): TObject;
      procedure Sort;
      procedure Remove(const s: string);
    end; { TGpStringListHelper }
    
  • Per semplificare l'accesso ai campi record e rimuovere la fusione.

Altri suggerimenti

All'inizio ero un po 'scettico riguardo agli aiutanti di classe. Ma poi ho letto un interessante post di blog e ora sono convinto che siano davvero utili.

Ad esempio, se si desidera funzionalità extra per una classe di istanza esistente e per qualche motivo non è possibile modificare l'origine esistente. È possibile creare un helper di classe per aggiungere questa funzionalità.

Esempio:

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

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

Ogni volta, ora utilizziamo un'istanza di (una sottoclasse di) TStrings e TStringsHelper rientra nell'ambito. Abbiamo accesso al metodo IsEmpty.

Esempio:

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

Note:

  • Gli helper di classe possono essere memorizzati in un'unità separata, in modo da poter aggiungere i propri helper di classe eleganti. Assicurati di dare a queste unità un nome facile da ricordare come ClassesHelpers per gli helper dell'unità Classes.
  • Ci sono anche helper di registrazione.
  • Se ci sono helper di classi multiple nell'ambito, si aspettano alcuni problemi, è possibile utilizzare un solo helper.

Sembra molto simile ai metodi di estensione in C # 3 (e VB9). L'uso migliore che ho visto per loro è l'estensione a IEnumerable<T> (e IQueryable<T>) che consente a LINQ di lavorare contro sequenze arbitrarie:

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

(o qualunque altra cosa, ovviamente). Tutto ciò è fattibile perché i metodi di estensione ti consentono di concatenare efficacemente le chiamate a metodi statici che assumono lo stesso tipo del loro ritorno.

Sono molto utili per i plug-in. Ad esempio, supponiamo che il tuo progetto definisca una determinata struttura di dati ed è salvato su disco in un certo modo. Ma poi qualche altro programma fa qualcosa di molto simile, ma il file di dati è diverso. Ma non vuoi gonfiare il tuo EXE con un sacco di codice di importazione per una funzione che molti dei tuoi utenti non dovranno usare. Puoi utilizzare un framework di plug-in e inserire gli importatori in un plug-in che funzioni in questo modo:

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

E quindi definire il convertitore. Un avvertimento: un aiutante di classe non è un amico di classe. Questa tecnica funzionerà solo se è possibile configurare completamente un nuovo oggetto TMyClass attraverso i suoi metodi e proprietà pubblici. Ma se puoi, funziona davvero bene.

La prima volta che ricordo di aver vissuto ciò che stai chiamando " class helpers " è stato durante l'apprendimento dell'obiettivo C. Il cacao (la struttura dell'obiettivo C di Apple) utilizza quelli che sono chiamati " Categorie. "

Una categoria ti consente di estendere una classe esistente aggiungendo i tuoi metodi senza subclassare. Infatti, il cacao ti incoraggia a evitare la sottoclasse quando possibile. Spesso ha senso effettuare una sottoclasse, ma spesso può essere evitato usando le categorie.

Un buon esempio dell'uso di una categoria in Cocoa è quello che viene chiamato " Key Value Code (KVC) " e " Key Value Observing (KVO). "

Questo sistema è implementato usando due categorie (NSKeyValueCoding e NSKeyValueObserving). Queste categorie definiscono e implementano metodi che possono essere aggiunti a qualsiasi classe desiderata. Ad esempio, Cocoa aggiunge & Quot; conformance & Quot; a KVC / KVO usando queste categorie per aggiungere metodi a NSArray come:

- (id)valueForKey:(NSString *)key

La classe NSArray non ha né una dichiarazione né un'implementazione di questo metodo. Tuttavia, attraverso l'uso della categoria. È possibile chiamare quel metodo su qualsiasi classe NSArray. Non è necessario sottoclassare NSArray per ottenere la conformità KVC / KVO.

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

L'uso di questa tecnica semplifica l'aggiunta del supporto KVC / KVO alle tue classi. Le interfacce Java consentono di aggiungere dichiarazioni di metodi, ma le categorie consentono anche di aggiungere le implementazioni effettive alle classi esistenti.

Come mostra GameCat, TStrings è un buon candidato per evitare di scrivere:

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;

Hai mai avuto bisogno di accedere a stringhe multilinea nel registro?

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;

Non consiglierei di usarli, poiché ho letto questo commento:

  

" Il problema più grande con la classe   aiutanti, dal p.o.v del loro utilizzo   nelle tue applicazioni, è il fatto   che solo UN aiutante di classe per un dato   la classe può essere nell'ambito in qualsiasi momento. "   ... " Cioè, se hai due aiutanti   nell'ambito, solo UNO sarà riconosciuto   dal compilatore. Non ne otterrai nessuno   avvertimenti o anche suggerimenti su qualsiasi altro   aiutanti che possono essere nascosti. "

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

Li ho visti usati per rendere coerenti i metodi di classe disponibili tra le classi: aggiungere Open / Close e Show / Hide a tutte le classi di un dato " type " piuttosto che solo proprietà attive e visibili.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top