objective-cprotocolsabstract-classcocoa-design-patterns

Abstract class in Objective-C


I need your help. Following problem in Objective-C:

// Robot.h
@protocol RobotProtocol <NSObject>
    -(void)doWork;
@end

@interface Robot : NSObject 


// Rob1 sublass of class Robot
// rob1.h
@interface Rob1 : Robot <RobotProtocol>

// rob1.m
@implementation
-(void)doWork
{
    // print 'robot 1'
}


// Rob2 sublass of class Robot
// rob2.h
@interface Rob2 : Robot <RobotProtocol>

// rob2.m
@implementation
-(void)doWork
{
    // print 'robot 2'
}



// Task.h
@interface Task : NSObject
{
    Robot *rob;
}


// Task.m
@implementation
- (id)init
{
    if ([super init]) {
        rob = [[Rob1 alloc] init]; // or Rob2 !!
    }
    return self;
}

-(void)doSomething
{
    [rob doWork]; // how to make sure, that this is implemented, depending on Rob1 or Rob2
}

How should Robot and its subclasses be implemented, that Robot *rob can be one of the subclasses of Robot rob1, rob2, ... and the method doWork:(BOOL)val; can be called? My first idea was to implement Robot as an abstract class, but unfortunately there are no abstract classes in Objective-C...

At the moment I am using a protocol, but I am not confident. Because it is not sure, that doWork is implemented, the compiler complains about

'Robot' may not respond to 'doWork'

Thank you for your ideas.


Solution

  • Protocols should work.

    @protocol RobotProtocol <NSObject>
    @required
    - (void)doWork:(BOOL)flag;
    @end
    
    @interface Robot1 : NSObject <RobotProtocol>
    @end
    
    @implementation Robot1
    - (void)doWork:(BOOL)flag
    {
    }
    @end
    

    Unit Test for Robot1 called though id<RobotProtocol>

    - (void)testRobot
    {
        id<RobotProtocol> robot = [[Robot1 alloc] init];
        [robot doWork:YES];
    }
    

    Update

    After looking at your code, @interface Robot : NSObject should be @interface Robot : NSObject <RobotProtocol>. The thing is you don't need @interface Robot : NSObject <RobotProtocol> at all. You can just use id<RobotProtocol>. This is the name of your abstract class.