Prototype Pattern

What Is the Prototype Pattern?node

The Prototype pattern is one of the simplest design patterns. A client knows an abstract Prototype class. At runtime any object that is a subclass of the abstract Prototype can be cloned at the client’s will. So the client can make multiple instances of the same type without creating them manually. A class diagram that shows their static relationships is illustrated in Figure 3–1.canvas

 

Figure 3–1. A class diagram of the Prototype patternapp

Prototype declares an interface for cloning itself. ConcretePrototype as a subclass of the Prototype implements the clone operation for cloning itself. The client here creates a new object by asking a prototype to clone itself.ide

THE PROTOTYPE PATTERN: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.*

 

* The original definition appeared in Design Patterns, by the “Gang of Four” (Addison-Wesley, 1994).oop

When Would You Use the Prototype Pattern?ui

We may think about using the Prototype pattern whenthis

We need to create objects that should be independent of what they are and how they are created.atom

Classes to be instantiated are determined at runtime.idea

  •  We don’t want to have a hierarchy of factories for a corresponding hierarchy of products.prototype

  •  The differences between instances of different classes are just a few combinations of state. Then it’s more convenient to clone a corresponding number of prototypes rather than instantiating them manually.

  •  Classes are not easy to create, such as composite objects in which each component can have other components as children. It’d be easier to clone existing composite objects and modify the copies.

CHAPTER 3: Prototype 49

NOTE: A common misconception about using the Prototype pattern is that a prototype object should be an archetypal object and, typically, one that is never actually used. That misconception focuses on a particular way to implement the pattern. From a functional point of view, a prototype object can be any object that should be better off cloning itself than getting instantiated manually. There are two particularly common situations where we would naturally think about using the pattern

 

  1. 1)  You have many related classes whose behavior is slightly different, and they mostly differ in internal attributes, such as name, image, etc.

  2. 2)  You need to use a composite (tree) object as a basis for something else, e.g., use a composite object as a building block to build another composite object.

There are a lot more situations where you’d apply this pattern in the real world. Using design patterns is more art than science. Break some rules, be creative, and work smarter!

The bottom line for this pattern is to make a true copy of an object so we can use it as a basis (prototype) for something else related in the same context. So our next stop is to discuss issues related to copying objects.

Shallow Copying vs. Deep Copying

If an object has a pointer as a member variable that points to some resource in memory, how would you make a copy of that object? Would you just copy that pointer value and pass it to a new object as a clone? The pointer is just a placeholder that stores an address of some resource in memory. In a cloning operation, if a pointer is just copied over to a new object (a clone), the underlying resource is still actually being shared by both instances, as illustrated in Figure 3–2.

50 CHAPTER 3: Prototype

Figure 3–2. An illustration depicts a scenario of cloning ConcretePrototype1 by just copying the value of the Resource Pointer 1, but the actual resource is not copied.

In the clone operation of ConcretePrototype, it copies a pointer value of the Resource Pointer to a new clone. Even though the instance of ConcretePrototype made another instance of the same type as its clone, the pointers in both instances are still pointing to the same resource in memory. So the pointer value is cloned but not the actual resource. We call this shallow copying.

So what’s deep copying then? Deep copying is to copy not just pointer values over but also the resources being referenced by the pointers. A deep copying version of the same clone operation is illustrated in Figure 3–3.

The clone operation is to not just simply make a copy of the Resource Pointer to a new one but also to make a true copy of the actual resource in memory. So the pointer of the clone is pointing to a copy of the same resource (content) in memory but in a different location.

CHAPTER 3: Prototype 51

Figure 3–3. This is a similar scenario as in Figure 3–2, but the actual resource in memory is copied during the cloning operation.

Using Object Copying in the Cocoa Touch Framework

The Cocoa Touch framework provides a protocol for any NSObject descendent to implement deep copying. Any subclass of NSObject needs to implement the NSCopying protocol and its method, (id)copyWithZone:(NSZone *)zone. NSObject has an instance method called (id)copy. The default copy method calls [self copyWithZone:nil]. For subclasses that adopt the NSCopying protocol, that method needs to be implemented, otherwise it will raise an exception. In iOS, this method retains the newly cloned object before returning it. The invoker of this method is responsible for releasing the returned object.

Most of the time, an implementation for deep copying doesn’t look very complicated. The idea is to copy any necessary member variables and resources, pass them to a new instance of the same class, and return the new instance. The trick is to make sure you do really copy the resource in memory and not just pointer values. It’s more apparent when you need to deal with a composite structure like the one for the TouchPainter app in Chapter 2.

52 CHAPTER 3: Prototype

Implementing the Copy Method for the Mark Aggregate

In our original TouchPainter app, one of the most important data structures is the Mark aggregate object that contains all Dots and Strokes instances for a scribble. There are at least two situations that require the cloning of the whole structure:

Make a deep copy of it and archive it.
Reuse the same scribble as a “pattern template” (rubber stamp) to

repeat the same pattern as the user draws.

For the first one, we need to make sure the copy won’t be modified while it’s being kept for archiving or other related processes as compared to just retaining a reference to the original aggregate (see Memento pattern in Chapter 23 for details).

If we allow the user to reuse the same scribble as a basis for other strokes, then we need to let the current scribble copy itself so it can be used as a “pattern template” feature.

We are going to adopt a composite structure (Composite pattern, Chapter 13) that contains the user’s strokes in the TouchPainter app. The composite structure is illustrated in Chapter 2 as an integral part of the app. The parent of the structure called Mark is defined as an Objective-C protocol. Mark has three concrete classes (components) that define a composite object at runtime. Dot and Vertex define individual components while Stroke defines composite components that can also contain other Mark instances as children. Dot is a subclass of Vertex. The challenge here is to make an exact deep copy of the whole Mark aggregate structure without knowing how to parse the whole tree. A Stroke object can contain objects of Dots or its subclasses as well as other Stroke objects. We need to modify the original Mark and its implementing classes to have a “copy” method that will do the recursive deep copying trick. Figure 3–4 illustrates a class diagram of the Mark composite classes with a copy method.

There is not much change in the interfaces of Mark and its concrete classes except a copy method is added to each of them. There is a fictitious client that does savePattern with a currentMark as a copy called pattern for later use. How to use the copies depends on the application, but the rule of thumb is we ask objects to create themselves when it’s too complicated to recreate by a client, like reconstructing an existing Mark composite object, for example.

Figure 3–4. A class diagram of the Mark composite classes implementing the Prototype pattern Now let’s look at some code.

Listing 3–1 illustrates changes in the Mark protocol. Listing 3–1. Mark.h
@protocol Mark <NSObject>

@property (nonatomic, retain) UIColor * color; @property (nonatomic, assign) CGFloat size; @property (nonatomic, assign) CGPoint location; @property (nonatomic, readonly) NSUInteger count; @property (nonatomic, readonly) id <Mark> lastChild;

- (id) copy;

- (void) addMark:(id <Mark>) mark;
- (void) removeMark:(id <Mark>) mark;
- (id <Mark>) childMarkAtIndex:(NSUInteger) index;

// number of children

@end

CHAPTER 3: Prototype 53

54 CHAPTER 3: Prototype

We have added a new copy method to the Mark protocol that returns an instance of an implementing class.

There are a few implementing classes that will implement the copy method. Classes of their objects that will be part of a Mark aggregate at runtime are Vertex, Strokes, as well as a subclass of Vertex, Dot. Dot objects are to represent a single dot drawn on the screen as opposed to a Stroke object. A Stroke object can be the grandparent of all types of Mark as well as just a simple parent that contains Vertex objects to form a complete stroke. Vertex doesn’t do anything except maintain the location (coordinates) on the screen, so a rendering algorithm can draw them as a stroke (see Composite pattern in Chapter 13 and Visitor pattern in Chapter 15).

A visual diagram that depicts their relationships is illustrated in Figure 3–5.

Figure 3–5. The relationships between Dot, Stroke, and Vertex objects as a composite structure
We will continue to implement the copy method for the implementing classes of the Mark

protocol. The first one is Vertex in Listing 3–2. Listing 3–2. Vertex.h
#import "Mark.h"

@interface Vertex : NSObject <Mark, NSCopying> {

@protected

CGPoint location_; }

@property (nonatomic, retain) UIColor *color;

@property (nonatomic, assign) CGFloat size; @property (nonatomic, assign) CGPoint location; @property (nonatomic, readonly) NSUInteger count; @property (nonatomic, readonly) id <Mark> lastChild;

