Does my use of the strategy pattern violate the fundamental MVC pattern in iOS?
- by Goodsquirrel
I'm about to use the 'strategy' pattern in my iOS app, but feel like my approach violates the somehow fundamental MVC pattern.
My app is displaying visual "stories", and a Story consists (i.e. has @properties) of one Photo and one or more VisualEvent objects to represent e.g. animated circles or moving arrows on the photo. Each VisualEvent object therefore has a eventType @property, that might be e.g. kEventTypeCircle or kEventTypeArrow. All events have things in common, like a startTime @property, but differ in the way they are being drawn on the StoryPlayerView.
Currently I'm trying to follow the MVC pattern and have a StoryPlayer object (my controller) that knows about both the model objects (like Story and all kinds of visual events) and the view object StoryPlayerView.
To chose the right drawing code for each of the different visual event types, my StoryPlayer is using a switch statement.
@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;
// (...)
}
But switch statements for type checking are bad design, aren't they? According to Uncle Bob they lead to tight coupling and can and should almost always be replaced by polymorphism.
Having read about the "Strategy"-Pattern in Head First Design Patterns, I felt this was a great way to get rid of my switch statement.
So I changed the design like this:
All specialized visual event types are now subclasses of an abstract VisualEvent class that has a showOnStoryPlayerView: method.
@interface VisualEvent : NSObject
- (void)showOnStoryPlayerView:(StoryPlayerView *)storyPlayerView; // abstract
Each and every concrete subclass implements a concrete specialized version of this drawing behavior method.
@implementation CircleVisualEvent
- (void)showOnStoryPlayerView:(StoryPlayerView *)storyPlayerView
{
[storyPlayerView drawCircleAtPoint:self.position
color:self.color
lineWidth:self.lineWidth
radius:self.radius];
}
The StoryPlayer now simply calls the same method on all types of events.
@implementation StoryPlayer
- (void)showVisualEvent:(VisualEvent *)event onStoryPlayerView:storyPlayerView
{
[event showOnStoryPlayerView:storyPlayerView];
}
The result seems to be great: I got rid of the switch statement, and if I ever have to add new types of VisualEvents in the future, I simply create new subclasses of VisualEvent. And I won't have to change anything in StoryPlayer.
But of cause this approach violates the MVC pattern since now my model has to know about and depend on my view! Now my controller talks to my model and my model talks to the view calling methods on StoryPlayerView like drawCircleAtPoint:color:lineWidth:radius:. But this kind of calls should be controller code not model code, right??
Seems to me like I made things worse.
I'm confused! Am I completely missing the point of the strategy pattern? Is there a better way to get rid of the switch statement without breaking model-view separation?