Właściwa architektura

0

Heja. Mam takie klasy:

class A{
    public void go() {}
}

class B{
    A a;

    public B(A a) {
        this.a = a;
    }

    void doIt(){
        a.go();
    }
}

class B2{
    A a;

    public B2() {
        this.a = new A();
    }

    void doIt(){
        a.go();
    }
}

class B3{
    public B3() {}

    void doIt(){
        A a = new A();
        a.go();
    }
}

Zastanawia mnie czy z punktu widzenia ogólnie rozumianej poprawności architektury tylko klasa B jest właściwym wariantem, a klas typu B2 i B3 nie powinno się tworzyć?

0

Z punktu widzenia ogólnie rozumianej poprawności powyższy kod nic nie robi, więc nie powinien istnieć :)

1
  1. Kod nic sensownego nie przedstawia.
  2. Architektura nijak się ma, według mnie, do powyższego przykładu. IMHO o architekturze zaczyna się mówić w chwili gdy pada pytanie: "jak zorganizować pakiety w projekcie?"
  3. Jakbym miał wskazać błędy w kodzie to powiedziałbym że klasa B2 nie powinna używać operatora new wewnątrz konstruktora - sama sobie tworzyć zależności tylko otrzymywać je z zewnątrz.
0

Nie wiem co ten kod ma robić i w jakim celu, to ciężko się wypowiadać, ale z punktu widzenia logiki, wolałbm mieć w kodzie klasę B, której przekazuję referencję do obiektu (co jest w Javie tanie), a nie mieć konstruktory z "side efects".

0

Ok, nie chciałem się wdawać tak mocno w szczegóły. Powiedzmy, że dochodzę do wariantu B3 i zastanawia mnie czy on nie jest kupowaty i czy nie powinienem zawsze dążyć do wstrzyknięcia zależności z zewnątrz.

Edit: Eh... Naczytałem się o dobrych praktykach, o wstrzykiwaniu zależności i zgłupiałem. Tak jak teraz patrzę to B2 jest właściwie zwykłą kompozycją, a i B3 też jakby taką bardziej lokalną. Istnieje jakaś ogólna zasada, że któregoś z tych sposobów nie powinienem nigdy używać?

0

Wstrzykiwanie zależności masz tylko w klasie B. B2 jest przykładem jak nie należy robić. B3 z wstrzykiwanie zależności wygląda np tak:

class B4 {
    private FactoryOfA factory;
    public B3(FactoryOfA factory) {
        this.factory = factory;
    }

    void doIt(){
        A a = factory.newInstanceA();
        a.go();
    }
}
5

Wszystkie wzorce B, B2 i B3 są poprawne i stosowane (oczywiście pomijając, że kod powyżej nic nie robi i ma metody void).

Nie wszędzie należy wstrzykiwać, zależy co jest tą zależnością.
Żeby się przekonać - zamieńcie klasę A na ArrayList<...> i zobaczcie ile razy macie tworzone przez new w konstruktorze, ile razy na polu, a ile razy przez new w metodzie.
(oczywiście ćwiczenie nie dotyczy programistów, którzy już nie używają java.util)

0

Kto powinien tworzyć instancję A? Mogą pomóc zasady GRASP, a konkretnie wzorzec Creator. Zgodnie z nim, kandydatem, który będzie miał odpowiedzialność tworzenia instancji klasy może być:
1) ten kto mocno (kompozycja) lub słabo (agregacja) przechowuje obiekty klasy A
2) ten kto wie jak utworzyć obiekt (ma niezbędne informacje, np. kolor guzika, wiek etc.)
3) ten kto często używa takich obiektów
4) coś czego nie do końca rozumiem w GRASP (w oryginale chodzi o to, że B jest kandydatem do tworzenia instancji A, jeśli "B records A"), ale tłumaczę sobie, że chodzi o odkładanie historii/emitowanie zdarzeń, ale nie mam pewności czy taki w oryginale był zamysł...

Jeśli jest więcej niż jeden kandydat, to preferowany jest ten z 1).

Twój przykład jest bardzo prosty i każdą z wersji można obronić. W B3, biznesowo może być uzasadnione użycie nowej instancji obiektu, np. prezerwatywy, strzykawki, nowego pliku tymczasowego. Niektórzy mogą upierać się na re-użycie i mieć jakieś ważne powody, ale to już kwestia kontekstu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0