Pregunta

Delphi (y probablemente muchos otros idiomas) tiene ayudantes de clase. Estos proporcionan una manera de agregar métodos adicionales a una clase existente. Sin hacer una subclase.

Entonces, ¿cuáles son los buenos usos para los ayudantes de clase?

¿Fue útil?

Solución

Los estoy usando:

  • A inserte enumeradores en clases de VCL que no los implementen.
  • Para mejorar clases de VCL.
  • Para agregar métodos a la clase TStrings para que pueda usar los mismos métodos en mis listas derivadas y en 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 }
    
  • Para simplificar el acceso a los campos de registro y eliminar fundición .

Otros consejos

Al principio era un poco escéptico sobre los ayudantes de clase. Pero luego leí una interesante entrada de blog y ahora estoy convencido de que son realmente útiles.

Por ejemplo, si desea una funcionalidad adicional para una clase de instancia existente y por alguna razón no puede cambiar la fuente existente. Puede crear un ayudante de clase para agregar esta funcionalidad.

Ejemplo :

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

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

Cada vez, ahora usamos una instancia de (una subclase de) TStrings, y TStringsHelper está dentro del alcance. Tenemos acceso al método IsEmpty.

Ejemplo :

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

Notas :

  • Los ayudantes de clase se pueden almacenar en una unidad separada, por lo que puede agregar sus propios ayudantes de clase ingeniosos. Asegúrese de dar a estas unidades un nombre fácil de recordar como ClassesHelpers para ayudantes de la unidad Classes.
  • También hay ayudantes de grabación.
  • Si hay varios ayudantes de clase dentro del alcance, espere algunos problemas, solo se puede usar un ayudante.

Esto se parece mucho a los métodos de extensión en C # 3 (y VB9). El mejor uso que he visto para ellos es las extensiones de IEnumerable<T> (y IQueryable<T>) que permiten a LINQ trabajar contra secuencias arbitrarias:

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

(o lo que sea, por supuesto). Todo esto es factible porque los métodos de extensión le permiten encadenar efectivamente las llamadas a métodos estáticos que toman el mismo tipo cuando regresan.

Son muy útiles para complementos. Por ejemplo, supongamos que su proyecto define una determinada estructura de datos y se guarda en el disco de cierta manera. Pero luego, otro programa hace algo muy similar, pero el archivo de datos es diferente. Pero no desea inflar su EXE con un montón de código de importación para una función que muchos de sus usuarios no necesitarán usar. Puede usar un marco de plugins y poner a los importadores en un plugin que funcione así:

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

Y luego defina el convertidor. Una advertencia: una clase ayudante no es una clase amigo . Esta técnica solo funcionará si es posible configurar completamente un nuevo objeto TMyClass a través de sus métodos y propiedades públicas. Pero si puedes, funciona muy bien.

La primera vez que recuerdo haber experimentado lo que llamas " ayudantes de clase " fue mientras aprendía el Objetivo C. El cacao (marco del Objetivo C de Apple) usa lo que se llama " Categorías. "

Una categoría le permite ampliar una clase existente agregando sus propios métodos sin subclasificar. De hecho, Cocoa lo alienta a evitar subclases cuando sea posible. A menudo tiene sentido subclasificar, pero a menudo se puede evitar usando categorías.

Un buen ejemplo del uso de una categoría en Cocoa es lo que se llama " Código de valor clave (KVC) " y " Observación del valor clave (KVO). "

Este sistema se implementa utilizando dos categorías (NSKeyValueCoding y NSKeyValueObserving). Estas categorías definen e implementan métodos que se pueden agregar a cualquier clase que desee. Por ejemplo, Cocoa agrega & Quot; conformidad & Quot; a KVC / KVO utilizando estas categorías para agregar métodos a NSArray como:

- (id)valueForKey:(NSString *)key

La clase NSArray no tiene una declaración ni una implementación de este método. Sin embargo, a través del uso de la categoría. Puede llamar a ese método en cualquier clase de NSArray. No es necesario que subclasifique NSArray para obtener la conformidad KVC / KVO.

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

El uso de esta técnica hace que sea fácil agregar soporte KVC / KVO a sus propias clases. Las interfaces Java le permiten agregar declaraciones de métodos, pero las categorías también le permiten agregar las implementaciones reales a las clases existentes.

Como muestra GameCat, TStrings es un buen candidato para evitar escribir algo:

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;

¿Alguna vez necesitó acceder a cadenas de varias líneas en el 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;

No recomendaría usarlos, ya que leí este comentario:

  

" El mayor problema con la clase   ayudantes, desde el p.o.v de usarlos   en sus propias aplicaciones, es el hecho   que solo UN ayudante de clase para un determinado   la clase puede estar dentro del alcance en cualquier momento. "   ... " Es decir, si tienes dos ayudantes   en alcance, solo UNO será reconocido   por el compilador No obtendrás ninguna   advertencias o incluso pistas sobre cualquier otra   ayudantes que pueden estar ocultos. "

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

Los he visto utilizados para hacer que los métodos de clase disponibles sean consistentes en todas las clases: Agregar Abrir / Cerrar y Mostrar / Ocultar a todas las clases de un " tipo " en lugar de solo propiedades activas y visibles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top