- (id) initWithLocation:(CGPoint) location;
- (void) addMark:(id <Mark>) mark;
- (void) removeMark:(id <Mark>) mark;
- (id <Mark>) childMarkAtIndex:(NSUInteger) index; // needs to be added to draft

- (id) copyWithZone:(NSZone *)zone;

@end

Wait a minute—why is there no copy method and copyWithZone: instead? And why is there a copy method in the Mark protocol but not the copyWithZone: method? The Mark protocol adopts the NSObject protocol while Mark’s concrete classes adopt Mark and subclass NSObject class. The NSObject protocol doesn’t have a copy method declared, but NSObject does. When a message of copy is invoked on a receiver of NSObject, NSObject will in turn forward the call to its subclass that adopts the NSCopying protocol. The subclass needs to implement the required copyWithZone:zone method defined in NSCopying to return a clone of itself. If the subclass doesn’t implement the method, an instance of NSInvalidArgumentException will be thrown. That’s why we need to let the Vertex class adopt the NSCopying protocol and implement its copyWithZone:zone method for the cloning process. However, the NSObject protocol doesn’t have a method copy declared, so we also declared it in our Mark protocol to avoid compiler warnings. Vertex is a subclass of NSObject, so it implements that copyWithZone: method as in Listing 3–3.

Listing 3–3. Vertex.m #import "Vertex.h"

@implementation Vertex @synthesize location=location_; @dynamic color, size;

- (id) initWithLocation:(CGPoint) aLocation {

if (self = [super init]) {

[self setLocation:aLocation]; }

  return self;
}

// default properties do nothing

  • -  (void) setColor:(UIColor *)color {}

  • -  (UIColor *) color { return nil; }

  • -  (void) setSize:(CGFloat)size {}

  • -  (CGFloat) size { return 0.0; }

    // Mark operations do nothing

CHAPTER 3: Prototype 55

56 CHAPTER 3: Prototype

- (void) addMark:(id <Mark>) mark {}
- (void) removeMark:(id <Mark>) mark {}
- (id <Mark>) childMarkAtIndex:(NSUInteger) index { return nil; } - (id <Mark>) lastChild { return nil; }

- (NSUInteger) count { return - (NSEnumerator *) enumerator

#pragma mark -
#pragma mark NSCopying method

// it needs to be implemented
- (id)copyWithZone:(NSZone *)zone {

Vertex *vertexCopy = [[[self class] allocWithZone:zone] initWithLocation:location_];

return vertexCopy; }

@end

In the overridden copyWithZone: method, a new instance of Vertex is created with [[self class] allocWithZone:zone] and initialized with the current location. [self class] is used because we want its subclasses to be able to reuse this copy method as well. If directly used [Vertex alloc], then its subclasses will just return a copy of Vertex but not its own actual type. Vertex only implements the location property, so once the new copy is initialized with the current location then vertexCopy is returned.

Vertex objects are used for composing strokes and don’t contain any other information such as color and size. But when there is a single point created on the screen by the user, we need another type of data structure to contain color and size to represent that dot. Besides color and size, location is also crucial to an individual dot. So we create a subclass of Vertex called Dot as shown in Listing 3–4.

Listing 3–4. Dot.h #import "Vertex.h"

@interface Dot : Vertex {

@private
UIColor *color_; CGFloat size_;

}

@property (nonatomic, retain) UIColor *color; @property (nonatomic, assign) CGFloat size;

- (id) copyWithZone:(NSZone *)zone;

@end

Similar to Vertex, it implements the copyWithZone: method to support copying in conjunction with the protocol. Its implementation of the method is shown in Listing 3.5.

0; }
{ return nil; }

for memento

Listing 3–5. Dot.m #import "Dot.h"

@implementation Dot
@synthesize size=size_, color=color_;

- (void) dealloc {

[color_ release];

[super dealloc]; }

#pragma mark -
#pragma mark NSCopying delegate method

- (id)copyWithZone:(NSZone *)zone {

Dot *dotCopy = [[[self class] allocWithZone:zone] initWithLocation:location_];

// copy the color
[dotCopy setColor:[UIColor colorWithCGColor:[color_ CGColor]]];

// copy the size [dotCopy setSize:size_];

return dotCopy; }

@end

The first initialization statement is almost the same as Vertex. Dot supports two more attributes types, so it also needs to set the color and size properties with its own color_ and size_ private variables on top of location. Both location and size can be assigned to a copy with zero concern. However, color needs some attention here. We need to make a copy of UIColor with an existing CGColor value in the color_ variable. Finally the method returns dotCopy.

