3

I am trying to implement the concept of component programming while writing my iOS game.

In the book "Component Software: Beyond Object-Oriented Programming" by Clemens Szyperski, he mentions a tactic:

(not quote) Start with a Duck class, which adds component Quack. Class Quack implements an interface on whichever object that calls it, the interface specifies a method which uses Quacks quack()

With this setup, Duck has no reference or awareness about Quack except for when it's instantiated, and is never used in Duck thereafter. Other objects can call duckObject.quack() and reach Quack while only being aware of Duck object.

So far, I've been trying to implement this without success. Preferably, Duck should need no more code than instantiation, the rest placed in Quack class. Can this be done in Objective-C (for iOS?), or am I better off leaving COP for other languages?

C-A
  • 699
  • 1
  • 6
  • 11
  • I realize you've already accepted an answer, but have you looked at Objective-C's categories? You can implement a Quack category on Duck which adds the `-quack` method. The Duck class wouldn't need to be aware of this. (For what it's worth, I'm with KillerX that this sounds like a terrible design anti-pattern.) – Ken Thomases Apr 14 '12 at 09:06

2 Answers2

2

I don't think there's an exact comparison in ObjC, but it sounds like you want to look into message forwarding. If an object is sent a message to which it doesn't respond, right before an error is signaled, the runtime sends the object forwardInvocation:, with an NSInvocation argument that encapsulates the message and arguments.

In forwardInvocation:, an object can pass along the invocation to another object which does handle that message. This allows a Duck instance to respond to the message quack, even though quack is not implemented by Duck, by holding a reference to an instance of Quack, which does implement it:

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if( [myQuack respondsToSelector:[anInvocation selector]] ){
        [anInvocation invokeWithTarget:someOtherObject];
    }
    else{
        [super forwardInvocation:anInvocation];
    }
}
jscs
  • 63,694
  • 13
  • 151
  • 195
  • Maybe the wrong place to ask this (more CS) but here we go any way: Would it make sense to have a set/array of objects (components), and you loop over them with respondsToSelector: and fire it on the 1st one found? Does anyone have an idea what kind of performance hit that would be (obviously the more objects you have...)? – KillerX Apr 12 '12 at 07:22
  • @Killer: Sure, you could do that. I can't say what the performance hit would be; you're incurring the cost of n+1 message sends (`respondsToSelector:` * n, then `invokeWithTarget:`), but message sends aren't really as slow as everyone thinks they are. I'd be more worried about the design implications of one object pretending that it responds to a whole bunch of other class's methods. – jscs Apr 12 '12 at 07:28
  • Yes, that is true, if nothing else Xcode would probably give you a gazilion warnings so real problems would get lost in the noise + noone would really be able to tell what selectors that thing responds to. To expand it further into an antipattern: "Yay, you can dynamically extend objects using other objects at run-time!" :) One could even go as far as to write a "generic" object that would only acquire its full functionality by adding modules at run time. (To anyone considering this: BAAAAAAD IDEA!!!!) – KillerX Apr 12 '12 at 07:35
0

Not really sure what your question is. It sounds like you want a weak reference to a class. First the duck class

//Duck.h
#import "Quack.h"

@interface Duck : NSObject {
    Quack *quacker;
}

@property (nonatomic, retain) Quack *quacker;

@end

//Duck.m

@implementation Duck
@synthesize quarker;

-(id) init {
    self = [super init];

    if(self) {

    }

    return self;
}

-(Quack *)quacker {
    if(quacker == nil) {
        [self setQuacker:[[[Quack alloc] init] autorelease]];
    }

    return quacker;
}

@end

Then implement the Quack class.

//Quack.h

@interface Quack : NSObject {

}

-(void)quack;

@end

//Quack.m

@implementation Quack 

-(id) init {
    self = [super init];

    if(self) {

    }

    return self;
}

-(void)quack {
    NSLog(@"quack");
}
@end

Now in what ever class you want:

//RandomClass.m
[[[self duck] quacker] quack];
ColdLogic
  • 7,206
  • 1
  • 28
  • 46
  • What I am looking for is to somehow implement the functionality of the component into it's owner, without the owner being aware of what the component does. Your solution, while still being a weak reference, assumes Quack is known by Duck. This is what I'm trying to avoid :) – C-A Apr 12 '12 at 08:00
  • I don't see how that is beneficial. What you could do is create a property of type `id` and assign it to a `Quack` object outside of `Duck`. There would not be any needs for imports and `Duck` wouldn't know wth that thing was or what it could do. – ColdLogic Apr 12 '12 at 08:57
  • I screwed up. What I meant was that Quacks insides, quack(), should not be known by Duck. The reasons I want to build it is... curiosity for one. For learning purposes, why should this not be done? – C-A Apr 13 '12 at 05:43