Exciting Announcements at WWDC 2012: New MacBook Pro, Mountain Lion, and iOS 6
The cat is finally out of the bag. Apple announced some amazing new hardware and software at the WWDC 2012 keynote. There were some expected...
Christopher Alexander, a noted design architect, defined design pattern as:
Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.
This blog lists some well known examples for 5 Creational Design Patterns as applicable in Cocoa Touch Framework.
Creational design patterns specifically target the problems of how an object is created and instantiated. These patterns were originally described in the Gang of Four (GoF) book on Design Patterns which is regarded as an important source for object-oriented design theory and practice.
1. Abstract Factory
The intent of Abstract Factory design pattern as specified in GoF is:
Provide an interface for creating families of related or dependent objects without
specifying their concrete classes.
We use Abstract Method pattern to create objects when we want to provide a class library of products, and we want to reveal just their interfaces, not their implementations. So the system is independent of how its products are created and represented.
The Abstract Factory pattern is commonly seen in the Cocoa Touch Framework and a lot of Foundation classes have used the pattern.
The interface declared by the abstract superclass, NSNumber in Foundation Framework serves a good example for this design pattern.
Consider these messages:
NSNumber *aChar = [NSNumber numberWithChar:’a’];
NSNumber *anInt = [NSNumber numberWithInt:1];
NSNumber *aFloat = [NSNumber numberWithFloat:1.0];
NSNumber *aDouble = [NSNumber numberWithDouble:1.0];
Each returned object — aChar, anInt, aFloat, and aDouble share a common public interface which is the interface declared by the abstract superclass, NSNumber.
@interface NSNumber : NSValue
- (char)charValue;
- (int)intValue;
- (float)floatValue;
- (double)doubleValue;
.
.
.
.
@end
@interface NSNumber (NSNumberCreation)
...
+ (NSNumber *)numberWithChar:(char)value;
+ (NSNumber *)numberWithInt:(int)value;
+ (NSNumber *)numberWithFloat:(float)value;
+ (NSNumber *)numberWithDouble:(double)value;
@end
but each object returned by the factory methods (numberWithChar, numberWithInt) belong to a different private subclass which is hidden to users.
On a side note, NSNumber is also a “class cluster”. Class clusters are based on the Abstract Factory design pattern as discussed in “Cocoa Design Patterns.”
2. Factory Method
The intent of Factory Method design pattern as provided in GoF is:
Define an interface for creating an object, but let subclasses decide which class
to instantiate.
We use the Factory Method pattern when a class wants its subclasses to specify the objects it creates.
As an example, again consider NSNumber class in the Foundation framework which defines several class factory methods:
+ numberWithBool:
+ numberWithChar:
+ numberWithDouble:
+ numberWithFloat:
+ numberWithInt:
+ numberWithInteger:
+ numberWithLong:
+ numberWithLongLong:
+ numberWithShort:
+ numberWithUnsignedChar:
+ numberWithUnsignedInt:
+ numberWithUnsignedInteger:
+ numberWithUnsignedLong:
+ numberWithUnsignedLongLong:
+ numberWithUnsignedShort:
These methods combine the two steps of allocating and initializing to return new, initialized instances of the class which are returned by the subclasses of the class where they are declared.
Having mentioned both Factory Method and Abstract Factory Method patterns, it is sometimes difficult to differentiate between the two. If we revisit the example for NSNumber class, in Factory Method pattern, we have a factory that creates objects that derive from a particular base class. So considering this example,
NSNumber aNum = [NSNumber numberWithInt:1];
Here numberWithInt is the “factory” that allocates, initializes, and returns the “product object “ aNum
while in Abstract Factory pattern we have a factory that creates other factories, and these factories in turn create objects derived from base classes. In other word, in this example, the methods of the NSNumber Abstract Factory are implemented as Factory Methods.
3. Prototype
As per GoF, sometimes when instances of a class can have one of only a few different combinations of state it it is more convenient to have a corresponding number of prototypes and reuse them rather than creating the class each time with the appropriate state.
Under this scenario, it advises us to use Prototype Design Pattern. This applicability reminds us of the prototype cells we use in UITableView.
As per Apple developer guide:
Use dynamic prototypes to design one cell and then use it as the template for other cells in the table. Use a dynamic prototype when multiple cells in a table should use the same layout to display information.
Consider this example:
#define FIRST_LABEL_TAG 1
#define SECOND_LABEL_TAG 2
#define PHOTO_TAG 3
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"ImageOnRightCell";
UILabel *firstLabel, *secondLabel;
UIImageView *photo;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
firstLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)]];
firstLabel.tag = FIRST_LABEL_TAG;
firstLabel.font = [UIFont systemFontOfSize:14.0];
firstLabel.textAlignment = UITextAlignmentRight;
firstLabel.textColor = [UIColor blackColor];
[cell.contentView addSubview:firstLabel];
secondLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0.0, 20.0, 220.0, 25.0)]];
secondLabel.tag = SECOND_LABEL_TAG;
secondLabel.font = [UIFont systemFontOfSize:12.0];
secondLabel.textAlignment = UITextAlignmentRight;
secondLabel.textColor = [UIColor darkGrayColor];
[cell.contentView addSubview:secondLabel];
photo = [[[UIImageView alloc] initWithFrame:CGRectMake(225.0, 0.0, 80.0, 45.0)]];
photo.tag = PHOTO_TAG;
photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:photo];
} else {
firstLabel = (UILabel *)[cell.contentView viewWithTag:FIRST_LABEL_TAG];
secondLabel = (UILabel *)[cell.contentView viewWithTag:SECOND_LABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
NSDictionary *aDict = [self.list objectAtIndex:indexPath.row];
firstLabel.text = [aDict objectForKey:@"mainTitleKey"];
secondLabel.text = [aDict objectForKey:@"secondaryTitleKey"];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:[aDict objectForKey:@"imageKey"] ofType:@"png"];
UIImage *theImage = [UIImage imageWithContentsOfFile:imagePath];
photo.image = theImage;
return cell;
}
Here we create a prototype for a cell in – tableView:cellForRowAtIndexPath: method as follows:
We create an instance of UITableViewCell and assign it a reuseIdentifier
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]];
We then add subviews to it based on our design
[cell.contentView addSubview:firstLabel];
.
.
[cell.contentView addSubview:secondLabel];
.
.
[cell.contentView addSubview:photo];
This prototype is now ready, and we use use this fully initialised cell as a prototype for other cells in our table view.
- tableView:cellForRowAtIndexPath: method first tries to acquire a cell by using dequeueReusableCellWithIdentifier.If a cell is not yet created, it creates it by using the prototype cell we had defined.
4. Singleton
The intent of Singleton design pattern as provided in GoF is:
Ensure a class only has one instance, and provide a global point of access to it.
Regarding ‘Applicability’, the book states to use the Singleton pattern when
There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point
Some common scenarios when we use Singletons in the Cocoa Touch Framework are
a. When an application is launched, the UIApplicationMain function (we can find it in main.m class in our project) is called and it creates a singleton UIApplication object. UIApplication class provides a centralized point of control for an iOS application. We can access this singleton object from any class in our project by invoking the sharedApplication class method:
UIApplication *applicationSingleton = [UIApplication sharedApplication];
b. UIAccerometer’s sharedAccelerometer class method returns the the singleton shared accelerometer object for the system:
UIAccelerometer *accelerometerSingleton = [UIAccelerometer sharedAccelerometer];
5. Builder
The intent of Builder design pattern as provided in GoF is:
Separate the construction of a complex object from its representation so that
the same construction process can create different representations.
Unlike creational patterns that construct objects in one go, the Builder pattern constructs the object step by step. It is used in creation of a complex object.
The builder pattern is not too much adopted in Objective-C as in java. Eric Buck, author of Cocoa Design Patterns, in one of his interview has said
“I think all of the famous GoF patterns exist within Cocoa, but many are either trivially implemented or made less necessary thanks to Objective-C. For example, the Cocoa convention of two stage allocation and initialization makes the GoF Abstract factory and Builder patterns trivial.”
In one flavor, as described in the book - Learn Objective-C for Java Developerscategories can be used for Builder Pattern in Objective C. The complex construction code is isolated from the main class definition via a category.
Summary
We saw how Cocoa Touch Framework uses different creational design patterns to create objects and their intent behind choosing a particular design pattern while creation of an object. For eg. Abstract Factory, Builder, and Prototype patterns - all 3 involve creating a new "factory object" which creates “product objects”. But each differ the way the product objects are created - Abstract Factory factory object produces objects of several classes. Prototype has the factory object building a product by copying a prototype object while Builder has the factory object building a complex product incrementally.
This blog listed only the design patterns used in the creation of objects. There are also structural and behavioral design patterns. It is always good to have a knowledge of wide variety of design patterns and the intent behind the use of a particular design pattern.
This helps us to leverage the knowledge of our industry experts and reuse it in our application design. Of course, the applicability of a particular design pattern depends on various factors. We must carefully choose from different design patterns. Understanding how the Cocoa Touch Framework uses these patterns, gives us a fair idea about their usage.
The cat is finally out of the bag. Apple announced some amazing new hardware and software at the WWDC 2012 keynote. There were some expected...
Have you ever noticed just how many businesses and brands are starting to pop up on the various different social media platforms and want to know if...
Choosing the right programming language is the most crucial thing for the developers in today’s time. You need to choose a language which is robust...