Strategy Design Pattern

I was over in Sweden last week teaching a Java design patterns course. Having spent so much time with iOS recently, it was interesting to put my Java hat back on and talk about designing enterprise scale applications. Some of my students probably thought I was a little slow writing code during demos but I did have to readjust to writing Java instead of Objective-C — the Swedish keyboard layout was an extra challenge too!

We discuss a lot of Java-specific design patterns on that course, but we start off by looking at some of the classic object-oriented design patterns from “Design Patterns: Elements of Reusable Object-Oriented Software” by Gamma, Helm, Johnson and Vlissides.

Those patterns are applicable to any object-oriented language and it got me thinking about how some of them could be applied to iPhone and iPad development with Objective-C.

Strategy Design Pattern

Strategy is a simple but useful design pattern that allows different strategies to be chosen dynamically to implement a certain piece of functionality. There are all sorts of applications of this pattern; choosing a different parser for a web service based on the content type of the response, loading different data based on region/language, or creating different content for a web view on iPad versus iPhone.

Simple choices can be achieved with if statements and switch statements of course, but the strategy pattern makes for much cleaner code, with complex variations on algorithms refactored into individual classes.

The basic idea of the strategy pattern is that a class makes use of a strategy object without worrying about the concrete class of that object. All it knows is that the strategy object implements a protocol:

DataLoader.h

@protocol DataLoader <NSObject>
- (NSArray *)data;
@end

Different implementations of that protocol are created for different situations. This one is for iPhone data, but we could create another similar one for iPad data:

iPhoneDataLoader.h

@interface iPhoneDataLoader : NSObject <DataLoader>
@end

iPhoneDataLoader.m

@implementation iPhoneDataLoader
- (NSArray *)data
{
    // Create some sample data for testing ...
    return @[@"iPhone 3GS", @"iPhone 4", @"iPhone 4S"];
}
@end

A table view controller could then make use of a generic data loader, e.g. using a lazy property and choosing the appropriate strategy class:

MyTableViewController.m

@property (nonatomic, strong) id<DataLoader> dataLoader;
...
- (id<DataLoader>)dataLoader
{
    if (!_dataLoader) {
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
            _dataLoader = [[iPadDataLoader alloc] init];
        else
            _dataLoader = [[iPhoneDataLoader alloc] init];
    }
    return _dataLoader;
}

The rest of the table view controller can then use the chosen strategy wherever it needs it:

- (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section
{
    return [[self.dataLoader data] count];
}

The beauty of this is that any changes to the algorithm, e.g. changing the data loaders to pull data from a database or web service, has no impact on the table view controller. Any complexity associated with downloading data from a URL and parsing, or accessing a database, is hidden in the data loader implementation classes. This is the open-closed principle of good object-oriented design; that ideally a class should be open for extension but mostly closed for modification.

In this example, all our bases are covered with iPhone and iPad data loaders, but the strategy pattern makes it particularly easy to add new strategies for different situations. Just create a new class that implements the protocol.

You can learn more about other design patterns applicable to iPhone and iPad applications on Learning Tree’s Building iPhone® and iPad® Applications: Extended Features course.

Richard Senior

Type to search blog.learningtree.com

Do you mean "" ?

Sorry, no results were found for your query.

Please check your spelling and try your search again.