Does my use of the strategy pattern violate the fundamental MVC pattern in iOS?
Posted
by
Goodsquirrel
on Programmers
See other posts from Programmers
or by Goodsquirrel
Published on 2014-06-01T17:03:39Z
Indexed on
2014/06/01
21:54 UTC
Read the original article
Hit count: 520
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?
© Programmers or respective owner