项目代码结构优化(工厂模式以及面向协议编程)

举例提问

你有什么方法在项目中实现快速切换百度地图高德地图?(ps:本文例子是针对iOS项目讲解的,但是思想是可以借鉴到其他语言中的。)
或许有不少朋友的答案是修改代码呗。
那么,我再给一个前提:如何在不改动客户端代码或者尽可能少量的修改代码呢?
今天,我就带大家来实现如何不改动客户端代码或者尽可能少量的修改客户端代码来实现项目中百度地图高德地图的快速切换。

集成百度地图

先创建一个工程,然后将百度地图sdk集成到项目,(此处忽略集成步骤,具体可以在百度地图sdk接入文档中查看)。在百度地图官网申请appkey,然后在AppDelegate初始化百度地图,这篇文章我们只是简单的使用一下百度地图,在ViewController中我们导入#import <BaiduMapAPI_Map/BMKMapComponent.h>,然后创建一个mapView添加到控制器上,

#import "ViewController.h"
#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface ViewController ()

@property (nonatomic, strong) BMKMapView *mapView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.mapView = [[BMKMapView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:self.mapView];
}

运行我们的app,ok,不出意外的话,我们界面上能够正确的显示百度地图。(ps:问了项目结构看起来舒服,这里分文件夹管理Framework下包含了GaodeMapBaiduMap两个文件夹)

集成高度地图

然后我们需要再集成高德地图sdk到项目,申请appkey,然后在Appdelegate里面添加

[AMapServices sharedServices].apiKey = @"你的key";

同样,我们在ViewController中我们导入#import <MAMapKit/MAMapView.h>,然后创建一个mapView添加到控制器上,

#import "ViewController.h"
// #import <BaiduMapAPI_Map/BMKMapComponent.h>
#import <MAMapKit/MAMapView.h>

@interface ViewController ()

// @property (nonatomic, strong) BMKMapView *mapView;
@property (nonatomic, strong) MAMapView *mMapView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // self.mapView = [[BMKMapView alloc] initWithFrame:self.view.bounds];
    // [self.view addSubview:self.mapView];
    
    self.mMapView = [[MAMapView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:self.mMapView];
}

运行我们的代码,ok,我们也能愉快的看到界面上显示的是高德地图。

面向协议思想

通过以上的代码,我们可以发现有两个点:

  • 无论是BMKMapView还是MAMapView,他们都是继承于UIView的。
  • 必须指定创建的位置和大小。

因此,我们可以通过protocol来抽出他们的共性。

ok,我们在Framework文件夹下创建一个BaseMap文件夹,然后创建一个IMapViewProtocol的协议类,然后将上述的两个特点定义成两个方法。

#import <UIKit/UIKit.h>

@protocol IMapViewProtocol <NSObject>

- (instancetype)initWithFrame:(CGRect)frame;

- (UIView *)getMapView;

@end

接下来,我们创建两个类BaiduMapViewGaodeMapView并且这两个类都实现IMapViewProtocol协议,因此需要实现协议方法。

  • BaiduMapView
#import "BaiduMapView.h"
#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface BaiduMapView ()

@property (nonatomic, strong) BMKMapView *mapView;

@end

@implementation BaiduMapView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super init];
    if (self) {
        _mapView = [[BMKMapView alloc] initWithFrame:frame];
    }
    return self;
}

- (UIView *)getMapView {
    return _mapView;
}

@end
  • GaodeMapView
#import "GaodeMapView.h"
#import <MAMapKit/MAMapView.h>

@interface GaodeMapView ()
@property (nonatomic, strong) MAMapView *mapView;
@end

@implementation GaodeMapView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super init];
    if (self) {
        _mapView = [[MAMapView alloc] initWithFrame:frame];
    }
    return self;
}

- (UIView *)getMapView {
    return self.mapView;
}

@end

此时我们可以在ViewController里面添加如下代码。

#import "ViewController.h"
#import "BaiduMapView.h"
#import "GaodeMapView.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    id<IMapViewProtocol> mapView = [[GaodeMapView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:[mapView getMapView]];
}

运行项目,此时,我们可以看到界面上显示出来高德地图。(ps:在Appdelegate里面配置好高德地图的key,下面也是同理。)此时,如果我们想要切换成百度地图的时候,我们只需要修改创建mapView对象的

工厂模式

