我想接受一个Class对象作为我的一个类的构造函数的参数。它需要用它做很多自定义工作,我想从类的用户那里抽象出来。
例如,假设我的班级是经销商,我想用任何类型的车辆初始化它。
所以我有以下层次结构:
Dealership : NSObject
Vehicle : NSObject
Truck : Vehicle
Van : Vehicle
Car : Vehicle
我想要做的是,在经销商内部,实现以下初始化程序:
- (id)initWithVehicle:(Class)aVehicle;
除了不接受泛型类之外,我想将其限制为仅仅类型为“Vehicle”的类(其中包括我所有的继承类)。我可以在初始化程序中测试此属性,但如果有一种方法可以在编译时强制执行此操作而不是等待运行时反馈,那将会很棒。
看来你可以引用Class来限制实现某个接口的类,所以我可以在那里做一些hackery。有没有办法引用特定类型的Class对象?
编辑 - 请注意,我编辑了示例类,因为原始示例有点误导。该示例仅用于演示目的,而不是我正在使用的实际类层次结构。
不是在编译时,但你可以发布 self
并返回 nil
如果课程无效:
- (id)initWithCar: (Class)carClass {
self = [super init];
if (self) {
if (![carClass isSubclassOfClass:[Car class]]) {
[self release];
self = nil;
} else {
// Normal initialization here.
}
}
return self;
}
这是你最接近你想要的那种限制。
但是这种设计表明你需要重新思考你的类层次结构。而不是传递一个子类 Car
,你应该有一个 Manufacturer
类。像这样的东西:
@interface Manufacturer : NSObject
+ (id)manufacturerWithName: (NSString *)name;
- (NSArray *)allCars;
@property (readonly) Car *bestsellingCar;
// etc.
@end
#define kManufacturerVolvo [Manufacturer manufacturerWithName: @"Volvo"]
#define kManufacturerToyota [Manufacturer manufacturerWithName: @"Toyota"]
// etc.
然后这个经销商的初始化程序:
- (id)initWithManufacturer: (Manufacturer *)aManufacturer;
您可以确保使用协议检查:
- (id)initWithVehicle:(id<VehicleProtocol>)aVehicle;
...
}
将对象声明为id告诉编译器您不关心对象的类型,但您确实知道它符合指定的VehicleProtocol协议**。
我不确定你到底得到了什么样的解决方案,但也许正在对待 Vehicle
作为类集群,您可以在一个保护伞下合并通用功能,并让类集群管理不同的实现(并将其与用户屏蔽)?
例如, NSString
做这个;底层实例通常是类型 NSCFString
,除非他们是文字(即 @"this is a literal, in code"
),在这种情况下他们是 NSConstantString
秒。
这里 摘自相关博客文章,解释类集群:
简而言之,它是一种设计,允许您将一系列功能相关的对象合并到您的应用程序中,同时保持代码与这些对象的交互,松散耦合,灵活,易于维护或更新。
类集群使这组公共对象符合单个接口的行为,并且通过该接口引导它们的所有创建。构造由两个关键部分组成:a)一个公共抽象接口,作为集群的“面”,用于通告支持的API; b)该接口的许多私有,具体子类,负责实际实现广告行为超自然的特定方式。抽象超类本身实现了一些方法,最重要的是一个工厂方法来销售私有子类的实例;所有子类(如访问器)共享的其他常用功能也可以在此处定义并共享。
集群的用户只看到一个公共超类,不知道它实际上是抽象的,并且对任何私有具体子类的存在一无所知。超类提供工厂创建方法,该方法负责确定哪个子类适用于任何给定情况并透明地返回它的实例。由于此返回的对象根据公共超类的接口实现并运行,因此用户可以简单地假设他们已获得此超类的直接实例。
如果您想使用车辆初始化经销商(我的意思是初始化实例),您应该:
- (id)initWithCar:(Vehicle *)carClass
{
//An extra check (only for DEBUG mode)
NSAssert([carClass isKindOfClass:[Vehicle class]]);
... //carClass is now a Vehicle instance
}