我目前仍在使用 Delphi 2009,因此我想添加一些其他方法来扩展泛型类。这些在 Delphi 的新版本中应该同样有效。让我们看看添加一个会是什么样子ToArray
List 类的方法。
拦截器类
拦截器类是与其继承的类同名的类:
TList<T> = class(Generics.Collections.TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray;
end;
function TList<T>.ToArray: TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := Self[I];
end;
end;
请注意,您需要使用完全限定名称,Generics.Collections.TList<T>
作为祖先。否则你会得到E2086 Type '%s' is not completely defined
.
这种技术的优点是您的扩展大部分是透明的。您可以在使用原始 TList 的任何地方使用新 TList 的实例。
这种技术有两个缺点:
- 如果其他开发人员不知道您重新定义了熟悉的类,则可能会造成混乱。
- 它不能用于密封类。
通过仔细的单元命名并避免在与拦截器类相同的位置使用“原始”类,可以减轻这种混乱。在 Embarcadero 提供的 rtl/vcl 类中,密封类并不是什么大问题。我在整个源代码树中只找到了两个密封类:TGCHandleList(仅在现已不存在的Delphi.NET中使用)和TCharacter。不过,您可能会遇到第三方库的问题。
装饰器模式
装饰器模式允许您通过用继承其公共接口的另一个类包装它来动态扩展一个类:
TArrayDecorator<T> = class abstract(TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray; virtual; abstract;
end;
TArrayList<T> = class(TArrayDecorator<T>)
private
FList: TList<T>;
public
constructor Create(List: TList<T>);
function ToArray: TListDecorator<T>.TDynArray; override;
end;
function TMyList<T>.ToArray: TListDecorator<T>.TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := FList[I];
end;
end;
再次有优点和缺点。
优点
- 您可以推迟引入新功能,直到实际需要时再引入。需要将列表转储到数组中?构造一个新的 TArrayList,将任何 TList 或后代作为构造函数中的参数传递。完成后只需丢弃 TArrayList。
- 您可以创建额外的装饰器来添加更多功能并以不同的方式组合装饰器。您甚至可以使用它来模拟多重继承,尽管接口仍然更容易。
缺点
- 理解起来有点复杂。
- 将多个装饰器应用于一个对象可能会导致冗长的构造函数链。
- 与拦截器一样,您无法扩展密封类。
边注
所以看来,如果你想让一个类几乎不可能扩展,就让它成为一个密封的泛型类。那么类助手就无法触及它,也无法继承它。剩下的唯一选择就是包装它。