2012-09-17 13 views
6

Jak wiem w standardowej implementacji MVC przekazujemy sterownik i model do widokuMVC - czy muszę używać kontrolera w widoku?

Ale jestem trochę nie zgadzam się z tym pomysłem. Nie chcę mój widok wiedzieć zarówno o kontrolerze i modelu (oh no. Może czasami zobaczyć potrzeb modelu, ale jestem pewien, że można żyć bez znajomości Controller)

Moim zdaniem kontrolera powinien zarządzać View i model, Model nie musi wiedzieć o kontrolerze i widoku; widok nie wymaga znajomości kontrolera (nie wykluczam modelu, ponieważ niektóre implementacje widoków muszą wiedzieć o modelu, aby słuchać zmian w modelu). Więc moim pomysłem jest, że widok nie musi wiedzieć o kontrolerze.

1. Oto jeden z przykładów:

public class MyView implements ButtonClickListener { 

    private Controller myController; 
    private Button myButton; 

    // I commented out the model because we dont need it now 
    // we are talking about using controller in the view 

    public MyView(Controller c/*, Model m*/) { 
     myController = c; 
     myButton  = new Button(); // lets say that it is "register" button 
     myButton.setOnButtonClickListener(this); 
    } 

    public void setRegisterButtonText(String text) { 
     myButton.setText(text); 
    } 

    @Override 
    public void onClick() { 
     myController.tellToModelToDoSomething(); 
    } 

} 

A Kontroler:

public MyController implements Controller { 

    private Model model; 
    private View view; 

    public MyController(Model model) { 

      this.model = model; 
      this.view = new MyView(this); 

    } 

    public void tellToModelToDoSomething() { 
      model.doSomeActions(); 
    } 


} 

2. A teraz jak widzę tej implementacji bez przechodzenia kontroler:

Mój widok:

public class MyView { 

    private Button myButton; 

    public MyView() { 
     myButton = new Button(); 
    } 

    public void setRegisterButtonText(String text) { 
     myButton.setText(text); 
    } 

    public void setOnRegisterButtonClick(final Command command) { 
     myButton.setOnButtonClickListener(new ButtonClickListener() { 
          @Override 
          public void onClick() { 
           command.execute(); 
          } 
         }); 
    } 

} 

"Command" interfejs:

public interface Command { 

    void execute(/*also can handle extra params*/); 

} 

A Kontroler:

public MyController implements Controller { 

private Model model; 
private View view; 

public MyController(Model model) { 

     this.model = model; 
     this.view = new MyView(); 

     view.setOnRegisterButtonClick(command); 

} 

public void tellToModelToDoSomething() { 
     model.doSomeActions(); 
} 

private Command command = new Command() { 

    public void execute() { 
      tellToModelToDoSomething(); 
    } 

}; 

}

Dlaczego więc myślę, że za pomocą kontrolera w widoku nie jest dobry:

Miksujemy kontroler i przeglądaj implementacje, tworząc nowe zależności.

Myślę również, że View powinien zawierać tylko WIDOKI i operacje z nimi (a używanie kontrolera i niektórych jego metod już wygląda jak logika).

W pierwszym przykładzie widok informuje kontrolera, co ma zrobić. Zgadzasz się? Wygląda na to, że widok kontroluje kontroler!

W drugim przykładzie steruje co robić i po prostu mówi do widzenia, co zrobić, jeśli jakiś przycisk (tylko widok wie co guzik będzie) kliknął

ja zawsze drugi plan, ale po przeczytaniu nowa książka o mvc, która mówi, że musimy przekazać kontroler do widoku, jestem trochę zagmatwany.

Czy możesz mi pomóc zrozumieć, dlaczego się mylę i pokazać mi kilka przykładów?

+0

Uważam, że kontroler i widok nie współdziałają bezpośrednio. Oddziałują jednak na model. więc model zna zarówno kontroler, jak i widok, ale widok i kontroler nie znają się nawzajem. – gigadot

+2

powiedziawszy to. MVC występuje w wielu wariantach, a rzeczywiste implanty różnią się w praktyce. – gigadot

+0

masz rację .., i jak myślisz w tym przykładzie, która implementacja jest lepsza? – pleerock

Odpowiedz

11

Nie ma standardu MVC, ponieważ istnieje wiele implementacji. Oto jedna interpretacja MVC nauczana w wielu podręcznikach:

Definicja kontrolera w tej interpretacji polega na obsłudze zdarzeń z widoku, więc widok musi korzystać z kontrolera.

W standardowym MVC model zawiera i eksponuje dane, kontroler manipuluje modelem i akceptuje zdarzenia z widoku, a widok przedstawia model i generuje zdarzenia dla kontrolera.

MVC jest uważany za system transakcyjny, w którym transakcja jest inicjowana przez zdarzenie. Transakcje zazwyczaj wyglądają tak:

  1. W widoku generowane jest zdarzenie (np. Kliknięcie przycisku).
  2. Informacja o zdarzeniu jest przekazywana z widoku do kontrolera.
  3. Sterownik wywołuje metody w modelu, aby je zmienić (setery i inne metody manipulacji, które mogą aktualizować niektóre bazy danych).

Te pierwsze kroki reprezentują łącze V-C i łącze M-C. V-C istnieje, ponieważ zdarzenia są przekazywane z widoku do kontrolera, który ma być przetworzony zamiast widoku, który obsługuje je bezpośrednio. Link M-C istnieje, ponieważ model jest aktualizowany przez kontroler zgodnie ze zdarzeniem, które zostało uruchomione.

