Tuesday, April 9, 2013

Observer Design Pattern - Objective C



Myself and my friend Suresh, Vibin are interested in knowng the book publisher's new release. we do not want to call them to check for the new published books, instead we should get notified when ever there is an release.  So we asked them to note down our mobile number  to call and update us.

How to solve this problem in software.

Stalin, suresh, and vibin, These people are going to be an observer. BookPublisher is going to inform me whenever there is a new book is published.

PublisherDelegate:

This is an interface, any publisher interested in notifying/informing others should implement the interface. This is a guideline to all the publishers to keep the same interface so that the observer no need to remember too many interface name whenever they are interested to register with a publisher.

Tomorrow there will be different publisher comes into picture, so we have to provide the common interface  for all the publisher. so its better to start with common interface, so observer already aware about the method signature.

#import <Foundation/Foundation.h>
#import "ObserverDelegate.h"

@protocol PublisherDelegate <NSObject>

-(void) registerObserver:(id) observer;
-(void) unRegisterObserver:(id) observer;
-(void) notifyObservers;

@end


As i told earlier the BookPublisher implements the interface PublisherDelegate.

#import <Foundation/Foundation.h>
#import "PublisherDelegate.h"

@interface BookPublisher : NSObject<PublisherDelegate>
{
    NSMutableArray *observers;
    NSString *newBook;
}

-(void) setNewBook:(NSString *) bookName;

@end



BookPublisher maintains a list to keep track all the observer to notify later point of time. 
#import "BookPublisher.h"
#import "ObserverDelegate.h"

@implementation BookPublisher

- (id)init
{
    self = [super init];
    if (self) {
        observers = [[NSMutableArray alloc] init];
    }
    return self;
}

-(void) registerObserver:(id) newObserver
{
    if ([observers containsObject:newObserver] == NO) {
        [observers addObject:newObserver];
    }
}

-(void) unRegisterObserver:(id) oldObserver
{
    if ([observers containsObject:oldObserver]) {
        [observers removeObject:oldObserver];
    }
}

-(void) notifyObservers
{
    for (id<ObserverDelegate> observer in observers) {
        
        if ([observer conformsToProtocol:@protocol(ObserverDelegate)])
        {
            [observer newBookAvailable:newBook];
        }
    }
}

-(void) setNewBook:(NSString *) bookName
{
    newBook = bookName;
    [self notifyObservers];
}

@end



We have an base class Observer  which provides the basic functionality to register with publisher. The registration goes as part of the observer object creation. User has to pass the publisher as part of initialization process so the Observer will take care to register with the publisher. Observer do not want to explicitly call the register method.


#import <Foundation/Foundation.h>
#import "PublisherDelegate.h"

@interface Observer : NSObject
{
    id<PublisherDelegate> thePublisher;
}

-(id) initWithPublisher:(id<PublisherDelegate>) newPublisher;

@end




#import "Observer.h"

@implementation Observer

-(id) initWithPublisher:(id<PublisherDelegate>) newPublisher
{
    self = [super init];
    
    if (self) {
        thePublisher = newPublisher;
        [thePublisher registerObserver:self];

    }
    
    return self;
}
@end





#import <Foundation/Foundation.h>

@protocol ObserverDelegate <NSObject>

-(void) newBookAvailable:(NSString*) book;

@end

#import <Foundation/Foundation.h>
#import "Observer.h"

@interface Stalin : Observer<ObserverDelegate>
{
    
}

@end




#import "Stalin.h"

@implementation Stalin

-(void) newBookAvailable:(NSString*)book
{
    NSLog(@"Stalin: \nNew Book %@", book);
}

@end




#import <Foundation/Foundation.h>
#import "Observer.h"

@interface Suresh : Observer<ObserverDelegate>

@end




#import "Suresh.h"

@implementation Suresh

-(void) newBookAvailable:(NSString*)book
{
    NSLog(@"Suresh: \nNew Book %@", book);
}

@end




#import <Foundation/Foundation.h>
#import "Observer.h"

@interface Vibin : Observer<ObserverDelegate>

@end




#import "Vibin.h"

@implementation Vibin

-(void) newBookAvailable:(NSString*)book
{
    NSLog(@"Vibin: \nNew Book %@", book);
}

@end




#import <UIKit/UIKit.h>
@class Stalin;
@class Suresh;
@class Vibin;

@interface ViewController : UIViewController
{
    Stalin *stalinTheObserver;
    Suresh *sureshTheObserver;
    Vibin *vibinTheObserver;
}

@end




#import "ViewController.h"
#import "BookPublisher.h"
#import "Stalin.h"
#import "Suresh.h"
#import "Vibin.h"


@interface ViewController ()

@end


@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
}


-(void) viewDidAppear:(BOOL)animated
{
    BookPublisher *bookPublisher = [[BookPublisher alloc] init];
    
    stalinTheObserver = [[Stalin alloc] initWithPublisher:bookPublisher];
    sureshTheObserver = [[Suresh alloc] initWithPublisher:bookPublisher];
    vibinTheObserver = [[Vibin alloc] initWithPublisher:bookPublisher];
    
    
    
    [bookPublisher setNewBook:@"Test your C++ skills"];
    [bookPublisher setNewBook:@"8086 Assembly Language"];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}







The output will look like below


2013-04-09 13:02:48.722 ObserverDesignPattern[25839:11303] Stalin: 
New Book Test your C++ skills
2013-04-09 13:02:48.724 ObserverDesignPattern[25839:11303] Suresh: 
New Book Test your C++ skills
2013-04-09 13:02:48.725 ObserverDesignPattern[25839:11303] Vibin: 
New Book Test your C++ skills
2013-04-09 13:02:48.725 ObserverDesignPattern[25839:11303] Stalin: 
New Book 8086 Assembly Language
2013-04-09 13:02:48.726 ObserverDesignPattern[25839:11303] Suresh: 
New Book 8086 Assembly Language
2013-04-09 13:02:48.726 ObserverDesignPattern[25839:11303] Vibin: 
New Book 8086 Assembly Language

No comments: