Jak na mój gust, iniekcja w polu to trochę zbyt „upiorna akcja na odległość” .
Rozważ przykład podany w poście w Grupach dyskusyjnych Google:
public class VeracodeServiceImplTest {
@Tested(fullyInitialized=true)
VeracodeServiceImpl veracodeService;
@Tested(fullyInitialized=true, availableDuringSetup=true)
VeracodeRepositoryImpl veracodeRepository;
@Injectable private ResultsAPIWrapper resultsApiWrapper;
@Injectable private AdminAPIWrapper adminApiWrapper;
@Injectable private UploadAPIWrapper uploadApiWrapper;
@Injectable private MitigationAPIWrapper mitigationApiWrapper;
static { VeracodeRepositoryImpl.class.getName(); }
...
}
Więc w zasadzie mówisz, że „Mam tę klasę z państwem prywatnym, do której załączyłem @injectable
adnotacje, co oznacza, że państwo może zostać automatycznie zaludnione przez jakiegoś agenta z zewnątrz, mimo że mój stan został uznany za prywatny. „
Rozumiem motywacje do tego. Jest to próba uniknięcia dużej części ceremonii, która jest nieodłącznie związana z prawidłowym zorganizowaniem klasy. Zasadniczo chodzi o to, że „jestem zmęczony pisaniem całego tego bojlera, więc po prostu opiszę cały mój stan i pozwól pojemnikowi DI zająć się ustawieniem go dla mnie”.
To całkowicie poprawny punkt widzenia. Ale jest to również obejście funkcji językowych, które prawdopodobnie nie powinny być omijane. A po co się tu zatrzymywać? Tradycyjnie DI opierał się na każdej klasie posiadającej interfejs towarzyszący. Dlaczego nie wyeliminować również wszystkich tych interfejsów z adnotacjami?
Rozważ alternatywną opcję (będzie to C #, ponieważ znam ją lepiej, ale prawdopodobnie jest to dokładny odpowiednik w Javie):
public class VeracodeService
{
private readonly IResultsAPIWrapper _resultsApiWrapper;
private readonly IAdminAPIWrapper _adminApiWrapper;
private readonly IUploadAPIWrapper _uploadApiWrapper;
private readonly IMitigationAPIWrapper _mitigationApiWrapper;
// Constructor
public VeracodeService(IResultsAPIWrapper resultsApiWrapper, IAdminAPIWrapper adminApiWrapper, IUploadAPIWrapper uploadApiWrapper, IMitigationAPIWrapper mitigationApiWrapper)
{
_resultsAPIWrapper = resultsAPIWrapper;
_adminAPIWrapper = adminAPIWrapper;
_uploadAPIWrapper = uploadAPIWrapper;
_mitigationAPIWrapper = mitigationAPIWrapper;
}
}
Już wiem kilka rzeczy na temat tej klasy. To niezmienna klasa; stan można ustawić tylko w konstruktorze (w tym konkretnym przypadku odwołania). A ponieważ wszystko wywodzi się z interfejsu, mogę wymieniać implementacje w konstruktorze, czyli tam, gdzie przychodzą twoje symulacje.
Teraz wszystko, co musi zrobić mój kontener DI, to zastanowienie się nad konstruktorem, aby określić, jakie obiekty będą potrzebne do nowego. Ale ta refleksja odbywa się na członku publicznym, w pierwszej kolejności; tzn. metadane są już częścią klasy, ponieważ zostały zadeklarowane w konstruktorze, metodzie, której wyraźnym celem jest zapewnienie klasie potrzebnych zależności.
Przyznaję, że jest to duży bojler, ale tak właśnie zaprojektowano język. Adnotacje wyglądają jak brudny hack do czegoś, co powinno być wbudowane w sam język.