Sto per utilizzare lo schema "strategia" nella mia app iOS, ma sento che il mio approccio viola il modello MVC in qualche modo fondamentale.
La mia app sta visualizzando "storie" visive e un Story
è costituito (cioè ha @properties
) di un Photo
e uno o più VisualEvent
oggetti da rappresentare per es. cerchi animati o frecce in movimento sulla foto. Ogni oggetto VisualEvent
ha quindi un eventType
@property
, che potrebbe essere ad es. kEventTypeCircle
o kEventTypeArrow
. Tutti gli eventi hanno cose in comune, come startTime
@property
, ma differiscono nel modo in cui vengono disegnati su StoryPlayerView
.
Attualmente sto provando a seguire lo schema MVC e ho un oggetto StoryPlayer
(il mio controller) che conosce sia gli oggetti del modello (come Story
e tutti i tipi di eventi visivi) sia l'oggetto vista StoryPlayerView
.
Per scegliere il codice di disegno corretto per ciascuno dei diversi tipi di eventi visivi, il mio StoryPlayer
utilizza un'istruzione switch
.
@implementation StoryPlayer
// (...)
- (void)showVisualEvent:(VisualEvent *)event onStoryPlayerView:storyPlayerView
{
switch (event.eventType) {
case kEventTypeCircle:
[self showCircleEvent:event onStoryPlayerView:storyPlayerView];
break;
case kEventTypeArrow:
[self showArrowDrawingEvent:event onStoryPlayerView:storyPlayerView];
break;
// (...)
}
Ma le istruzioni switch per il controllo dei tipi non sono di buon livello, no? Secondo Uncle Bob portano a un accoppiamento stretto e possono e dovrebbero essere sostituiti quasi sempre con il polimorfismo.
Dopo aver letto su "Strategia" -Pattern in Head First Design Patterns , ho sentito che era un grande modo per sbarazzarsi della mia dichiarazione di switch.
Quindi ho cambiato il progetto in questo modo:
Tutti i tipi di eventi visivi specializzati sono ora sottoclassi di una classe VisualEvent
astratta che ha un metodo showOnStoryPlayerView:
.
@interface VisualEvent : NSObject
- (void)showOnStoryPlayerView:(StoryPlayerView *)storyPlayerView; // abstract
Ciascuna sottoclasse concreta implementa una versione specializzata concreta di questo metodo di comportamento del disegno.
@implementation CircleVisualEvent
- (void)showOnStoryPlayerView:(StoryPlayerView *)storyPlayerView
{
[storyPlayerView drawCircleAtPoint:self.position
color:self.color
lineWidth:self.lineWidth
radius:self.radius];
}
Il StoryPlayer
ora chiama semplicemente lo stesso metodo su tutti i tipi di eventi.
@implementation StoryPlayer
- (void)showVisualEvent:(VisualEvent *)event onStoryPlayerView:storyPlayerView
{
[event showOnStoryPlayerView:storyPlayerView];
}
Il risultato sembra fantastico: mi sono liberato dell'istruzione switch e, se mai dovessi aggiungere nuovi tipi di VisualEvents in futuro, creerò semplicemente nuove sottoclassi di VisualEvent
. E non dovrò modificare nulla in StoryPlayer
.
Ma di fatto questo approccio viola lo schema MVC da quando il mio modello deve sapere e dipendere dal mio punto di vista! Ora il mio controller parla con il mio modello e il mio modello parla con i metodi di chiamata view su StoryPlayerView
come drawCircleAtPoint:color:lineWidth:radius:
. Ma questo tipo di chiamate dovrebbe essere il codice del controller non il codice del modello, giusto ??
Mi sembra come se avessi peggiorato le cose.
Sono confuso! Mi manca completamente il punto del modello strategico? C'è un modo migliore per sbarazzarsi dell'istruzione switch senza interrompere la separazione della vista modello?