Objective c - OOP 最佳实践问题
Objective c - OOP Best practices question
我是 Objective C 的新手。
假设有 3 个 class:厨师、食物、菜肴
如您所料:厨师烹制食物 -> 菜肴。
- (Dishe *)cook:(Food *)food;
现在我想添加 ChefFish、Fish 和 FishDishe class。
正如你所料:当厨师煮鱼时,我们将有 FishDishe
自然我会选择:
- (FishDishe *)fishTraitment:(Fish *)fish {
return [FishDishe alloc];
}
- (Dishe *)cook:(Food *)food {
if ([food isKindOfClass:[Fish class]]) {
return [self fishTraitement:food];
} else {
return [Dishe alloc];
}
}
然后我收到这个警告:
Incompatible pointer types sending 'Food *' to parameter of type 'Fish *'
当然,代码本身会按预期进行编译和运行。
警告不是真正的问题,因为我们可以通过转换或简单地在 cook 方法中移动 fishTraitment 块来避免它。
但是四处搜索,我发现一些话题说 using isKindOfClass is not 'clean'.
违反多态和面向对象原则
我的问题在这里:
此处最佳做法是什么?
请注意,我可以在其他地方使用具有通用 Chef 和 ChefFish 的 Chef 数组。
我希望:
Chef cook fish -> Dishe
ChefFish cook fish -> FishDishe
还有关于重载的问题,看起来我们不能有相同名称和相同数量参数的方法(具有不同类型和名称的事件),这在 Swift 中是可能的:(
Objective-C.
中没有像 C++ 那样的重载
尽量避免声明具有未使用参数的方法。如果你这样做,你只会让你的堆栈浪费比需要更多的内存。
所有 Objective-C 对象通常在某些时候继承自 NSObject。
所以他们都默认继承了一些方法。例如:alloc
、init
、new
(立即调用 alloc+init)、dealloc
.
@interface Cook : NSObject
-(instancetype)init; //default anyway..
@end
@interface Fish : NSObject
-(instancetype)initWithCook:(Cook*)cook; //not default
// so Fish has also one 'init' method even if not declared explicit.
@end
@interface Dish : NSObject
-(instancetype)initWithCook:(Cook*)cook;
-(instancetype)initWithCook:(Cook*)cook AndFish:(Fish*)fish;
@end
@interface SmellyFish : Fish
-(void)washSmellyDish:(Dish*)dish;
@end
您可以查看 NSObject 的声明并遍历因此任何 NSObject 继承的默认方法。
上面的示例:Cook、Dish 和 Fish 继承自 NSObject,因此您可以请求 [object isKindOfClass:[NSObject class]]
这有点多余,因为几乎所有 objc-object 都在某些时候继承自 NSObject。但是 SmellyFish 在这里继承自 Fish,所以你可以问是 isKindOfClass
Fish、SmellyFish 还是 NSObject,它应该回答是。
如果您需要确定某些 obj 是某些特定的 class,请改用
[obj isMemberOfClass:[Fish class]]
所以也许你会做类似的事情..
-(FishDish *)fishDish {
return [FishDish new];
}
-(Dish *)cook:(id)food {
if ([food isKindOfClass:[Fish class]]) {
return [self fishDish]; //FishDish must be a subclass of Dish
} else {
return [[Dish alloc] init];
}
}
看到(id)food
? id
是一个 Objective-C 特定的数据类型,表示某些(任何类型的)NSObject
的 C 指针。你也可以写 id<SuperFood> food
来表达你期望一些遵循一些特定协议的指针作为对象引用。这类似于 (SuperFood*)food
,其中 SuperFood*
将声明它必须是指向一个 SuperFood
对象的指针。
也许在要求符合特定数据类型之前避免强制转换也是一个好习惯,因为仅通过强制转换就可能使对 isKindOfClass 的方法调用变得毫无价值。
你想检查,所以避免铸造。
因为如果你转换太多并且实际上不知道参考中给出的数据类型,你最好使用 id
或 NSObject*
。当您甚至不在实现文件的那部分使用它的方法时,这种做法还可以防止您导入更多代码只是为了声明某些特定数据类型。
我是 Objective C 的新手。
假设有 3 个 class:厨师、食物、菜肴
如您所料:厨师烹制食物 -> 菜肴。
- (Dishe *)cook:(Food *)food;
现在我想添加 ChefFish、Fish 和 FishDishe class。
正如你所料:当厨师煮鱼时,我们将有 FishDishe
自然我会选择:
- (FishDishe *)fishTraitment:(Fish *)fish {
return [FishDishe alloc];
}
- (Dishe *)cook:(Food *)food {
if ([food isKindOfClass:[Fish class]]) {
return [self fishTraitement:food];
} else {
return [Dishe alloc];
}
}
然后我收到这个警告:
Incompatible pointer types sending 'Food *' to parameter of type 'Fish *'
当然,代码本身会按预期进行编译和运行。
警告不是真正的问题,因为我们可以通过转换或简单地在 cook 方法中移动 fishTraitment 块来避免它。
但是四处搜索,我发现一些话题说 using isKindOfClass is not 'clean'.
违反多态和面向对象原则
我的问题在这里:
此处最佳做法是什么?
请注意,我可以在其他地方使用具有通用 Chef 和 ChefFish 的 Chef 数组。
我希望:
Chef cook fish -> Dishe
ChefFish cook fish -> FishDishe
还有关于重载的问题,看起来我们不能有相同名称和相同数量参数的方法(具有不同类型和名称的事件),这在 Swift 中是可能的:(
Objective-C.
中没有像 C++ 那样的重载尽量避免声明具有未使用参数的方法。如果你这样做,你只会让你的堆栈浪费比需要更多的内存。
所有 Objective-C 对象通常在某些时候继承自 NSObject。
所以他们都默认继承了一些方法。例如:alloc
、init
、new
(立即调用 alloc+init)、dealloc
.
@interface Cook : NSObject
-(instancetype)init; //default anyway..
@end
@interface Fish : NSObject
-(instancetype)initWithCook:(Cook*)cook; //not default
// so Fish has also one 'init' method even if not declared explicit.
@end
@interface Dish : NSObject
-(instancetype)initWithCook:(Cook*)cook;
-(instancetype)initWithCook:(Cook*)cook AndFish:(Fish*)fish;
@end
@interface SmellyFish : Fish
-(void)washSmellyDish:(Dish*)dish;
@end
您可以查看 NSObject 的声明并遍历因此任何 NSObject 继承的默认方法。
上面的示例:Cook、Dish 和 Fish 继承自 NSObject,因此您可以请求 [object isKindOfClass:[NSObject class]]
这有点多余,因为几乎所有 objc-object 都在某些时候继承自 NSObject。但是 SmellyFish 在这里继承自 Fish,所以你可以问是 isKindOfClass
Fish、SmellyFish 还是 NSObject,它应该回答是。
如果您需要确定某些 obj 是某些特定的 class,请改用
[obj isMemberOfClass:[Fish class]]
所以也许你会做类似的事情..
-(FishDish *)fishDish {
return [FishDish new];
}
-(Dish *)cook:(id)food {
if ([food isKindOfClass:[Fish class]]) {
return [self fishDish]; //FishDish must be a subclass of Dish
} else {
return [[Dish alloc] init];
}
}
看到(id)food
? id
是一个 Objective-C 特定的数据类型,表示某些(任何类型的)NSObject
的 C 指针。你也可以写 id<SuperFood> food
来表达你期望一些遵循一些特定协议的指针作为对象引用。这类似于 (SuperFood*)food
,其中 SuperFood*
将声明它必须是指向一个 SuperFood
对象的指针。
也许在要求符合特定数据类型之前避免强制转换也是一个好习惯,因为仅通过强制转换就可能使对 isKindOfClass 的方法调用变得毫无价值。
你想检查,所以避免铸造。
因为如果你转换太多并且实际上不知道参考中给出的数据类型,你最好使用 id
或 NSObject*
。当您甚至不在实现文件的那部分使用它的方法时,这种做法还可以防止您导入更多代码只是为了声明某些特定数据类型。