views:

240

answers:

1

Hi,

I need to develop a strategy pattern where i have a main class with other three classes where i need to refer to the objects of the other three classes using the main class object.To solve this is the strategy pattern will help me? If so please do give me the syntax in Objective-C?

+3  A: 

You'll want to look at Objective-C's protocol mechanism. Here's a simple protocol with a single required method:

@protocol Strategy <NSObject>

@required
- (void) execute;

@end

Then you declare a class that fulfills that protocol:

@interface ConcreteStrategyA : NSObject <Strategy>
{
    // ivars for A
}
@end

The implementation must provide the -execute method (since it was declared as @required):

@implementation ConcreteStrategyA

- (void) execute
{
    NSLog(@"Called ConcreteStrategyA execute method");
}

@end

You can make a similar ConcreteStrategyB class, but I'm not going to show it here.

Finally, make a context class with a property maintaining the current strategy.

@interface Context : NSObject
{
    id<Strategy> strategy;
}
@property (assign) id<Strategy> strategy;

- (void) execute;

@end

Here is the implementation. The method that delegates to the strategy's -execute method just happens to be called -execute as well, but it doesn't have to be.

@implementation Context

@synthesize strategy;

- (void) execute
{
    [strategy execute];
}

@end

Now I'll make a few instances and put them to use:

ConcreteStrategyA * concreteStrategyA = [[[ConcreteStrategyA alloc] init] autorelease];
ConcreteStrategyB * concreteStrategyB = [[[ConcreteStrategyB alloc] init] autorelease];
Context * context = [[[Context alloc] init] autorelease];

[context setStrategy:concreteStrategyA];
[context execute];
[context setStrategy:concreteStrategyB];
[context execute];    

The console output shows that the strategy was successfully changed:

2010-02-09 19:32:56.582 Strategy[375:a0f] Called ConcreteStrategyA execute method
2010-02-09 19:32:56.584 Strategy[375:a0f] Called ConcreteStrategyB execute method

Note that if the protocol does not specify @required, the method is optional. In this case, the context needs to check whether the strategy implements the method:

- (void) execute
{
    if ([strategy respondsToSelector:@selector(execute)])
        [strategy execute];
}

This is a common Cocoa pattern called delegation. For more information on delegation and other design patterns in Cocoa, see this.

Jon Reid
Thank u so much for the reply,one doubt what is the 'setStrategy' keyword here represents in the instances u have made.
Cathy
The `-setStrategy:` method is automatically generated by the `@synthesize` directive. If the property is declared `retain`, it takes care of doing retain/release (but you still have to release it in `-dealloc`). But if the property is declared `assign`, it does a simple assignment as a weak reference, with the assumption that the the assigned instance is guaranteed to exist and be managed elsewhere. In that case it should not be released. …In fact, I am going to change my answer to this second form.
Jon Reid
Thanks for the reply. The @protocol should i need to declare it in seperate file
Cathy
Generally you declare the @protocol in the same header that uses it. The strategy pattern is extremely common in Cocoa, though it's often referred to as Delegate.
Rob Napier
Rather than id<Strategy,NSObject>, it is usually better to make Strategy itself inherit from the <NSObject> protocol: "@protocol Strategy <NSObject>" This is almost always what you want, and simplifies usage.
Rob Napier
@Jon: Great overview of a very useful technique.
Rob Napier
Thanks so much for a very good reply
Cathy
The question of what you declare whhere is a separate question which revolves around reducing unnecessary recompilation. But I would put the protocol in its own header.
Jon Reid
Rob, thanks for pointing out the bit on making the protocol inherit from another protocol. I'm going to change my answer to reflect that, thanks!
Jon Reid
Now i am getting with the output, I have declared the @protocol in ConcreteStrategyA.h and ConcreteStrategyB.h files so in the Context.m there is warning as: duplicate declaration for the protocol Strategy. how should i solve this problem?
Cathy
Cathy, you're getting "duplicate declaration" because, uh, you're declaring it twice. Put the protocol in a header file instead.
Jon Reid
Hi Jon thanks!! now i got the warning cleared.
Cathy