Stąd są dwie ścieżki. Pierwszy:

  1. Transakcja zostaje zakończona.
  2. Oddzielnie, model uruchamia własne zdarzenia, aby wskazać, że się zmienił.
  3. Widok nasłuchuje modelu i odbiera zdarzenie oraz aktualizuje jego reprezentację modelu, aby odzwierciedlić zmiany.

Ta pierwsza ścieżka reprezentuje jedną interpretację łącza M-V. Łącze M-V to 1) widok pobierający informacje z modelu dla jego danych oraz 2) model informujący widok o aktualizacji, ponieważ został zmodyfikowany.

Druga ścieżka to tylko jeden krok: po przetworzeniu zdarzenia przez kontroler widok jest natychmiast aktualizowany po prostu odświeżając wszystkie jego elementy interfejsu użytkownika. Ta interpretacja łącza M-V polega na tym, że model po prostu dostarcza swoje informacje do widoku, tak samo jak punkt # 1 z łącza M-V w pierwszej ścieżce powyżej.

Oto niektóre z kodu zmodyfikowanego dla architektury MVC Opisałem:

public class MyView implements View, ModelListener { 

    private Button myButton; 
    private Controller controller; 

    public MyView(Controller controller, Model model) { 
     myButton = new Button(); 
     myButton.setOnButtonClickListener(new ButtonClickListener() { 
      @Override 
      public void onClick() { 
       controller.onRegisterButtonClick(); 
      } 
     }); 
     this.controller = controller; 
     model.addModelListener(this); 
    } 

    public void setRegisterButtonText(String text) { 
     myButton.setText(text); 
    } 

    public void modelUpdated(Model model) { 
     // Update view from model 
    } 
} 

a kontrolerem:

public MyController implements Controller { 

    private Model model; 
    private View view; 

    public MyController(Model model) { 
     this.model = model; 
     this.view = new MyView(this, model); 
    } 

    private void manipulateModel() { 
     model.doSomeActions(); 
    } 

    public void onRegisterButtonClick() { 
     maniuplateModel(); 
    } 
} 

wówczas modelu:

public class MyModel implements Model { 
    private List<ModelListener> modelListeners = new ArrayList<ModelListener>(); 

    public void addModelListener(ModelListener ml) { 
     if (!modelListeners.contains(ml)) { 
      modelListeners.add(ml); 
     } 
    } 

    public void removeModelListener(ModelListener ml) { 
     modelListeners.remove(ml); 
    } 

    public void doSomeActions() { 
     // Do something 
     fireUpdate(); 
    } 

    private void fireUpdate() { 
     // Iterates backwards with indices in case listeners want to remove themselves 
     for (int i = modelListeners.size() - 1; i >= 0; i-- { 
      modelListener.modelUpdated(this); 
     } 
    } 
} 

ModelListener jest całkiem proste:

public interface ModelListener { 
    void modelUpdated(Model model); 
} 

To tylko jedna interpretacja. Jeśli potrzebujesz dalszego oddzielenia między różnymi częściami, powinieneś zajrzeć do Presentation, Abstraction, Control (PAC) pattern. Jest bardziej odsprzężony niż MVC i doskonale nadaje się również do systemów rozproszonych. To przesada dla prostych aplikacji internetowych, mobilnych i stacjonarnych, ale niektóre aplikacje klient/serwer i większość aplikacji w chmurze może skorzystać z tego podejścia.

W PAC masz trzy części, prezentację, abstrakcję i kontrolę, ale abstrakcja i prezentacja (model i widok) nie współdziałają ze sobą.Zamiast tego informacje przekazywane są tylko do modułu kontrolnego i poza nim. Co więcej, możesz mieć wiele pod-modułów PAC, które współdziałają ze sobą tylko za pomocą swoich kontrolek, nadając się do dobrego wzorca dla systemów rozproszonych. Zasadniczo moduł sterowania jest głównym koncentratorem każdego transferu danych.

Zasadniczo Twoja interpretacja MVC może być inna niż moja lub ich. Liczy się to, że wybierasz wzór architektoniczny i podążasz za nim, aby zachować kod w przyszłości. I masz rację, że istnieją sposoby dalszego oddzielenia MVC. W rzeczywistości twój przykład jest trochę podobny do PAC, ale zamiast usuwania linku V-C usuwa link M-V.

W każdym razie, postępuj zgodnie z architekturą, dokument swoją architekturę (aby ludzie wiedzieli, co twoja interpretacja jest) i nie odstępuj od tego.

+0

Dziękuję za odpowiedź. Doceniam twoją radę i dowiem się więcej na temat wzorca PAC. – pleerock

+0

Kto mógłby dodać "widoki" w tablicy 'modelListeners' ArrayList w klasie' MyModel'? Czy byłoby to zrobione w 'MyController', gdzie w klasie' MyController' zrobiłbyś 'model. addModelListener (widok) '? – CapturedTree

+1

Jasne, myślę, że kontroler będzie odpowiednim miejscem w tym przykładzie tak. Tak więc w konstruktorze kontrolera: 'model.addModelListener (widok);' Opcjonalnie, możesz mieć interfejs 'View' rozszerzający 'ModelListener', abyś wiedział, że zawsze będzie słuchaczem. Lub interfejs 'View' implementuje metodę, która zwraca jego' ModelListener'. Istnieje wiele opcji. Tak jak powiedziałem, wybierz implementację i trzymaj się jej razem :) – Brian

Powiązane problemy