Il mio utilizzo del modello di strategia viola il modello MVC fondamentale in iOS?

2

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?

    
posta Goodsquirrel 01.06.2014 - 19:03
fonte

1 risposta

2

Stai cercando di unire due livelli di funzionalità in una singola classe. Questo è quasi garantito per causare un disastro nel tuo progetto. Invece, come su questo:

Crea un altro set di classi parallelo alle classi Event. Ogni xxVisualEvent avrà un xxVisualEventRenderer corrispondente che incapsula la sua logica di rendering / visualizzazione. Queste classi conoscono sia il modello che la vista e sono essenzialmente estensioni del controller.

Crea una classe Mapper (fondamentalmente una factory), che contiene una VisualEvent e crea una VisualEventRenderer in base al tipo. Sì, questo significa un commutatore basato sul tipo, ma la classe non ha altra logica che costruire le istanze del Renderer.

Quindi puoi chiamare il metodo Render / Draw su queste classi Renderer invece che sulle classi Event. Conserverai tutti i vantaggi del tuo approccio, come l'accoppiamento libero, ecc.

    
risposta data 03.06.2014 - 07:42
fonte

Leggi altre domande sui tag