2012-04-12 3 views
2

Я пытаюсь реализовать концепцию программирования компонентов при написании своей игры iOS.Objective-C и компонентное программирование

В книге «Компонент программного обеспечения: Beyond объектно-ориентированное программирование» Клеменс Szyperski, он упоминает тактику:

(не цитата) Start с классом Duck, который добавляет компонент Quack. Класс Quack реализует интерфейс на любом объекте, который его вызывает, интерфейс указывает метод, в котором используется Quacks quack()

С этой настройкой Duck не имеет никакой ссылки или осведомленности о Quack, за исключением случаев, когда она создана и никогда не используется в Утке после этого. Другие объекты могут вызывать duckObject.quack() и достигать Quack, но только знают о объекте Duck.

До сих пор я пытался реализовать это без успеха. Желательно, чтобы утка не нуждалась в большем количестве кода, чем инстанцирование, а остальные - в классе Quack. Это можно сделать в Objective-C (для iOS?), Или мне лучше оставить COP для других языков?

+0

Я понимаю, что вы уже приняли ответ, но посмотрели ли вы на категории Objective-C? Вы можете реализовать категорию Quack в Duck, которая добавляет метод '-quack'. Класс Утки не должен был бы знать об этом. (Для чего это стоит, я с KillerX, что это звучит как ужасный дизайн анти-шаблона.) –

ответ

1

Я не думаю, что есть точное сравнение в ObjC, но это звучит, как вы хотите посмотреть в message forwarding. Если объекту отправлено сообщение, на которое он не отвечает, перед сообщением об ошибке, среда выполнения отправляет объект forwardInvocation: с аргументом NSInvocation, который инкапсулирует сообщение и аргументы.

В forwardInvocation: объект может пройти по вызову другому объекту, который делает обрабатывает это сообщение. Это позволяет Duck экземпляра, чтобы ответить на сообщение quack, даже если quack не реализуется Duck, удерживая ссылку на экземпляр Quack, который делает его реализацию:

- (void)forwardInvocation:(NSInvocation *)anInvocation 
{ 
    if([myQuack respondsToSelector:[anInvocation selector]]){ 
     [anInvocation invokeWithTarget:someOtherObject]; 
    } 
    else{ 
     [super forwardInvocation:anInvocation]; 
    } 
} 
+0

Возможно, это неправильное место, чтобы спросить об этом (больше CS), но здесь мы идем в любом случае: имеет ли смысл иметь набор/массив объектов (компонентов), и вы зацикливаете на них с помощью responseToSelector: и стреляйте в него на 1-ом найденный? Есть ли у кого-нибудь представление о том, какая производительность была бы такой (очевидно, чем больше объектов у вас есть)? – KillerX

+0

@ Киллер: Конечно, вы могли бы это сделать. Я не могу сказать, что будет хитом производительности; вы понесете стоимость n + 1 сообщений ('responsesToSelector:' * n, затем 'invokeWithTarget:'), но сообщения отправляются не так медленно, как все считают. Я был бы больше обеспокоен проектными последствиями одного объекта, притворяясь, что он реагирует на целую кучу методов другого класса. –

+0

Да, это правда, если ничто иное Xcode, вероятно, не даст вам предупреждения о газионе, поэтому реальные проблемы будут потеряны в шуме, и никто не сможет сказать, на какие селекторы реагирует эта вещь. Чтобы расширить его дальше в антипаттерн: «Да, вы можете динамически расширять объекты, используя другие объекты во время выполнения!» :) Можно даже дойти до того, что нужно написать «общий» объект, который только приобрел бы свою полную функциональность, добавив модули во время выполнения. (Кто-нибудь, рассматривающий это: BAAAAAAD IDEA !!!!) – KillerX

0

Не знаю, в чем ваш вопрос. Похоже, вам нужна слабая ссылка на класс. Первый класс утка

//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 

Затем реализовать класс Quack.

//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 

Теперь в какой-либо класс, который вы хотите:

//RandomClass.m 
[[[self duck] quacker] quack]; 
+0

Я ищу, чтобы каким-то образом реализовать функциональность компонента в его собственнике, без того, чтобы владелец знал о том, что компонент. Ваше решение, хотя и является слабым ориентиром, предполагает, что Quack известен Duck. Это то, чего я пытаюсь избежать :) –

+0

Я не вижу, как это выгодно. Что вы можете сделать, так это создать свойство типа 'id' и назначить его для объекта Quack' за пределами' Duck'. Там не было бы никаких потребностей в импорте, и «Дак» не знал бы, что это было или что он мог сделать. – ColdLogic

+0

Я прищурился. Я имел в виду, что Quacks insides, quack(), не должны быть известны Duck. Причины, которые я хочу построить, это ... любопытство для одного. Для учебных целей, почему это не должно быть сделано? –

Смежные вопросы