题
德尔斐(并可能是一个很大的其他语言)具有类佣工。这些提供一种方法来增加额外的方法,以现有类。没有做一个子类。
那么,什么是良好的用途类帮手?
解决方案
我使用它们:
- 要 插入调查员 成VCL类不执行它们。
- 要 增强 VCL课程。
添加的方法TStrings类的所以我可以使用同样的方法 我列出来 在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 }
为了简化出入记录和领域 删除铸件.
其他提示
在第一次我是那种怀疑论者关于类佣工。但之后我读了一个有趣的 博客入口 现在我相信他们确实是有用的。
例如,如果你想要额外的功能,对现有实例类和由于某种原因你不能改变现有的来源。你可以创建一个类帮助中添加这种功能。
例如:
type
TStringsHelper = class helper for TStrings
public
function IsEmpty: Boolean;
end;
function TStringsHelper.IsEmpty: Boolean;
begin
Result := Count = 0;
end;
每一次,我们现在使用的一个实例(子类)TStrings,并TStringsHelper是范围之内。我们访问的方法为空.
例如:
procedure TForm1.Button1Click(Sender: TObject);
begin
if Memo1.Lines.IsEmpty then
Button1.Caption := 'Empty'
else
Button1.Caption := 'Filled';
end;
注:
- 类佣工可存储在一个单独的单元,所以你可以添加自己漂亮的类佣工。一定要给这些单位的一个容易记住的名字就像ClassesHelpers用于佣工的课程单元。
- 还有记录的佣工。
- 如果有多个类佣工的范围内,预计一些问题,只有一个帮手可以使用。
这听起来非常像C#3(和VB9)中的扩展方法。我见过的最好的用途是IEnumerable<T>
(和IQueryable<T>
)的扩展,它允许LINQ对任意序列起作用:
var query = someOriginalSequence.Where(person => person.Age > 18)
.OrderBy(person => person.Name)
.Select(person => person.Job);
(当然还是其他什么)。所有这一切都是可行的,因为扩展方法允许您有效地将对静态方法的调用链接在一起,这些方法采用与返回时相同的类型。
它们对插件非常有用。例如,假设您的项目定义了某个数据结构,并以某种方式保存到光盘。但是其他一些程序做的事情非常相似,但数据文件不同。但是,您不希望使用大量导入代码来膨胀您的EXE以获得许多用户不需要使用的功能。您可以使用插件框架并将导入程序放入一个可以像这样工作的插件:
type
TCompetitionToMyClass = class helper for TMyClass
public
constructor Convert(base: TCompetition);
end;
然后定义转换器。一个警告:类帮助不是类朋友。只有在可以通过其公共方法和属性完全设置新的TMyClass对象时,此技术才有效。但如果可以的话,它的效果非常好。
我第一次记得遇到你正在呼唤的东西<!>“;帮助者<!>”;在学习Objective C时,Cocoa(Apple的Objective C框架)使用了所谓的<!> quot; Categories。<!>;
类别允许您通过添加自己的方法来扩展现有类,而无需子类化。事实上,Cocoa鼓励你尽可能避免使用子类化。通常,子类是有意义的,但通常可以使用类别来避免。
在Cocoa中使用类别的一个很好的例子是所谓的<!>“键值代码(KVC)<!>”;和<!>“键值观察(KVO)。<!>
该系统使用两个类别(NSKeyValueCoding和NSKeyValueObserving)实现。这些类别定义并实现可添加到所需类的方法。例如,Cocoa添加<!> quot; conformance <!> quot;使用这些类别向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接口允许您添加方法声明,但类别允许您还将实际实现添加到现有类。
正如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;
我不建议使用它们,因为我读了这个评论:
<!>“;班级最大的问题 帮助者,从p.o.v使用它们 在你自己的应用程序中,是事实 对于给定的只有一个类助手 类可以在任何时候在范围内。<!> quot; ...... <!>;也就是说,如果你有两个助手 在范围内,只有一个将被识别 由编译器。你不会得到任何 关于任何其他的警告甚至提示 可能隐藏的助手。<!>
http://davidglassborow.blogspot.com /2006/05/class-helpers-good-or-bad.html
我已经看到它们用于在类之间建立一致的类方法:向给定<!>的所有类添加打开/关闭和显示/隐藏;类型<!>而不仅仅是Active和Visible属性。