我正在编写一个基于 TDictionary 的简单依赖注入/控制系统反转,该 TDictionary 持有抽象类引用及其各自的实现类。
我的目标是:
- 避免按类型直接实例化(显然)。
- 在 dpr 中包含一个类的单元应该足以让它注册并可以通过 di/ioc 系统进行选择和实例化。
- 仅在实现部分声明具体的实现类。
- 使用类构造函数而不是初始化部分。
顺便说一句,我知道使用类构造函数来利用智能链接并希望包含一个足以使类可用的单元正在互相击败。出于其他原因,我也想使用类构造函数而不是初始化部分。而且我想将所有类初始化/注册代码放在一起,而不必在类构造函数和初始化部分之间拆分它。
问题
我希望将类注册到工厂中以在类构造函数中。不幸的是,编译器并不认为仅通过在其自己的类构造函数中使用其类型来“触及”该类。
当我将注册函数放在初始化部分时,编译器确实认为该类被触摸并调用类构造函数。但这违背了我将所有类初始化代码保留在类构造函数中的练习目标。
两个问题
- 编译器是否应该考虑在其自己的类构造函数中使用该类“接触类”,还是期望编译器做太多?
- 是否有人对我如何在不使用初始化部分的情况下仍然实现目标有任何聪明的想法?
例子
应用程序中使用的抽象类:
TSite = class abstract (TObject)
function GetURL: string; virtual; abstract;
property URL: string read GetURL;
end;
TSites = class (TList<TSite>);
TThisApplication = class abstract (TObject)
function Sites: TSites; virtual; abstract;
end;
TThisApplication 的具体实现类(在实现部分声明!)
TThisApplicationConcrete = class(TThisApplication)
class constructor ClassCreate;
strict private
FSites: TSites;
function Sites: TSites; override;
end;
class constructor TThisApplicationConcrete.ClassCreate;
begin
RegisterImplementorClass(TThisApplication, TThisApplicationConcrete);
end;
function TThisApplicationConcrete.Sites: TSites;
var
SiteList: TSites;
begin
if not Assigned(FSites) then begin
SiteList := TSites.Create; // Change to use factory
//RetrieveSites(SiteList);
FSites := SiteList;
end;
Result := FSites;
end;
获取 TThisApplication 实例的函数:
function ThisApplication: TThisApplication;
var
ImplementorClass: TClass;
begin
ImplementorClass := GetImplementorClass(TThisApplication);
if Assigned(ImplementorClass) then begin
Result := ImplementorClass.Create as TThisApplication;
end else begin
Result := nil;
end;
end;
这目前被编码在一个单独的函数中,但它可以移动到工厂。
完整的示例代码
如果有人想试验,我有我的测试项目的完整代码:http ://www.bjsoftware.com/delphistuff/stackoverdlow/classconstructors.zip
邮编内容:
- 4 个项目都使用相同的源文件,仅在条件定义上有所不同(这就是为什么还包括 dproj 的原因)
- 4个源文件
- groupproj 及其 dsk 与所有 4 个项目
- RunTestApps.cmd 运行所有 4 个项目
- Results.txt 与我运行 RunTestApps.cmd 的输出
- WriteUp.txt 与此问题的文本
请记住,在任何时候您都需要执行“构建所有项目”,因为所有 dcu 和 exe 都将进入源目录,否则您将面临很多错误和/或混淆,因为 exe 不是做它的名字所表明的。