OC中是不支持多繼承的,但是某些情況下想實(shí)現(xiàn)類似多繼承的效果怎么辦呢?簡(jiǎn)單的總結(jié)了幾種實(shí)現(xiàn)偽多繼承的方法。不對(duì)之處歡迎大家指正!
第一種:組合
比如魚類會(huì)游泳,鳥類會(huì)飛,現(xiàn)在有個(gè)怪物類,要求既會(huì)飛又會(huì)游泳該怎么辦?就是在怪物類里各持有一個(gè)魚類和鳥類的實(shí)例,外界調(diào)用怪物的飛行方法實(shí)際是其持有的鳥類實(shí)例調(diào)用鳥類飛行的方法,游泳方法亦是如此。直接上代碼吧!
//Fish.h的代碼
#import <Foundation/Foundation.h>
@interface Fish : NSObject
//游泳
- (void)swim;
@end
#import "Fish.h"
//Fish.m的代碼
@implementation Fish
- (void)swim {
NSLog(@"開始游泳.");
}
@end
//Bird.h的代碼
#import <Foundation/Foundation.h>
@interface Bird : NSObject
//飛行
- (void)fly;
@end
//Bird.m的代碼
#import "Bird.h"
@implementation Bird
- (void)fly {
NSLog(@"開始起飛.");
}
@end
//Monster.h的代碼
#import <Foundation/Foundation.h>
@interface Monster : NSObject
//游泳
- (void)swim;
//飛行
- (void)fly;
@end
//Monster.m的代碼
#import "Monster.h"
#import "Fish.h"
#import "Bird.h"
@interface Monster ()
@property (nonatomic, strong) Fish *fish;
@property (nonatomic, strong) Bird *bird;
@end
@implementation Monster
- (instancetype)init {
if (self = [super init]) {
self.fish = [Fish new];
self.bird = [Bird new];
}
return self;
}
- (void)swim {
[_fish swim];
}
- (void)fly {
[_bird fly];
}
這樣創(chuàng)建Monster實(shí)例對(duì)象就既可以調(diào)用游泳方法又可以調(diào)用飛行方法了。
//組合
Monster *m = [Monster new];
[m swim];
[m fly];
第二種:Protocol
使用Protocol來實(shí)現(xiàn)多繼承,因?yàn)镻rotocol只能提供接口,而沒有提供實(shí)現(xiàn)方式,所以這種方法只能實(shí)現(xiàn)接口多繼承。如果只是想多繼承基類的接口,那么遵守多協(xié)議無疑是最好的方法,而既需要多繼承接口,又要多繼承其實(shí)現(xiàn),那么協(xié)議是無能為力了。
直接上代碼。
//Add.h的代碼
#ifndef Add_h
#define Add_h
@protocol Add <NSObject>
- (int)addA:(int)a b:(int)b;
@end
#endif /* Add_h */
//Sub.h的代碼
#ifndef Sub_h
#define Sub_h
@protocol Sub <NSObject>
- (int)subA:(int)a b:(int)b;
@end
#endif /* Sub_h */
//Mul.h的代碼
#ifndef Mul_h
#define Mul_h
@protocol Mul <NSObject>
- (int)mulA:(int)a b:(int)b;
@end
#endif /* Mul_h */
//Calculator.h的代碼
#import <Foundation/Foundation.h>
#import "Add.h"
#import "Sub.h"
#import "Mul.h"
NS_ASSUME_NONNULL_BEGIN
@interface Calculator : NSObject<Add,Sub,Mul>
@end
NS_ASSUME_NONNULL_END
//Calculator.m的代碼
#import "Calculator.h"
@implementation Calculator
#pragma mark - Add
- (int)addA:(int)a b:(int)b {
return a+b;
}
#pragma mark - Sub
- (int)subA:(int)a b:(int)b {
return a-b;
}
#pragma mark - Mul
- (int)mulA:(int)a b:(int)b {
return a*b;
}
@end
這樣創(chuàng)建Calculator實(shí)例對(duì)象就可以調(diào)用Add、Sub和Mul協(xié)議里面方法了。從而實(shí)現(xiàn)接口多繼承。但是只遵循協(xié)議相當(dāng)于聲明了協(xié)議里的方法,不實(shí)現(xiàn)的話運(yùn)行時(shí)調(diào)用會(huì)報(bào)錯(cuò)unrecognized selector sent to instance xxxxxx.
//protocol
int a=8,b=4;
Calculator *c = [Calculator new];
NSLog(@"%d+%d=%d",a,b,[c addA:a b:b]);
NSLog(@"%d-%d=%d",a,b,[c subA:a b:b]);
NSLog(@"%dx%d=%d",a,b,[c mulA:a b:b]);
第三種:組合+Protocol
下面模擬一個(gè)賣書的,一個(gè)賣衣服的,還有一個(gè)既賣書又賣衣服的經(jīng)銷商。這種方法實(shí)際是使用runtime和Protocol對(duì)第一種方法的延伸和擴(kuò)展。直接上代碼。
//BookProvider.h的代碼
#import <Foundation/Foundation.h>
@protocol BookProviderDelegate <NSObject>
- (void)sellBookWithTitle:(NSString *)title;
@end
//在本類里下面三種方式都可以,效果也不盡相同(可以自己進(jìn)行嘗試):
//第一種:不遵循BookProviderDelegate,也不是對(duì)相關(guān)方法進(jìn)行聲明。這種情況自己本身實(shí)例不能進(jìn)行相關(guān)方法調(diào)用
//第二種:遵循BookProviderDelegate,這種情況自己本身實(shí)例也可以進(jìn)行相關(guān)方法調(diào)用
//第三種:相關(guān)方法進(jìn)行聲明,這種情況自己本身實(shí)例也可以進(jìn)行相關(guān)方法調(diào)用
@interface BookProvider : NSObject<BookProviderDelegate>//遵循代理
//- (void)sellBookWithTitle:(NSString *)title;
//聲明不實(shí)現(xiàn)不會(huì)在methodlist中找到,所以調(diào)用會(huì)報(bào)錯(cuò) unrecognized selector sent to instance
//methodlist中都是.m中有實(shí)現(xiàn)的方法
- (void)publicMethod;
@end
//BookProvider.m的代碼
#import "BookProvider.h"
@implementation BookProvider
#pragma mark - BookProviderDelegate
- (void)sellBookWithTitle:(NSString *)title {
NSLog(@"You've bought \"%@\".",title);
}
#pragma mark - 私有方法
- (void)packageBook {
}
@end
//ClothProvider.h的代碼
#import <Foundation/Foundation.h>
typedef enum : NSUInteger {
ClothesSizeSmall = 0,
ClothesSizeMedium,
ClothesSizeLarge,
} ClothSize;
@protocol ClothProviderDelegate <NSObject>
- (void)sellClothWithSize:(ClothSize)size;
@end
@interface ClothProvider : NSObject<ClothProviderDelegate>
//- (void)sellClothWithSize:(ClothSize)size;
@end
//ClothProvider.m的代碼
#import "ClothProvider.h"
@implementation ClothProvider
#pragma mark - ClothProviderDelegate
- (void)sellClothWithSize:(ClothSize)size {
NSString *sizeStr;
switch (size) {
case ClothesSizeLarge:
sizeStr = @"large size";
break;
case ClothesSizeMedium:
sizeStr = @"medium size";
break;
case ClothesSizeSmall:
sizeStr = @"small size";
break;
default:
break;
}
NSLog(@"You've bought some clothes of %@.",sizeStr);
}
@end
//DealerProxy.h的代碼
#import <Foundation/Foundation.h>
#import "BookProvider.h"
#import "ClothProvider.h"
@interface DealerProxy : NSProxy<BookProviderDelegate,ClothProviderDelegate>
+ (instancetype )dealerProxy;
@end
//DealerProxy.h的代碼
#import "DealerProxy.h"
#import <objc/runtime.h>
@interface DealerProxy (){
BookProvider *_bookProvider;
ClothProvider *_clothProvider;
//方法map
NSMutableDictionary *_methodsMap;
}
@end
@implementation DealerProxy
+ (instancetype)dealerProxy {
return [[DealerProxy alloc] init];
}
- (instancetype)init {
_bookProvider = [BookProvider new];
_clothProvider = [ClothProvider new];
_methodsMap = [NSMutableDictionary dictionary];
//獲取method并存入_methodsMap中
[self _registerMethodsWithTarget:_bookProvider];
[self _registerMethodsWithTarget:_clothProvider];
return self;
}
#pragma mark - private method
- (void)_registerMethodsWithTarget:(id)target {
unsigned int numberOfMethods = 0;
//這里處理的只是針對(duì)對(duì)象方法,類方法沒有處理.注意:這里的方法列表只包含.m中實(shí)現(xiàn)的方法,只聲明的方法不包括在內(nèi)。
Method *method_list = class_copyMethodList([target class], &numberOfMethods);
for (int i = 0; i < numberOfMethods; i++) {
Method method = method_list[i];
SEL sel = method_getName(method);
NSString *selName = NSStringFromSelector(sel);
[_methodsMap setObject:target forKey:selName];
}
NSLog(@"-->%@",_methodsMap);
free(method_list);
}
#pragma mark - NSProxy override methods
//消息轉(zhuǎn)發(fā)流程
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
NSString *selName = NSStringFromSelector(sel);
id target = _methodsMap[selName];
if (target && [target respondsToSelector:sel]) {
return [target methodSignatureForSelector:sel];
}else{
return [super methodSignatureForSelector:sel];
}
}
//消息轉(zhuǎn)發(fā)流程
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel = invocation.selector;
NSString *selName = NSStringFromSelector(sel);
id target = _methodsMap[selName];
if (target && [target respondsToSelector:sel]) {
[invocation invokeWithTarget:target];
}else{
[super forwardInvocation:invocation];
}
}
@end
這樣DealerProxy實(shí)例既可以賣書又可以賣衣服了。其中涉及到NSProxy、消息轉(zhuǎn)發(fā)以及runtime相關(guān)知識(shí)大家請(qǐng)自行百度。
//組合+Protocol
BookProvider *b = [BookProvider new];
[b sellBookWithTitle:@"<<從刪庫(kù)到跑路>>"];
ClothProvider *c = [ClothProvider new];
[c sellClothWithSize:ClothesSizeLarge];
DealerProxy *p = [DealerProxy dealerProxy];
[p sellBookWithTitle:@"Object C"];
[p sellClothWithSize:ClothesSizeMedium];