课堂助手有什么好处?

时间:2008-10-31 13:07:06

标签: delphi class helper

Delphi(可能还有许多其他语言)都有类助手。这些提供了一种向现有类添加额外方法的方法。没有制作子类。

那么,班主任的好用途是什么?

8 个答案:

答案 0 :(得分:33)

我正在使用它们:

  • insert enumerators转换为未实现它们的VCL类。
  • enhance VCL课程。
  • 要向TStrings类添加方法,以便在my derived lists和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 }
    
  • 简化对记录字段和remove casting的访问。

答案 1 :(得分:13)

起初我对班主任持怀疑态度。但后来我读了一篇有趣的blog entry,现在我确信它们确实很有用。

例如,如果您想要现有实例类的额外功能,并且由于某种原因您无法更改现有源。您可以创建一个类助手来添加此功能。

示例:

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;

备注:

  • 类助手可以存储在一个单独的单元中,因此您可以添加自己漂亮的类助手。请务必为这些单元提供一个易于记忆的名称,例如ClassesHelpers,用于Classes单元的帮助程序。
  • 还有记录助手。
  • 如果范围内有多个类助手,可能会遇到一些问题,只能使用一个助手。

答案 2 :(得分:6)

这听起来非常像C#3(和VB9)中的扩展方法。我见过的最好的用法是IEnumerable<T>(和IQueryable<T>)的扩展,它允许LINQ对任意序列起作用:

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

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

答案 3 :(得分:4)

它们对插件非常有用。例如,假设您的项目定义了某个数据结构,并以某种方式保存到光盘。但是其他一些程序做的事情非常相似,但数据文件不同。但是,您不希望使用大量导入代码来膨胀您的EXE以获得许多用户不需要使用的功能。您可以使用插件框架并将导入程序放入一个可以像这样工作的插件:

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

然后定义转换器。一个警告:类帮助不是类朋友。只有在可以通过其公共方法和属性完全设置新的TMyClass对象时,此技术才有效。但如果可以的话,它的效果非常好。

答案 4 :(得分:3)

我第一次记得在学习Objective C时遇到你所谓的“课堂助手”.Cocoa(Apple的Objective C框架)使用所谓的“类别”。

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

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

该系统使用两个类别(NSKeyValueCoding和NSKeyValueObserving)实现。这些类别定义并实现可添加到所需类的方法。例如,Cocoa通过使用这些类别向NSArray添加方法来为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接口允许您添加方法声明,但类别允许您还将实际实现添加到现有类。

答案 5 :(得分:3)

正如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;

答案 6 :(得分:2)

我不建议使用它们,因为我读了这个评论:

  

“课堂上最大的问题   帮助者,从p.o.v使用它们   在你自己的应用程序中,是事实   对于给定的只有一个类助手   班级可能随时都在范围内。“   ......“也就是说,如果你有两个帮手   在范围内,只有一个将被识别   由编译器。你不会得到任何   关于任何其他的警告甚至提示   可能隐藏的助手。“

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

答案 7 :(得分:0)

我已经看到它们用于使各种类的可用类方法一致:向给定“类型”的所有类添加打开/关闭和显示/隐藏,而不仅仅是活动和可见属性。