到现在为止,我们确实能够尽可能少地修改代码去切换两个地图的显示了,可是,
假如我们一个项目中很多的地方用到了百度地图或者高德地图,那么我们是不是需要逐个逐个地去修改呢?这时候,我们就应该考虑使用工厂模式了,就好比生产衣服的工厂,怎么生产的我们不知道,其实我们也并不关心,我们只对其生产出来的结果感兴趣。那么,我们应该将生产高德地图的工厂和生产百度地图的工厂分开呢,还是写在一个工厂呢?不用想,我们肯定是需要分开生产的。但是,我们可以考虑到两个工厂生产出来的实例有个共同点:

  • 生产出来的实例必须遵守<IMapViewProtocol>协议

因此,我们可以定义一个协议类IMapFactoryProtocol

#import <UIKit/UIKit.h>
#import "IMapViewProtocol.h"

@protocol IMapFactoryProtocol <NSObject>

- (id<IMapViewProtocol>)getMapView:(CGRect)frame;

@end

然后定义两个遵守<IMapViewProtocol>的工厂类:

  • BaiduMapFactory
#import "BaiduMapFactory.h"
#import "BaiduMapView.h"
#import <BaiduMapAPI_Base/BMKMapManager.h>

@interface BaiduMapFactory (){
    BMKMapManager *_mapManager;
}

@end

@implementation BaiduMapFactory

- (instancetype)init {
    self = [super init];
    if (self) {
        _mapManager = [[BMKMapManager alloc]init];
        // 如果要关注网络及授权验证事件,请设定     generalDelegate参数
        BOOL ret = [_mapManager start:@"xnbikl7G1GolppT27HKdgfd10jtqDd0G"  generalDelegate:nil];
        if (!ret) {
            NSLog(@"初始化失败");
        }
    }
    return self;
}

- (id<IMapViewProtocol>)getMapView:(CGRect)frame {
    return [[BaiduMapView alloc] initWithFrame:frame];
}

@end
  • GaodeMapFactory
#import "GaodeMapFactory.h"
#import <AMapFoundationKit/AMapFoundationKit.h>
#import "GaodeMapView.h"

@implementation GaodeMapFactory

- (instancetype)init {
    self = [super init];
    if (self) {
        [AMapServices sharedServices].apiKey = @"fdbbc0bd9dc04f6b9922bf357ef1eaa8";
    }
    return self;
}

- (id<IMapViewProtocol>)getMapView:(CGRect)frame {
    return [[GaodeMapView alloc] initWithFrame:frame];
}

经过上面的结构整理,我们在定义一个引擎类----MapEngine

MapEngine.h

#import <Foundation/Foundation.h>
#import "IMapFactoryProtocol.h"

@interface MapEngine : NSObject
- (id<IMapFactoryProtocol>)getMapFactory;
@end

MapEngine.m:

#import "MapEngine.h"
#import "BaiduMapFactory.h"
#import "GaodeMapFactory.h"


@implementation MapEngine

- (id<IMapFactoryProtocol>)getMapFactory {
    return [[BaiduMapFactory alloc] init];
}

@end

好了,到此为止,我们的结构优化算是完成了。这时候,我们再回到ViewController中来看看我们的代码。

#import "ViewController.h"
#import "IMapViewProtocol.h"
#import "MapEngine.h"

@interface ViewController ()

@property (nonatomic, strong) UIView *mMapView;
@property (nonatomic, strong) MapEngine *engine;
@property (nonatomic, strong) id<IMapFactoryProtocol> factory;
@property (nonatomic, strong) id<IMapViewProtocol> mapView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.engine = [[MapEngine alloc] init];
    self.factory = [self.engine getMapFactory];
    self.mapView = [self.factory getMapView:self.view.bounds];
    self.mMapView = [self.mapView getMapView];
    [self.view addSubview:self.mMapView];
}

现在,我们如果想要切换地图显示,我们只需要在MapEngine类里面改变一下工厂类即可。这时候,我们甚至还可以接入服务器,让服务配合,可以不修改客户端任何代码就实现地图切换了。

结尾

  • 如果您有更好的思路欢迎交流。
  • 如果您有发现错误或者有疑问的地方,欢迎交流,谢谢!!
  • 大神勿喷!!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,837评论 25 707
  • UML概述 UML简介 UML (Unified Modeling Language)为面向对象软件设计提供统一的...
    aron1992阅读 513评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 有感于电影《夏洛特烦恼》,感叹的核心是“节奏”。(纯感叹,无干货) 看完《夏洛特烦恼》的感觉就是:语言夸张但表现自...
    盐葱葱阅读 349评论 0 3
  • 2017年7月2日,党的生日刚过,美丽高唐书画之乡。来自各行各业的爱心人士组成一个大家庭的,经常做一些送温暖,献爱...
    邢跃华Aa阅读 193评论 0 0