Let’s move on to the Stroke class as shown in Listing 3–6. Listing 3–6. Stroke.h
#import "Mark.h"

@interface Stroke : NSObject <Mark, NSCopying> {

@private
UIColor *color_;
CGFloat size_; NSMutableArray *children_;

}

CHAPTER 3: Prototype 57

58 CHAPTER 3: Prototype

@property (nonatomic, retain) UIColor *color; @property (nonatomic, assign) CGFloat size; @property (nonatomic, assign) CGPoint location; @property (nonatomic, readonly) NSUInteger count; @property (nonatomic, readonly) id <Mark> lastChild;

- (void) addMark:(id <Mark>) mark;
- (void) removeMark:(id <Mark>) mark;
- (id <Mark>) childMarkAtIndex:(NSUInteger) index; - (id) copyWithZone:(NSZone *)zone;

@end

Then let’s see its implementation in Listing 3–7.

Listing 3–7. Stroke.m #import "Stroke.h"

@implementation Stroke

@synthesize color=color_, size=size_; @dynamic location;

- (id) init {

if (self = [super init]) {

children_ = [[NSMutableArray alloc] initWithCapacity:5]; }

  return self;
}
  • -  (void) setLocation:(CGPoint)aPoint {

    // it doesn't set any arbitrary location }

  • -  (CGPoint) location {

    // return the location of the first child if ([children_ count] > 0)
    {

    return [[children_ objectAtIndex:0] location]; }

    // otherwise returns the origin

    return CGPointZero; }

  • -  (void) addMark:(id <Mark>) mark {

    [children_ addObject:mark]; }

  • -  (void) removeMark:(id <Mark>) mark

{
// if mark is at this level then
// remove it and return
// otherwise, let every child
// search for it
if ([children_ containsObject:mark]) {

[children_ removeObject:mark]; }

else {

[children_ makeObjectsPerformSelector:@selector(removeMark:) withObject:mark];

} }

- (id <Mark>) childMarkAtIndex:(NSUInteger) index {

if (index >= [children_ count]) return nil;

return [children_ objectAtIndex:index]; }

// a convenience method to return the last child - (id <Mark>) lastChild
{

return [children_ lastObject]; }

// returns number of children

  • -  (NSUInteger) count {

    return [children_ count]; }

  • -  (void) dealloc {

    [color_ release]; [children_ release]; [super dealloc];

    }

    #pragma mark -
    #pragma mark NSCopying method

- (id)copyWithZone:(NSZone *)zone {

Stroke *strokeCopy = [[[self class] allocWithZone:zone] init];

// copy the color
[strokeCopy setColor:[UIColor colorWithCGColor:[color_ CGColor]]];

// copy the size

CHAPTER 3: Prototype 59

60 CHAPTER 3: Prototype
[strokeCopy setSize:size_];

// copy the children
for (id <Mark> child in children_) {

id <Mark> childCopy = [child copy]; [strokeCopy addMark:child]; [childCopy release];

}

return strokeCopy; }

@end

The Stroke class implements the same copyWithZone: method as the Vertex and Dot classes. But for Stroke, it needs to copy not only attributes that are defined in Mark but also its children (a for loop in the foregoing code). Each child in the children_ collection variable needs to make their own copy first, and then a Stroke object will add that cloned child to a cloned strokeCopy as a new child. When everything is cloned and set, it will return the strokeCopy as a clone of the original Stroke object.

You may have noticed that the location property that was declared in the Mark protocol is now defined as @dynamic in the @implementation scope of Stroke. A stroke doesn’t keep its own location on a view but just returns the location of its first child, if there is one. There are two overridden accessor methods for the location property to handle the special case. setLocation: doesn’t do anything, while location returns the screen coordinates of the stroke’s first child. We use @dynamic to tell the compiler not to generate those accessor methods for us as opposed to using @synthesize because we create own version of them. The details of the composite structure are discussed in Chapter 13.

We know that a Stroke object can contain any Mark reference as a child. A particular type is the Vertex; its purpose is to provide the location information to a drawing algorithm. Vertex is a direct subclass of Dot. Dot already has that copyWithZone: method implemented, as shown in Listing 3–3.

Now we have all the copying hocus-pocus set up, so we are ready to discuss how to use the prototype pattern to implement the “Pattern Template” feature.

Using a Cloned Mark As a “Pattern Template”

Now each subclass of Mark is clonable and able to return a true copy of it. One important use of object copying is for saving the state of it. In other words, a snapshot of what the object is at the moment when it is cloned (copied). When does it need to be copied? Undo and redo. Before executing an operation, the state of an object (e.g., a document) needs to be saved in some way. Then the state is pushed to an undo stack. When an undo operation is requested, the last state of the object (document) will be restored back to the application. Most of the time, copying objects is complicated and

error-prone. If clients handle the process, the client code may need to be changed every time there are some changes in a target class (e.g., document again). When we are talking about copying objects, we may be thinking only about some simple objects with just a few member variables and interfaces. However, things can go pretty wild when you need to deal with composite objects. It would be very complicated to clone a composite object just like that. A composite object could be very heavy-weighted and tricky to handle. You can picture traversing the whole structure and making new instances of each node with corresponding attributes. What’s even worse is that we don’t know the exact type of each node in the structure and that makes it even more complicated to create them externally. The implementation of prototype in the Mark family is not just a lifesaver for such situations but essential for the “Pattern Template” feature that we are going discuss in this section.

We want to reuse a particular stroke and make it as a “pattern template” to apply it to the CanvasView as a basis for drawing different things. The idea is to copy a particular Mark (either Stroke or Dot) and paste it on the CanvasView so the user can reuse the same pattern over and over again. A sample drawing based on that idea is shown in Figure 3–6.

Figure 3–6. A pattern with both original and cloned strokes—a black stroke indicates the original stroke. Gray strokes are copies of the black one.

The black stroke is the original stroke that was saved before as a pattern template. The gray ones are the clones of it. Both the black and gray strokes have the same shape. The cloned strokes may have different attributes in terms of color and location (or even transformation). The user can select whatever stroke onscreen and set it as a pattern template to be reused later. Each time the user applies the pattern, the application makes a copy out of the original and puts it on the CanvasView. Then the user can change the attributes, such as color, size, and location, of the stroke copies. A final structure that comprises the original stroke and the copies can be saved as another pattern template. The possibilities are unlimited.

We are not going too deep into this feature, but we will discuss the idea with some code snippets. I will leave this part for you to implement in the sample project as an exercise.

CHAPTER 3: Prototype 61

62 CHAPTER 3: Prototype

Let’s assume that we have an instance of Mark that was selected by the user as a pattern template called selectedMark. We will make a copy of it and save it in a data structure called templateArray, as shown in the snippet here.

id <Mark> patternTemplate = [selectedMark copy];

// save the patternTemplate in
// a data structure so it can be
// used later
[templateArray addObject:patternTemplate];

At this time, we have no idea what the user exactly selected. All we know is it’s an instance of Mark aggregate that could have just one Dot or multiple Strokes and each of them has multiple Vertex in it. With just a simple yet magical copy message sent to the selectedMark, we have a perfect copy of it. Now when the user wants to apply one of the previously saved pattern templates to the CanvasView, we will need to get it from the templateArray with a patternIndex provided by the user and append it to a current Mark composite. Then the new one will become part of the current one, as shown in the following snippet.

id <Mark> patternClone = [templateArray objectAtIndex:patternIndex]; [currentMark addMark:patternClone];
[canvasView setMark:currentMark];
[canvasView setNeedsDisplay];

After we set the canvasView with an updated Mark instance, we send a setNeedsDisplay message to it to draw the Mark on the screen.

Obviously we can’t add a copy of a stroke on the screen just like that without at least modifying its location; otherwise it may cover the original one if it’s still there. But the code snippets should be clear enough to showcase the idea of how to use the Prototype pattern that we have implemented in Mark to make this TouchPainter app more magical.

Summary

In this chapter, we have explored how to use the Prototype pattern to implement copying for the Mark composite structure in the TouchPainter app. A deep copying implementation is necessary for a Mark aggregate that contains a tree structure when we need to make a true copy of it. An example in the Memento pattern discussed in Chapter 23 keeps a copy of a complete Mark aggregate before saving it in a memento object.

The Prototype pattern is one of the simplest and easiest patterns for object creation. In the next chapter, you will see another object creation pattern that doesn’t use a copy method to create the same type of object, but a method that decides what type of object to create.