Próbuję znaleźć najlepszy sposób użycia wtrysku zależności dla jakiegoś starszego kodu, który zajmie dużo czasu refaktorowi i musi być wykonywany stopniowo. Większość starych klas użyć „dominująca” właściwość do określania różnych rzeczy i własnością rodzic często mijają się za pomocą argumentu konstruktora następująco:Wstrzyknięcie konstruktora kontra wstrzykiwanie ustawiające dla właściwości nadrzędnej
constructor TParentObject.Create;
begin
FChildObject := TChildObject.Create(Self);
end;
constructor TChildObject.Create(AParent: TParentObject)
begin
FParent := AParent;
end;
Jest to dość typowe dla naszej bazy kodu starszego typu. Jednak podczas przechodzenia do interfejsów i iniekcji konstruktora obiekt macierzysty nie jest znany w ramach Spring4D podczas tworzenia obiektu Child. Więc po prostu dostanie nowego rodzica, ale nie istniejącego. Oczywiście mogę utworzyć właściwość getter/setter, ale to wskazywałoby na "opcjonalną" właściwość klasy, która jest naprawdę obowiązkową własnością. Zobacz poniższy kod, aby uzyskać więcej wyjaśnień:
unit uInterfaces;
interface
uses
Spring.Collections;
type
IChildObject = interface;
IParentObject = interface
['{8EA8F9A2-E627-4546-8008-0A77DA2B16F1}']
function GetSomethingRequiredByChild: string;
procedure SetSomethingRequiredByChild(const Value: string);
property SomethingRequiredByChild: string read GetSomethingRequiredByChild write SetSomethingRequiredByChild;
function GetChild: IChildObject;
property Child: IChildObject read GetChild;
end;
// This introduces a property getter/setter
// However it also implies that Parent can be NIL which it cannot
IChildObject = interface
['{ECCA09A6-4A52-4BE4-A72E-2801160A9086}']
function GetParent: IParentObject;
procedure SetParent(const Value: IParentObject);
property Parent: IParentObject read GetParent write SetParent;
end;
TParentObject = class(TInterfacedObject, IParentObject)
private
FChild: IChildObject;
FSomethingRequiredByChild: string;
function GetChild: IChildObject;
function GetSomethingRequiredByChild: string;
procedure SetSomethingRequiredByChild(const Value: string);
public
constructor Create;
end;
TChildObject = class(TInterfacedObject, IChildObject)
private
FParent: IParentObject;
function GetParent: IParentObject;
procedure SetParent(const Value: IParentObject);
public
// This requries a Parent object, but how does the Spring4D resolve the correct parent?
constructor Create(const AParent: IParentObject);
end;
implementation
uses
Spring.Services;
{ TParentObject }
constructor TParentObject.Create;
begin
// Here is the old way...
FChild := TChildObject.Create(Self); // Old way of doing it
// This is the Service Locator way...
FChild := ServiceLocator.GetService<IChildObject>;
// I would prefer that the Parent is assigned somehow by the Service Locator
// IS THIS POSSIBLE - or am I dreaming?
FChild.Parent := Self;
end;
function TParentObject.GetChild: IChildObject;
begin
Result := FChild;
end;
function TParentObject.GetSomethingRequiredByChild: string;
begin
Result := FSomethingRequiredByChild;
end;
procedure TParentObject.SetSomethingRequiredByChild(const Value: string);
begin
FSomethingRequiredByChild := Value;
end;
{ TChildObject }
constructor TChildObject.Create(const AParent: IParentObject);
begin
FParent := AParent;
end;
function TChildObject.GetParent: IParentObject;
begin
Result := FParent;
end;
procedure TChildObject.SetParent(const Value: IParentObject);
begin
FParent := Value;
end;
end.
Może jest jakaś metoda, która może być używana, że nie jestem świadomy, aby ustawić obiektu nadrzędnego za pomocą ramy DI?
Mam nadzieję, że to pytanie jest jasne, co staram się osiągnąć. W razie potrzeby chętnie podam więcej opisu/kodu.
Byłoby interesujące zobaczyć kod, który faktycznie "tworzy" obiekty podrzędne. Czuję lokator usług. –
Haha Stefan, rzeczywiście masz rację, tego właśnie zamierzałem użyć, ale zastanawiałem się, czy istnieje alternatywa? Teraz opublikuję kod. –
Moje pytanie brzmi: dlaczego uważasz, że jest to lepsze niż bezpośrednie wywoływanie konstruktora obiektu TChildObject w obiekcie TParentObject? Domyślam się, że prawdziwy kod jest nieco bardziej złożony, ale nadal: jeśli masz relację rodzic/dziecko, klasy mogą się nawzajem znać. Jeśli tak nie jest, sugerowałbym użycie wzorca fabrycznego. Zostanie opublikowany kod. –