2009-07-30 11 views
6

Lepiej wyjaśnij pytanie na przykładzie. Mam Model interfejsu, który może być używany do uzyskiwania dostępu do danych. Mogą istnieć różne implementacje Modelu, który może reprezentować dane w różnych formatach, np. XMl, format txt itp. Model nie dotyczy formatów. Powiedzmy, że jedną z takich implementacji jest myxmlModel.Siła Singleton Pattern na klasie implementującej interfejs

Teraz chcę zmusić myxmlModel i każdą inną realizację Modelu podążać Singleton .Powierzchnia Zwykłym sposobem jest, aby myxmlModels konstruktor prywatne i zapewniają metody statycznej fabryki powrotu wystąpienie myModel class.But problem jest interfejs nie może mieć statyczne definicje sposób i wynik nie mogę wymusić konkretną definicję metody fabryki na wszystkich realizacji modelu. Tak więc jedna implementacja może kończyć się dostarczaniem getObject(), a inne mogą mieć NewModel()..

Jedna praca całego pakietu jest umożliwienie dostępu do konstruktora myxmlModel i utworzyć klasę fabryki, która tworzy myxmlModel obiekt i buforować go do dalszego wykorzystania.

Zastanawiam się, czy istnieje lepszy sposób na osiągnięcie tej samej funkcjonalności.

Odpowiedz

0

Czy możesz zmienić interfejs, aby był klasą abstrakcyjną? Umożliwi to wymuszenie określonej metody fabryki na wszystkie klasy implementacji.

+0

Próbowałem, że klasa .Abstract nie zadziała – Duleb

+1

Polimorfizm nie zadziała w przypadku metody statycznej. Sprawdź, czy masz metodę statyczną w klasie abstrakcyjnej i nadpisujesz ją w podklasie, a jeśli spróbujesz uzyskać dostęp do tej metody, oryginalna nazwa nie będzie nazywana metodą podklasy. – Duleb

+0

Ahhh, oczywiście, przepraszam za to. – Steven

4
  1. Utwórz fabrykę, która zwraca instancje interfejsu , Model.
  2. Wykonaj wszystkie konkretne implementacje pakietu modelu - prywatne klasy w tym samym pakiecie, co fabryka.
  3. Jeśli model ma być singletonem i używasz java 5+, użyj enum zamiast tradycyjnego singleton, ponieważ jest bezpieczniejszy.
public enum MyXMLModel{ 
INSTANCE(); 
//rest of class 
}; 

EDIT: Inną możliwością jest utworzenie klas delegata, że ​​nie wszystkie prace, a następnie użyć enum dostarczenie wszystkich opcji modelu.

na przykład:

class MyXMLModelDelegate implements Model { 
public void foo() { /*does foo*/} 
... 
} 

class MyJSONModelDelegate implements Model { 
public void foo() { /*does foo*/ } 
... 
} 

public enum Models { 
XML(new MyXMLModelDelgate()), 
JSON(new MyJSONModelDelegate()); 

private Model delegate; 
public Models(Model delegate) { this.delegate=delegate; } 

public void foo() { delegate.foo(); } 
} 
+0

Fabryka jest w porządku.Ale jestem ciekawa, czy tę samą funkcjonalność można osiągnąć bez Fabryki. – Duleb

+0

Pracuję nad eclipse. Interfejs modelu jest umową na punkt rozszerzenia. Wdrożenie modelu to rozszerzenie. Więc muszę odsłonić myxmlModel.Jeśli odsłonię niektóre klasy Factory, ponieważ nie donot modelu narzędzia, umowa nie powiedzie się. – Duleb

0

kiedyś zadać sobie to samo pytanie. A ja proponuje tę samą odpowiedź ;-)

Teraz normalnie upuścić „zmusza” zachowanie, mogę liczyć na dokumentacji. Nie znalazłem przypadku, w którym aspekt Singletona był tak przekonujący, że wymagał on egzekwowania na wszelkie sposoby. To tylko "najlepsza praktyka" dla projektu.

Zwykle używam sprężyny, aby zainicjować taki obiekt, i jest to konfiguracja Wiosna, która sprawia, że ​​jest to Singleton. Bezpieczne, i takie łatwe ... plus dodatkowe korzyści wiosenne (takie jak zastępowanie, zastępowanie innego obiektu tylko raz, aby przeprowadzić testy itp.)

0

To jest bardziej odpowiedź na twój komentarz/wyjaśnienie do odpowiedzi ktsa. Czy to jest tak, że prawdziwym problemem nie jest użycie wzorca Singleton, ale zdefiniowanie schematu punktu rozszerzenia zaćmienia, który umożliwia dodawanie singletonu?

Myślę, że nie da się tego zrobić, ponieważ za każdym razem, gdy wywołujesz IConfigurationElement.createExecutableExtension tworzysz nową instancję. Jest to całkowicie niezgodne z wymogiem singleton. I dlatego potrzebujesz publicznego domyślnego konstruktora, aby każdy mógł tworzyć instancje.

ile można zmienić definicję punktu rozszerzenia, tak aby przyczynić się do wtyczek ModelFactory zamiast modelu, jak

public interface ModelFactory { 

    public Model getModelInstance(); 

} 

więc użytkownik rozszerzenie będzie instancji ModelFactory i używać go w celu uzyskania singleton.

Gdybym domyślić źle, zostaw komentarz i usunąć odpowiedź;)

+0

Tak, masz rację. Ale jeśli ujawnię klasę fabryczną, umowa (tzn. Implementacja interfejsu modelu) zakończy się niepowodzeniem. Istnieje wiele innych metod w IConfigurationElement, z których możemy skorzystać, aby uzyskać więcej informacji o rozszerzeniu, może uzyskać nazwę klasy i wywołać metodę statyczną, aby uzyskać obiekt. Ale potem znowu wracamy do kwadratu 1. Nie możemy mieć deklaracji statycznej w interfejsie Modelu. – Duleb

+0

Niezupełnie - umowa została właśnie przeniesiona do klasy ModelFactory. Teraz będziesz miał dwie umowy: Fabryka (wkład poprzez punkt rozszerzenia) i Model (Fabryka musi zwrócić implementację Modelu) –

2

Można użyć refleksji. Coś takiego:

public interface Model { 
    class Singleton { 
    public static Model instance(Class<? extends Model> modelClass) { 
     try { 
     return (Model)modelClass.getField("instance").get(null); 
    } catch (blah-blah) { 
     blah-blah 
    } 
    } 
} 

public class XmlModel implements Model { 
    private static final Model instance = new XmlModel(); 

    private XmlModel() { 
    } 
} 

Wykorzystanie:

Model.Singleton.instance(XmlModel.class) 

Właściwie nie lubię tego kodu dużo :). Po pierwsze, używa refleksji - bardzo wolno, po drugie - istnieją możliwości błędów wykonania w przypadku błędnych definicji klas.

+0

Myślę, że Refleksja będzie działać. – Duleb