我有以下类:
Teacher
Student
Class (like a school class)
它们都是从具有以下代码的 KObject 扩展而来的:
- initWithKey
- send
- processKey
教师、学生班都使用 KObject 父类的函数 processKey 和 initWithKey。他们实现自己的发送版本。我遇到的问题是 KObject 永远不应该被实例化。它更像是一个抽象类,但在 objective-c 中没有抽象类概念。它仅对允许子类访问一个属性和两个函数有用。
我该怎么做才能使 KObject 无法实例化,但仍允许子类访问 KObject 的函数和属性?
抽象类在 Objective-C 中非常常见,类集群 - Cocoa 中广泛使用的模式 - 是抽象工厂模式的变体。
但是,正如您所注意到的,没有语言工具可以将方法或类显式划分为抽象 - 这通常在文档中完成。如果需要额外的安全性来确保类不会以意外的方式使用,则可以执行以下操作:
初始 化:
//Invocation of the initializer in a sub-class will not raise the exception.
if ([self class] == [MyAbstractClass class])
{
[NSException raise: . . . class is abstract - use subclass.
}
方法:
- (BOOL)someAbstractMethod
{
[NSException raise:NSInvalidArgumentException format:@"%@ is abstract",
NSStringFromSelector(_cmd)];
return NO;
}
协议与抽象基础
我不同意其他一些答案中提出的"最好使用协议"的说法。虽然可以将抽象基类与协议组合在一起,但不一定更好。
何时使用协议
使用协议指定集成合约 - 如插件架构。一个例子是"媒体播放器",其中电影和音频流的"播放"实现将完全不同。
何时使用抽象基类(或类集群)
当类层次结构之间的某些行为是共享的,并且某些实现细节在特定子类型之间有所不同时,请使用抽象基类。在这里使用协议不一定更好,除非您希望传达这组方法可交换为另一个实现的意图。
类集群:
对于类集群,获取其中一个子类型实例的工厂方法位于基类本身上。有时,这使得代码具有很好的可读性和凝聚力。(可能与您的特定示例无关,但与 Objective-C 中的抽象类相关的有趣观点)
一个笨拙的解决方案:
- (id)init { if ([self class] == [FastEnumerable class]) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:@"Error, attempting to instantiate KObject abstract class directly." userInfo:nil]; }
self = [super init]; if (self) {
// Initialization code here. }
return self; }
最好使用协议将"发送"作为抽象方法......
因为你写的抽象类在Objective-C中不受支持,所以很可能你不应该尝试"修复"它。Objective-C不像其他语言(如C ++/Java/C-Sharp语言)那样构建,并且不支持这些语言的某些功能。因此,当你编写"Objective-C"时,不要试图用Objective-C编写"Java",而是接受差异,并尝试以"Objective-C"的方式做一些事情,而不是做一些黑客,这可能只会让其他程序员更难,而不是更容易地使用或维护你的代码。