harlan kellaway's blog // Cocoa Design Patterns - An Example of the Factory Pattern

Published 01-10-2015

As I was hacking away today and reading the wonderful code crafting manual, Clean Code by Robert C. Martin, I came across a snippet disparaging the use of the switch statement. As Martin says: "My general rule for switch statments is that they can be tolerated if they appear only once, are used to create polymorphic objects, and are hidden behind an inheritance relationship so that the rest of the system can't see them". Alongside, he includes an example of refactoring a switch statement into a Factory.

I immediately thought of various situations in which I've relied too heavily on switch statments - which can become a growing problem with a growing code-base. I decided to refactor some recent code to use the Factory pattern in place of eventual switch statements or long if-elses down the line.

The code I've written borrows heavily from a post on Michael Crosby's blog, however, I found I was confused until I implemented it myself. If you're looking into the Factory pattern, I'd encourage you to read that post first and study both his and my examples.

The Factory pattern can come in handy when you have different types of the same object, especially if you don't know which variety of that object you'll need until runtime. Here's an example from Clean Code translated from Java to Objective-C:

- (Money *)calculatePay(Employee *e) {
  switch (e.type) {
    case HOURLY:
      return calculatedHourlyPay(e);
    case SALARIED:
      return calculateSalariedPay(e);
  }
}

We can imagine that other functions - e.g. isPayday(Employee *e, NSDate *date) - might have to adopt the same exact look. This will become a maintenance nightmare, especially when new Employee types are added.

Enter the Factory pattern!

We make a protocol for what is expected of Employees:

// Employee.h

@class Money;

@protocol Employee

- (Money *)calculatePay;

@end

We create our Factory class. This is the only place we'll need to import our individual class names - talk about DRY!

// EmployeeFactory.h
#import "Employee.h"

typedef NS_ENUM(NSInteger, EmployeeType)
{
  Hourly,
  Salaried
};

@interface EmployeeFactory : NSObject

+(id<Employee>) create:(EmployeeType)type;

@end
// EmployeeFactory.m
#import "EmployeeFactory.h"

#import "Employee.h"
#import "HourlyEmployee.h"
#import "SalariedEmployee.h"

@implementation EmployeeFactory

+(id<Employee>) create:(EmployeeType)type {
  switch (type) {
    case Hourly:
      return [[HourlyEmployee alloc] init];
    case Salaried:
      return [[SalariedEmployee alloc]init];
  }
}

Then go ahead and create your HourlyEmployee and SalariedEmployee classes - make sure they invoke the <Employee> protocol in their headers and implement required calculatePay method.

Now, wherever you want to create an Employee, you can use the create method and EmployeeType to return the correct class. The anonymous class id is used - as you may recall, this pattern is good for situations when you don't know the specific variety of the object you're creating until runtime (e.g. you're parsing JSON into objects of different types):

id<Employee> employee = [EmployeeFactory create:Hourly];
[employee calculatePay];

Happy coding!





This blog is licensed under Attribution-Noncommercial-Share Alike 3.0 Unported license.



comments powered by Disqus