一、继承
不恰当的使用继承导致的最大的一个特征就是高耦合。
是否使用继承需要考虑三个点:
- 父类只是给子类提供服务,并不涉及子类的业务逻辑
- 层级关系明显,功能划分清晰,父类和子类各做各的。
- 父类的所有变化,都需要在子类中体现,也就是说此时耦合已经成为需求
万不得已不要用继承,优先考虑组合等方式。
- 如果只是共享接口,我们可以使用协议;
@protocol ptc <NSObject>
- (void)do;
@end
@interface A : NSObject<ptc>
@end
@implementation A
- (void)do
{
}
@end
@interface B : NSObject<ptc>
@end
@implementation B
- (void)do
{
}
@end
- 如果希望共用一个方法的部分实现,但希望根据需要执行不同的其他行为,我们可以使用代理或者 AOP;
@protocol ptc <NSObject>
- (void)do;
@end
@interface A : NSObject
@property (nonatomic, weak) id<ptc>delegate;
@end
@implementation A
- (void)func
{
...
[self.delegate do];
...
}
@end
@interface B : NSObject <ptc>
@end
@implementation B
- (void)do
{
}
@end
- 如果是添加方法,我们可以优先使用类别;
- 如果是为了使用一个类的很多方法,我们可以使用组合来实现。
@interface A : NSObject
- (void)methodA;
@end
@interface B : NSObject
-(void)methodB;
@end
// 定义 C 以及其需要的 methodA,methodB
@interface C : NSObject
{
A * __a;
B * __b;
}
- (id)initWithA:(A *)a b:(B *)b;
- (void)methodA;
- (void)methodB;
@end
@implementation ClassC
- (id)initWithA:(A *)a b:(B *)b
{
__a = [[A alloc] initWithA:a]; // [A copy];
__b = [[B alloc] initWithB:b]; // [B copy];
}
- (void)methodA
{
[__a methodA];
}
- (void)methodB
{
[__b methodB];
}
@end
如果只是出于代码复用的目的而不区分类别和场景,就采用继承是不恰当的。当你发现你的继承超过 2 层的时候,你就要好好考虑是否这个继承的方案了,第三层继承正是滥用的开端。
二、多态
使用场景:
- 父类有部分public的方法是不需要,也不允许子类覆重
- 父类有一些特别的方法是必须要子类去覆重的,在父类的方法其实是个空方法
- 父类有一些方法是可选覆重的,一旦覆重,则以子类为准
- 父类有一些方法即便被覆重,父类原方法还是要执行的
通常带来的问题:
- 容易使得一个对象引入原本不属于它的业务逻辑
- 调用时机或忘记调用
解决方案:
- 面向接口编程(Interface Oriented Programming, IOP)
在决定是否采用多态时,要有一个清晰的角色概念,做好角色细分,不要角色混乱。
三、封装
将相关的一堆函数和一堆对象放在一起,只留给外部程序员操作方式,而不暴露具体执行细节。
带来的问题:
- 制约了并行程度
- 数据部分就是数据部分,执行部分就是执行部分,不同类的东西放在一起是不合适的