2013-04-29 9 views
15

Posiadam klasę ActiveRecord BaseModel i wiele modeli klas, które ją dziedziczą. I mam klasę Bookmark, która jest również dziedziczona z BaseModel. Ponadto, mam klasy Decorator, implementują specjalny interfejs do reprezentowania pojedynczego modelu (metoda getModelView(model)). To niektóre pseudo-code:Odpowiedni wzorzec dla klasy ActiveRecord

TestModel inherits BaseModel 
    getName: 
     return this.name 

BookmarkModel inherits BaseModel 
    BaseModel model 

    getBookmark: 
     return this.model 

TestDecorator inherits BaseDecorator implements SingleModelViewInterface: 
    getView(model): 
     return 'view' //html-view of model 

BookmarkDecorator inherits BaseDecorator 
    getBookmarksView(BookmarkModel[] bookmarks): 
     foreach(bookmarks > bookmark): 
      decorator = Relation::getDecoratorByModel(bookmark->getEntityType()) 
      decorator->getView(bookmark->getBookmark()) 

Tak, wszystko wygląda dobrze, dopóki nie chcesz zmieniać tego poglądu na zakładkach modelu nieco. Chcę dodać niestandardowy tytuł do tego widoku. I nie mogę zrobić tego w dekoratorze, ponieważ renderuje to nie tylko na zakładki.

EDYCJA: Problem jest - wydaje mi się, że potrzebuję wzoru dekoratora, ale nie mam nic do odziedziczenia, ponieważ konkretny TestDecorator używa specjalnych metod TestModel. Więc teraz ja zrobiłem jakieś naprawdę złe wykonanie, za pomocą metod magicznych (PHP):

class BookmarkedModel { 

    /** @var BaseEntityModel*/ 
    private $model; 

    public function __construct(BaseEntityModel $model) { 
     $this->model = $model; 
    } 

    public function getName() { 
     return 'Bookmark '.$this->model->getName(); 
    } 

    public function __call($name, $arguments) { 
     return call_user_func_array(array($this->model, $name), $arguments); 
    } 

    public function __get($name) { 
     return $this->model->$name; 
    } 

    public function __set($name, $value) { 
     return $this->model->$name[$value]; 
    } 

} 

tak to będzie działać teraz, ale pod względem struktury kodu, czytelność i stabilność to bardzo zła decyzja.

+0

moi 2cents: Modyfikacja getBookmark(), aby powrócić do modelu z tytułu niestandardowego. Widok to tylko mechanizm renderujący, powinien pozostać ogólny. – lucasg

+0

getBookmark zwraca dowolny model, który dziedziczy po BaseModel. BaseModel ma abstrakcyjną metodę 'getName()'. Zrobiłem coś w rodzaju wzorca dekoratora (ale to nie jest rzeczywisty dekorator, nie mam klasy, z której można dziedziczyć). – UnstableFractal

+0

Teraz myślę o dodaniu 'setName()' do 'BaseModel'. A po prostu ustawienie go w metodzie 'BookmarkModel'' getBookmark' po pobraniu z bazy danych. Myślę, że to łatwiejsza decyzja. Nie sądzę, że będę musiał stawić czoła innej wymaganej funkcjonalności. – UnstableFractal

Odpowiedz

2

Model powinien być nieświadomy widoku. Modele reprezentują nieprzetworzone dane widziane z każdego kąta naraz. Widok jest perspektywa tego modelu. Kontroler powinien karmić modelu do pogląd:

$model_view->render($model); 

Następnie udekorować pogląd:

$bookmark_view->render($model); // bookmark_view wraps a model_view, 
// returns 'Bookmark '.$this->model_view->render($model) 

tylko zdobią oparte na interfejsach, a nie typu.

Magiczne metody PHP są świetne, ale nie powinny być używane w ActiveRecord, jest to sprzeczne z "separacją obaw", w tym przypadku oderwaniem modelu od jego mechanizmu wytrwałości.

Zamiast tego utwórz obiekt ActiveRecord i podaj model do go.

$record->store($model); 

Następnie jeśli trzeba zmodyfikować przechowywanie, ponownie po prostu ozdobić mechanizmu składowania:

$log_record->store($model); // wraps $record, logs a message prior to database storage. 
+0

Jak dokładnie ten przypadek pomaga w oddzieleniu modelu od mechanizmu trwałości? Zasadniczo nie widzę żadnych zalet. – UnstableFractal

+0

Pierwszy punkt to przykład właściwej dekoracji, czyli tylko dekoracji interfejsów i oddzielania modelu od widoku. Druga kwestia ma na celu zilustrowanie tego, że sam obiekt, mechanizm magazynowania, wprowadza złożoność, która skaluje się ze złożonością obiektu i nie jest łatwo wymieniana lub _użyteczna testowalna_, o czym świadczy próba zawinięcia obiektu. Lepiej byłoby uczynić BookmarkedModel rozszerzeniem BaseEntityModel. –

+0

Modele powinny dbać tylko o to, czy są w poprawnym stanie. To jest ich cel. Nie po to, aby się wytrwać. –

Powiązane problemy