代码之家  ›  专栏  ›  技术社区  ›  Toon Krijthe

班级帮手的好用途是什么?

  •  33
  • Toon Krijthe  · 技术社区  · 16 年前

    Delphi(可能还有很多其他语言)有类助手。它们提供了向现有类添加额外方法的方法。没有生成子类。

    那么,班级帮手有什么好的用途呢?

    8 回复  |  直到 13 年前
        1
  •  34
  •   gabr    16 年前

    我正在使用它们:

    • insert enumerators
    • enhance VCL课程。
    • 向TStrings类添加方法,以便在中使用相同的方法 my derived lists 用英语说。

      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 }
      
    • 简化对记录字段和 remove casting .

        2
  •  14
  •   Toon Krijthe    12 年前

    blog entry 现在我确信它们确实有用。

    例如,如果您希望现有实例类具有额外的功能,并且由于某种原因无法更改现有源。您可以创建类帮助器来添加此功能。

    例子:

    type
      TStringsHelper = class helper for TStrings
      public
        function IsEmpty: Boolean;
      end;
    
    function TStringsHelper.IsEmpty: Boolean;
    begin
      Result := Count = 0;
    end;
    

    例子:

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

    笔记:

    • 类助手可以存储在单独的单元中,因此您可以添加自己的漂亮类助手。一定要给这些单元起一个容易记住的名字,比如ClassesHelpers for helpers for the Classes unit。
    • 如果范围内有多个类帮助器,则可能会出现一些问题,只能使用一个帮助器。
        3
  •  6
  •   Jon Skeet    16 年前

    这听起来很像C#3(和VB9)中的扩展方法。我所看到的对它们的最佳使用是对 IEnumerable<T> IQueryable<T>

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

    (当然,还是随便什么)。所有这些都是可行的,因为扩展方法允许您有效地将对静态方法的调用链接在一起,这些静态方法在返回时采用相同的类型。

        4
  •  4
  •   Mason Wheeler    16 年前

    它们对于插件非常有用。例如,假设您的项目定义了特定的数据结构,并以特定的方式保存到光盘中。但是其他一些程序做了一些非常相似的事情,但是数据文件不同。但是你不想用一堆导入代码来膨胀你的EXE,因为你的很多用户都不需要使用这个功能。您可以使用插件框架并将导入程序放入一个插件中,该插件的工作方式如下:

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

    然后定义转换器。一个警告:一个类 这不是一门课 朋友 . 只有在可以通过其公共方法和属性完全设置新的TMyClass对象的情况下,这种技术才会起作用。但如果可以,它的效果非常好。

        5
  •  3
  •   Robert Walker    16 年前

    我记得第一次体验你所谓的“类助手”是在学习Objective C时。Cocoa(苹果的Objective C框架)使用了所谓的“类别”

    类别允许您通过添加自己的方法来扩展现有类,而无需子类化。事实上,Cocoa鼓励您尽可能避免子类化。子类化通常是有意义的,但通常可以避免使用类别。

    Cocoa中使用类别的一个很好的例子是所谓的“键值代码(KVC)”和“键值观察(KVO)”

    - (id)valueForKey:(NSString *)key
    

    NSArray类既没有此方法的声明,也没有此方法的实现。但是,通过使用类别。您可以在任何NSArray类上调用该方法。您不需要子类NSArray来获得KVC/KVO一致性。

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

    使用此技术可以很容易地将KVC/KVO支持添加到您自己的类中。Java接口允许您添加方法声明,但类别也允许您将实际实现添加到现有类中。

        6
  •  3
  •   Uwe Raabe    16 年前

    正如GameCat所示,Tstring是避免某些键入的一个很好的选择:

    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;
    
        7
  •  2
  •   mjn anonym    15 年前

    我不建议使用它们,因为我阅读了以下评论:

    “课堂上最大的问题 在您自己的应用程序中,这是事实吗 类可能随时在范围内。” ... “也就是说,如果你有两个助手 在范围内,只有一个将被认可 警告,甚至关于任何其他的提示

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

        8
  •  0
  •   Jamo    16 年前

    我见过它们用于使可用的类方法在类之间保持一致:将打开/关闭和显示/隐藏添加到给定“类型”的所有类,而不仅仅是活动的和可见的属性。