5

Kontynuując poprzednie pytania (here i here), zaimplementowałem podstawowy wzorzec poleceń, utworzyłem klasy poleceń i zakodowałem do interfejsu, więc kiedy jakieś polecenie jest używane, wywołuję execute() metoda.kłopot z polimorfizmem pokonać te przełączniki/case statement

Jednak nadal nie jestem w stanie wstrząsnąć tymi stwierdzeniami: Czytam każdą postać z ciągu głównego/decyzji, który składa się z losowych, powtarzających się znaków A, B, C lub D, a następnie ja pobrać powiązaną implementację polecenia z mapy i wywołać jego metodę wykonywania.

Mój projekt był tak:

public interface Command { 
    void execute(); 
} 

public class CommandA implements Command{ 
    //implements execute() method 
} 

private Map myMap= new HashMap(); 
myMap.put("A", new CommandA); 
myMap.put("B", new CommandB); 
myMap.put("C", new CommandC); 
myMap.put("D", new CommandD); 

Ale wtedy, gdy czytam każdą instrukcję, znowu muszę uciekać się do przypadku stwierdzenia:

switch(instructionFromString){ 
case 'A':{myMap.get("A").execute(); break;} 
case 'B':{myMap.get("B").execute(); break;} 
case 'C':{myMap.get("C").execute(); break;} 
case 'D':{myMap.get("D").execute(); break;} 

Oczywiście, gdzieś po drodze udało mi aby pokonać przewagę polimorfizmu w stosunku do stwierdzeń dotyczących przypadku.

Czy to może być rodzaj struktury danych, którą wybrałem do przechowywania moich poleceń? Może to być bardzo trwała struktura danych, z której można po prostu pobrać te polecenia.

Inną rzeczą, która przychodzi na myśl, jest nazwa klucz/wartość, której użyłem w mojej mapie. W jaki sposób starałem się koncepcyjnie połączyć każde zapisane polecenie z powiązaną z nim instrukcją? tj. Wdrożenie polecenia "A" jest zapisywane na mapie za pomocą klawisza "A", aby mogło pasować do odpowiedniej instrukcji "A"? Wydaje mi się to jednak mało prawdopodobne.

Każda wskazówka lub dalsza porada dotycząca mojego następnego posunięcia w celu usunięcia tych stwierdzeń raz na zawsze zostanie wysoko oceniona. Wiele z góry dzięki

Odpowiedz

14

I może być brakuje czegoś tutaj, ale zamiast rachunku switch, co się dzieje z

((Command)myMap.get(instructionFromString)).execute(); 

Jeśli instructionFromString jest char, nawrócony go do String przed wykonaniem odnośnika mapy, w innym przypadku użyj kluczy Character na mapie.

Ponadto, jeśli korzystasz z ogólnej mapy Java 5, możesz usunąć rzutowanie na Command. Oczyszczone się wersja będzie:

private Map<Character, Command> myMap = new HashMap<Character, Command>(); 
myMap.put('A', new CommandA()); 
myMap.put('B', new CommandB()); 
myMap.put('C', new CommandC()); 
myMap.put('D', new CommandD()); 

następuje:

char instructionFromString = .... 
myMap.get(instructionFromString).execute(); 
+0

@skaffman: Przepraszamy. Udało mi się jakoś odczytać próbkę kodu, ale pominięto tekst powyżej i poniżej. – Dirk

+0

+1 za odpowiedź "Cytuj" i rozwiń dalej. – KLE

+0

@skaffman: Dzięki, bardzo elegancki asnwer. Nie mogę uwierzyć, że to przegapiłem! – denchr

0

Z prostym mapie, co może się przykry skoro jesteś całym ponownie stosując tę ​​samą instancję CommandA.

Dobrym sposobem hermetyzacji tego rodzaju zachowanie byłoby być fabryka:

public class CommandFactory 
{ 
    public Command CreateCommand(String instruction) 
    { 
     if (instruction.equals("A")) 
      return new CommandA(); 
     else if ... 
    } 
} 

Innym sposobem byłoby prototype pattern (aka wzór klon), co pozwala na bardziej elastyczną obsługę wielu zróżnicowanych typy (polecenia dla tej sprawy):

public class CommandFactory 
{ 
    private Map<String, Command> commands = new HashMap<String, Command>(); 

    public void RegisterCommand(String instruction, Command commandTemplate) 
    { 
     commands.put(instruction, commandTemplate); 
    } 

    public Command CreateCommand(String instruction) 
    { 
     return commands.get(instruction).clone(); 
    } 
} 

Jak można zauważyć, trzeba będzie wdrożyć zachowanie klonowania do Commands, co może być czasochłonne.

0

Podoba mi się odpowiedź Skaffmana. Chcę tylko dodać więcej:

W celu nazwania poleceń można użyć prostszego wzoru. Na przykład możesz użyć nazwy polecenia jako przypadku domyślnego.

  • W ogólnym przypadku to o wiele mniej do pisania. Eliminuje błędy.
  • Gdy nazwa jest inna, nadal konfigurujesz mapę dla tego konkretnego przypadku.

Dostępnych jest wiele technologii związanych z nazwą i poleceniem. Przykłady:

  • Adnotacje dla klasy, która określa nazwę polecenia (z wartością domyślną równą nazwie klasy).
  • Konfiguracja sprężyn jest już tak dużą Mapą i bezpośrednio dostarcza odpowiedni obiekt, a po drodze dostępnych jest znacznie więcej usług.
  • Wyliczenia Java również w naturalny sposób wiążą nazwę z obiektem. Ponadto pozwalają na sprawdzenie kompletności i kompilacji w IDE, wraz z "wyszukiwaniem referencyjnym" i innymi gadżetami.
+0

@KLE: Dzięki! Dość użyteczne wskazówki. – denchr