2013-08-25 24 views
12

Czy dobrą praktyką jest stosowanie wzoru Odbicie w fabryce?Korzystanie z odbicia w fabrycznym wzorze

public class MyObjectFactory{ 
private Party party; 

public Party getObject(String fullyqualifiedPath) 
{ 
    Class c = Class.forName(fullyqualifiedPath); 
    party = (PersonalParty)c.newInstance(); 
    return party; 
} 
} 

PersonalParty realizuje Party

+1

Czy jest to przydatny przypadek. Ogólnie rzecz biorąc, rozważałbym refleksję jako moją ostatnią deskę ratunku. Specjalnie do tego celu. –

+0

Co ze strukturami takimi jak JSf2.0, które używa adnotacji? Powinny używać interfejsów API Reflection do tworzenia instancji obiektu w czasie wykonywania? – Ullas

+1

Jeśli chodzi o JSF, to oznacz to jako tak. –

Odpowiedz

9

Celem wzoru fabrycznego jest de-para jakiś kod typu run-time obiektu to konsumuje:

// This code doesn't need to know that the factory is returning 
// an object of type `com.example.parties.SurpriseParty` 
AbstractParty myParty = new PartyFactory().create(...); 

Korzystanie kod jak tego, PartyFactory jest wyłącznie odpowiedzialny za ustalenie lub dokładne określenie, jaki typ programu powinien być używany.

Zaspokajasz to świadczenie, przekazując w pełni kwalifikowaną nazwę klasy, której potrzebujesz. Jak to ...

// This code obviously DOES know that the factory is returning 
// an object of type `com.example.parties.SurpriseParty`. 
// Now only the compiler doesn't know or enforce that relationship. 
AbstractParty myParty = new PartyFactory().create("com.example.parties.SurpriseParty"); 

... każdy różni się od po prostu deklarując myParty jako typu com.example.parties.SurpriseParty? Na koniec twój kod jest tak samo sprzężony, ale zrezygnowałeś ze statycznej weryfikacji typu. Oznacza to, że ponosisz mniej niż żadna korzyść, podczas gdy niektóre korzyści z Javy są ściśle pisane. Jeśli usuniesz kod com.example.parties.SurpriseParty, twój kod się skompiluje, twój IDE nie dostarczy żadnych komunikatów o błędach i nie zdasz sobie sprawy, że istnieje związek między tym kodem a com.example.parties.SurpriseParty do czasu uruchomienia - to jest złe.

Przynajmniej, radzę ci przynajmniej zmienić ten kod tak argumentem tejże metody jest prosta nazwa klasy, a nie w pełni kwalifikowana nazwa:

// I took the liberty of renaming this class and it's only method 
public class MyPartyFactory{ 

    public Party create(String name) 
    { 
     //TODO: sanitize `name` - check it contains no `.` characters 
     Class c = Class.forName("com.example.parties."+name); 
     // I'm going to take for granted that I don't have to explain how or why `party` shouldn't be an instance variable. 
     Party party = (PersonalParty)c.newInstance(); 
     return party; 
    } 
} 

Następny: to jest złą praktyką użyć Class.forName(...)? To zależy od tego, czym jest alternatywa, i relacji między argumentami String a klasami, które zapewni ta fabryka. Jeśli alternatywą jest duży warunek:

if("SurpriseParty".equals(name) { 
    return new com.example.parties.SurpriseParty(); 
} 
else if("GoodbyeParty".equals(name)) { 
    return new com.example.parties.GoodbyeParty(); 
} 
else if("PartyOfFive".equals(name)) { 
    return new com.example.parties.PartyOfFive(); 
} 
else if(/* ... */) { 
    // ... 
} 
// etc, etc etc 

... to nie jest skalowalne. Ponieważ istnieje wyraźna obserwowalna zależność między nazwami typów wykonawczych tworzonych przez tę fabrykę a wartością argumentu name, należy rozważyć użycie wartości Class.forName. W ten sposób Twój obiekt Factory jest chroniony przed zmianą kodu za każdym razem, gdy dodajesz nowy system Party.


Zamiast tego można rozważyć użycie wzoru AbstractFactory. Jeśli kod spożywania wygląda następująco:

AbstractParty sParty = new PartyFactory().create("SurpriseParty"); 
AbstractParty gbParty = new PartyFactory().create("GoodByeParty"); 

... gdzie istnieje ograniczona liczba często występujących typów stron, które wnioskowano, należy rozważyć różne metody dla tych różnych typów stron:

public class PartyFactory { 

    public Party getSurpriseParty() { ... } 
    public Party getGoodByeParty() { ... } 

} 

...co pozwoli ci wykorzystać statyczne pisanie Java.

To rozwiązanie oznacza jednak, że za każdym razem, gdy dodajesz nowy typ Party, musisz zmienić obiekt fabryczny - tak, czy rozwiązanie odblaskowe, czy AbstractFactory jest lepszym rozwiązaniem, naprawdę zależy od tego, jak często i jak szybko Będą dodawać typy Party. Nowy typ każdego dnia? Użyj refleksji. Nowy typ imprezy co dekadę? Użyj AbstractFactory.

+0

Dzięki za szczegółowe wyjaśnienie Sir .. – Ullas

+0

@Ullas - Moja przyjemność. Dodano jeszcze jeden akapit podkreślający, kiedy powinieneś użyć rozwiązania refleksyjnego, a kiedy powinieneś użyć 'AsbtractFactory'. –

1

Korzystanie odbicie to w ten sposób (Class.forName) jest prawie zawsze oznaką złego projektowania aplikacji. Istnieje kilka rodzajów, w których jego użycie jest OK, na przykład, jeśli robisz jakiś dynamiczny ładunek zewnętrznych bibliotek lub wtyczek.

1

Można go użyć do interfejsu API, w którym podaje się interfejs API i plik konfiguracyjny XML, w którym użytkownicy mogą dodawać nazwy klas swoich wtyczek. Następnie, tak, można użyć tego