用工厂方法时,先定义了一个基类,在基类的声明中定义了一系列的方法,类实现里面并不需要实现,而是在子类里面实现的,需要的只是基类中的.h文件的方法声明。这个是不是和协议有点像,定义一个基协议,让各个工厂类都遵守这个基协议。我们就拿地图说事。百度地图和高德地图的视图都是继承的UIView,请看代码。
1>首先我们先定义2个基协议。
#import <UIKit/UIKit.h>
#import "ImapView.h"
@protocol IMapFactory <NSObject>
- (id<ImapView>)getMapViewWithFrame:(CGRect)frame;
@end
#import <UIKit/UIKit.h>
@protocol ImapView <NSObject>
- (instancetype)initWithFrame:(CGRect)frame;
- (UIView *)getMapView;
@end
第一个协议是用来生产一个遵守IMapFactory这个协议的工厂。第二个协议就是通过遵守IMapFactory协议的工厂来生产地图。
给每个第三方地图定义2个类,一个类是来生产地图工厂,另一个就是通过工厂来生产地图视图。
.h文件
#import <UIKit/UIKit.h>
#import "IMapFactory.h"
@interface BaiduMapFactory : NSObject <IMapFactory>
@end
遵守了IMapFactory就能拿到协议里面的方法,从而可以返回一个遵守ImapView协议的地图视图。同样初始化方法也可以写在地图工厂里,从而做到瘦身程序入口方法
.m文件
#import "BaiduMapFactory.h"
#import "BaiduMapView.h"
#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件
#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件
@interface BaiduMapFactory ()
@property (nonatomic,strong) BMKMapManager *mapManager;
@end
@implementation BaiduMapFactory
- (instancetype)init {
if (self = [super init]) {
_mapManager = [[BMKMapManager alloc] init];
[_mapManager start:@"HBnGpGicUfd6SwSr5oCMre3asI29U0GG" generalDelegate:nil];
}
return self;
}
- (id<ImapView>)getMapViewWithFrame:(CGRect)frame {
return [[BaiduMapView alloc] initWithFrame:frame];
}
@end
让地图视图这个类遵守ImapView这份协议。用来返回地图视图。
.h文件
#import <UIKit/UIKit.h>
#import "ImapView.h"
@interface BaiduMapView : UIView <ImapView>
@end
.m文件
#import "BaiduMapView.h"
#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件
#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件
@interface BaiduMapView ()
@property (nonatomic,strong) BMKMapView *mapView;
@end
@implementation BaiduMapView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
_mapView = [[BMKMapView alloc] initWithFrame:frame];
}
return self;
}
- (UIView *)getMapView {
return _mapView;
}
@end
等等,这个工厂谁来创建了,难道要在客户端去手动实例化工厂吗?no no no 这种设计原则太烂了。定义一个地图引擎用来返回工厂,而返回的工厂遵守IMapFactory协议就行。
.h文件
#import <Foundation/Foundation.h>
#import "IMapFactory.h"
typedef NS_ENUM(NSInteger, mapType) {
baidu,
gaode
};
@interface MapEngine : NSObject
- (id <IMapFactory>)getMapFactoryWithType:(mapType)type;
@end
.m文件
#import "MapEngine.h"
#import "BaiduMapFactory.h"
#import "GaodeMapFactory.h"
@implementation MapEngine
- (id <IMapFactory>)getMapFactoryWithType:(mapType)type {
if (type == baidu) {
return [[BaiduMapFactory alloc] init];
} else {
return [[GaodeMapFactory alloc] init];
}
}
@end
那么客户端的代码就简单了,引擎->工厂->地图。
MapEngine *engine = [[MapEngine alloc] init];
id <IMapFactory> factory = [engine getMapFactoryWithType:baidu];
id <ImapView> mapView = [factory getMapViewWithFrame:self.view.frame];
[self.view addSubview:[mapView getMapView]];
高德地图也是一样,定义2个类,一个工厂,一个视图。分别遵守2个协议。切换地图时,只需要修改一个参数即可替换。
总结:面向协议就是充分利用了只要继承了协议,就能获取协议中所有的方法这个特点,和工厂方法有点类似。
网友评论