hac*_*nal 26 ruby mixins objective-c-2.0
在Ruby中,有模块,您可以通过"混入"模块来扩展类.
module MyModule
def printone
print "one"
end
end
class MyClass
include MyModule
end
theOne = MyClass.new
theOne.printone
>> one
Run Code Online (Sandbox Code Playgroud)
在Objective-C中,我发现我有一组常用的方法,我想要一些Class来"继承".如果不创建一个公共类并从该公共类派生所有其他方法,我可以通过什么方式实现这一目标?
Vla*_*vic 31
无耻插件:ObjectiveMixin
它利用了Objective-C运行时在运行时向类添加方法的能力(与类别相反,仅为编译时).看看它,它的工作非常好,并且与Ruby的mixins类似.
Jea*_*uys 28
编辑:添加了更改,因为有些人认为我负责Objective-C的限制.
简短的回答:你做不到.Objective-C没有Ruby mixins的等价物.
稍微简短的回答:Objective-C确实有一些可以说是相同的味道:协议.协议(一些其他语言中的接口)是一种定义一组方法的方法,一个采用该协议的类承诺实现.但协议不提供实现.这种限制阻止使用协议作为Ruby mixins的精确等价物.
更简短的答案:但是,Objective-C运行时有一个公开的API,可以让您使用该语言的动态功能.然后你走出语言,但你可以拥有默认实现的协议(也称为具体协议).弗拉基米尔的答案显示了一种方法.在那一点上,在我看来你得到Ruby mixins没问题.
但是,我不确定我会建议那样做.在大多数情况下,其他模式符合条件,而无需使用运行时游戏.例如,您可以拥有一个实现混合方法的子对象(has-a而不是is-a).使用运行时是可以的,但有两个缺点:
您使代码的可读性降低,因为它要求读者比语言知道的更多.当然你可以(并且应该)对它进行评论,但请记住,任何必要的评论都可以被视为实施缺陷.
你依靠的是语言的实现.当然,Apple平台是迄今为止最常见的Objective-C平台,但不要忘记Cocotron或GnuStep(或Etoilé)有不同的运行时间,在这方面可能与苹果兼容.
作为旁注,我在下面说明类别不能将状态(实例变量)添加到类中.通过使用运行时API,您也可以解除该限制.然而,这超出了这个答案的范围.
答案很长:
两个Objective-C功能看起来像可能的候选者:类别和协议.如果我正确理解这个问题,那么类别在这里并不是正确的选择.正确的功能是协议.
让我举个例子.假设您希望一堆类具有称为"唱歌"的特定能力.然后定义协议:
@protocol Singer
- (void) sing;
@end
Run Code Online (Sandbox Code Playgroud)
现在,您可以通过以下方式声明您自己的任何类都采用该协议:
@interface Rectangle : Shape <Singer> {
<snip>
@end
@interface Car : Vehicle <Singer> {
<snip>
@end
Run Code Online (Sandbox Code Playgroud)
通过声明他们采用协议,他们承诺实施该sing
方法.例如:
@implementation Rectangle
- (void) sing {
[self flashInBrightColors];
}
@end
@implementation Car
- (void) sing {
[self honk];
}
@end
Run Code Online (Sandbox Code Playgroud)
然后你使用这些类,例如:
void choral(NSArray *choir) // the choir holds any kind of singer
{
id<Singer> aSinger;
for (aSinger in choir) {
[aSinger sing];
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,数组中的歌手不需要具有共同的超类.另请注意,一个类只能有一个超类,但许多采用的协议.最后注意,类型检查由编译器完成.
实际上,协议机制是用于mixin模式的多重继承.由于协议无法向类中添加新的实例变量,因此多重继承受到严重限制.协议仅描述了采用者必须实现的公共接口.与Ruby模块不同,它不包含实现.
这是最重要的.但是,让我们提一下类别.
声明类别不在尖括号中,而是在括号之间声明.不同之处在于可以为现有类定义类别以扩展它,而无需对其进行子类化.您甚至可以为系统类执行此操作.可以想象,可以使用类别来实现类似于mixin的东西.并且它们通常以这种方式使用,通常作为类别NSObject
(继承层次结构的典型根),在某种程度上被称为"非正式"协议.
这是非正式的,因为1-编译器没有进行类型检查,并且实现协议方法是可选的.
今天不需要使用类别作为协议,特别是因为正式协议现在可以声明它们的一些方法对于关键字@optional
或者必需(默认值)是可选的@required
.
类别对于向现有类添加某些特定于域的行为仍然很有用.NSString
是一个共同的目标.
同样有趣的是,大多数(如果不是全部)NSObject
设施实际上是在NSObject
协议中声明的.这意味着将它NSObject
作为所有类的公共超类使用并不是真的很有吸引力,尽管这仍然是出于历史原因通常所做的,而且......因为这样做没有任何缺点.但是一些系统类,例如NSProxy
,不是 NSObject
.
Rad*_*lin 11
你可以使用#include从字面上混合代码.这是不可取的,并且反对目标c中的所有宗教,但是完美无缺.
请不要在生产代码中执行此操作.
例如在文件中:
MixinModule.header (不应编译或复制到目标)
-(void)hello;
Run Code Online (Sandbox Code Playgroud)
MixinModule.body (不应编译或复制到目标)
-(void)hello{
NSLog(@"Hello");
}
Run Code Online (Sandbox Code Playgroud)
在mixin类中:
@interface MixinTest : NSObject
#include "MixinModule.header"
@end
@implementation MixinTest
#include "MixinModule.body"
@end
Run Code Online (Sandbox Code Playgroud)
使用案例:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]){
@autoreleasepool {
[[[MixinTest new] autorelease] hello];
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请不要在生产代码中执行此操作.
归档时间: |
|
查看次数: |
6416 次 |
最近记录: |