Skip to content

Instantly share code, notes, and snippets.

@matzew
Created October 15, 2012 11:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matzew/3892038 to your computer and use it in GitHub Desktop.
Save matzew/3892038 to your computer and use it in GitHub Desktop.
Builder Pattern for AGPipe creation

Builder Pattern for AGPipe creation

Right now the AGPipeline is used as a factory to create a concrete AGPipe object, by using its several add methods.

The more options we add (to the AGPipe) in the future, the more verbose the add API becomes. Today we have already several overloaded add methods. Below is an example of a complete add, which takes all current allowed arguments:

-(id<AGPipe>) add:(NSString*) name baseURL:(NSURL*)baseURL endpoint:(NSString*)endpoint type:(NSString*)type;

Change the AGPipeline API and use the builder pattern

The proposal is to use the 'Builder Patter' for the actual pipe creation. On the pipeline we will REMOVE the several add methods and introduce a new 'newPipe' method, which simply returns the Builder API.

/**
 * AGPipeline represents a 'collection' of server connections (pipes) and
 * their corresponding data models. This object provides a standard way to
 * communicate with the server no matter the data format or transport expected.
 *
 * A pipeline must have at least one pipe.
 */
@interface AGPipeline : NSObject

/**
 * Returns the AGPipeBuilder which helps to build new AGPipe objects
 * and attach them to the AGPipeline object.
 * 
 * @return the AGPipeBuilder object which is used to describe the new pipe
 */
-(id<AGPipeBuilder>) newPipe;

/**
 * Removes a pipe from the AGPipeline object
 *
 * @param name the name of the actual pipe
 *
 * @return the new created AGPipe object
 */
-(id<AGPipe>) remove:(NSString*) name;

/**
 * Look up for a pipe object.
 *
 * @param name the name of the actual pipe
 *
 * @return the new created AGPipe object
 */
-(id<AGPipe>) get:(NSString*) name;

@end

The builder protocol is used to describe the which arguments are used, in order to create the complex AGPipe object:

@protocol AGPipeBuilder <NSObject>

// set the values:
-(id<AGPipeBuilder>) withName:(NSString*) name;
-(id<AGPipeBuilder>) withEnpoint:(NSString*) endpoint;
-(id<AGPipeBuilder>) withType:(NSString*) type;
-(id<AGPipeBuilder>) withBaseURL:(NSURL*) baseURL;
// and even more... if needed...

//create it...
-(id<AGPipe>) buildAndAdd;

@end

Now with some Objective-C syntactic sugar (Categories), we make the AGPipeline class a PRIVATE implementation of the AGPipeBuilder protocol, by using a Objective-C Category. Below is the important section of the AGPipeline IMPLEMENTATION file (AGPipeline.m):

// "private" builder category which allows a "private" implementation of the 'AGPipeBuilder' protocol
@interface AGPipeline(Builder)<AGPipeBuilder>

@end

// category
@interface AGPipeline ()
// concurrency...
@property (atomic, copy) NSMutableDictionary* pipes;
@end

@implementation AGPipeline {
    // ivars...
    NSURL* _baseURL;
}
@synthesize pipes = _pipes;


- (id)init {
    self = [super init];
    if (self) {
        _pipes = [NSMutableDictionary dictionary];
    }
    return self;
}
....
....

@end // end of the 'public' AGPipeline
/// private implementation of the AGPipeBuilder protocol
@implementation AGPipeline(Builder)

-(id<AGPipeBuilder>) withName:(NSString*) name {
    // store the argument....
    return self;
}
-(id<AGPipeBuilder>) withEnpoint:(NSString*) endpoint {
    // store the argument....
    return self;
}
-(id<AGPipeBuilder>) withType:(NSString*) type {
    // store the argument....
    return self;
}
-(id<AGPipeBuilder>) withBaseURL:(NSURL*) baseURL {
    // store the argument....
    return self;
}

//create it...
-(id<AGPipe>) buildAndAdd {
    // create the AGPipe object and add it to the _pipes collection:
    [_pipes setValue:agpipeObject forKey:someKeyForthePipe];
    return setValue:agpipeObject;
}

@end

The benefit of making the AGPipeline a private implementation of the builder pattern is, that it can access all the instance variables (and private methods) from the actual AGPipeline class. If you take a close look at the above buildAndAdd method, you see that it not only builds the concrete AGPipe instance, it also automatically adds it to the "pipes" collection (similar to the previous add.....)

Usage of the builder pattern:

// create an empty pipeline:
AGPipeline* myPipeline = [[AGPipeline alloc] init];
    
// create a pipe, by using the builder pattern...:
id<AGPipe> tasksPipe = [[[[myPipeline newPipe] withName:@"logicalName"] withEnpoint:@"tasks" ] buildAndAdd];

Downside is, IMO, the deeply nested calls...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment