私は、それぞれの実装者クラスで抽象クラス参照を保持する TDictionary に基づいて、単純な依存性注入/制御システムの反転を書いています。
私の目標は次のとおりです。
- タイプによる直接のインスタンス化は避けてください (明らかに)。
- クラスのユニットを dpr に含めるだけで、それが登録され、di/ioc システムを介して選択およびインスタンス化できるようになります。
- 実装セクションでのみ具体的な実装クラスを宣言します。
- 初期化セクションの代わりにクラス コンストラクターを使用します。
ところで、クラス コンストラクターを使用してスマート リンクを利用することと、クラスを利用可能にするためにユニットを含めるだけで十分であることは、互いに打ち負かしていることを認識しています。他の理由でも、初期化セクションの代わりにクラス コンストラクターを使用したいと考えています。また、クラス コンストラクターと初期化セクションに分割するのではなく、すべてのクラスの初期化/登録コードをまとめておきたいと考えています。
問題
ファクトリへのクラスの登録は、クラス コンストラクターで行う必要があります。残念ながら、コンパイラは、独自のクラス コンストラクターでその型を使用するだけでは、クラスが "変更" されているとは見なしません。
登録関数を初期化セクションに入れると、コンパイラはクラスが変更されたと判断し、クラス コンストラクターを呼び出します。しかし、それは、すべてのクラス初期化コードをクラス コンストラクターに保持するという私の演習の目的を無効にします。
2 つの質問
- コンパイラーは、独自のクラスコンストラクターでのクラスの使用を「クラスに触れる」と見なすべきですか、それともコンパイラーが行うことを期待するには多すぎますか?
- 初期化セクションを使用せずに目標を達成する方法について、賢いアイデアを持っている人はいますか?
例
アプリケーションで使用される抽象クラス:
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で入手できます。
zip の内容:
- 4 つのプロジェクトはすべて同じソース ファイルを使用し、条件定義のみが異なります (そのため、dproj も含まれています)
- 4 つのソース ファイル
- groupproj とその dsk と 4 つのプロジェクトすべて
- 4 つのプロジェクトすべてを実行する RunTestApps.cmd
- RunTestApps.cmd の実行結果を含む Results.txt
- この質問のテキストを含む WriteUp.txt
すべての dcu と exe がソース ディレクトリに移動するため、常に "Build All Projects" を実行する必要があることに注意してください。そうしないと、多くのエラーや混乱に直面することになります。その名前が示すことを行います。