Delphi(可能还有许多其他语言)都有类助手。这些提供了一种向现有类添加额外方法的方法。没有制作子类。
那么,班主任的好用途是什么?
答案 0 :(得分:33)
我正在使用它们:
要向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;
备注:强>
答案 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)
我已经看到它们用于使各种类的可用类方法一致:向给定“类型”的所有类添加打开/关闭和显示/隐藏,而不仅仅是活动和可见属性。