項(xiàng)目代碼結(jié)構(gòu)優(yōu)化(工廠模式以及面向協(xié)議編程)

舉例提問

你有什么方法在項(xiàng)目中實(shí)現(xiàn)快速切換百度地圖高德地圖?(ps:本文例子是針對(duì)iOS項(xiàng)目講解的,但是思想是可以借鑒到其他語言中的。)
或許有不少朋友的答案是修改代碼唄。
那么,我再給一個(gè)前提:如何在不改動(dòng)客戶端代碼或者盡可能少量的修改代碼呢?
今天,我就帶大家來實(shí)現(xiàn)如何不改動(dòng)客戶端代碼或者盡可能少量的修改客戶端代碼來實(shí)現(xiàn)項(xiàng)目中百度地圖高德地圖的快速切換。

集成百度地圖

先創(chuàng)建一個(gè)工程,然后將百度地圖sdk集成到項(xiàng)目,(此處忽略集成步驟,具體可以在百度地圖sdk接入文檔中查看)。在百度地圖官網(wǎng)申請(qǐng)appkey,然后在AppDelegate初始化百度地圖,這篇文章我們只是簡(jiǎn)單的使用一下百度地圖,在ViewController中我們導(dǎo)入#import <BaiduMapAPI_Map/BMKMapComponent.h>,然后創(chuàng)建一個(gè)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];
}

運(yùn)行我們的app,ok,不出意外的話,我們界面上能夠正確的顯示百度地圖。(ps:問了項(xiàng)目結(jié)構(gòu)看起來舒服,這里分文件夾管理Framework下包含了GaodeMapBaiduMap兩個(gè)文件夾)

集成高度地圖

然后我們需要再集成高德地圖sdk到項(xiàng)目,申請(qǐng)appkey,然后在Appdelegate里面添加

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

同樣,我們?cè)?code>ViewController中我們導(dǎo)入#import <MAMapKit/MAMapView.h>,然后創(chuàng)建一個(gè)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];
}

運(yùn)行我們的代碼,ok,我們也能愉快的看到界面上顯示的是高德地圖。

面向協(xié)議思想

通過以上的代碼,我們可以發(fā)現(xiàn)有兩個(gè)點(diǎn):

  • 無論是BMKMapView還是MAMapView,他們都是繼承于UIView的。
  • 必須指定創(chuàng)建的位置和大小。

因此,我們可以通過protocol來抽出他們的共性。

ok,我們?cè)?code>Framework文件夾下創(chuàng)建一個(gè)BaseMap文件夾,然后創(chuàng)建一個(gè)IMapViewProtocol的協(xié)議類,然后將上述的兩個(gè)特點(diǎn)定義成兩個(gè)方法。

#import <UIKit/UIKit.h>

@protocol IMapViewProtocol <NSObject>

- (instancetype)initWithFrame:(CGRect)frame;

- (UIView *)getMapView;

@end

接下來,我們創(chuàng)建兩個(gè)類BaiduMapViewGaodeMapView并且這兩個(gè)類都實(shí)現(xiàn)IMapViewProtocol協(xié)議,因此需要實(shí)現(xiàn)協(xié)議方法。

  • 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

此時(shí)我們可以在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]];
}

運(yùn)行項(xiàng)目,此時(shí),我們可以看到界面上顯示出來高德地圖。(ps:在Appdelegate里面配置好高德地圖的key,下面也是同理。)此時(shí),如果我們想要切換成百度地圖的時(shí)候,我們只需要修改創(chuàng)建mapView對(duì)象的。

工廠模式

到現(xiàn)在為止,我們確實(shí)能夠盡可能少地修改代碼去切換兩個(gè)地圖的顯示了,可是,
假如我們一個(gè)項(xiàng)目中很多的地方用到了百度地圖或者高德地圖,那么我們是不是需要逐個(gè)逐個(gè)地去修改呢?這時(shí)候,我們就應(yīng)該考慮使用工廠模式了,就好比生產(chǎn)衣服的工廠,怎么生產(chǎn)的我們不知道,其實(shí)我們也并不關(guān)心,我們只對(duì)其生產(chǎn)出來的結(jié)果感興趣。那么,我們應(yīng)該將生產(chǎn)高德地圖的工廠和生產(chǎn)百度地圖的工廠分開呢,還是寫在一個(gè)工廠呢?不用想,我們肯定是需要分開生產(chǎn)的。但是,我們可以考慮到兩個(gè)工廠生產(chǎn)出來的實(shí)例有個(gè)共同點(diǎn):

  • 生產(chǎn)出來的實(shí)例必須遵守<IMapViewProtocol>協(xié)議

因此,我們可以定義一個(gè)協(xié)議類IMapFactoryProtocol

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

@protocol IMapFactoryProtocol <NSObject>

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

@end

然后定義兩個(gè)遵守<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];
        // 如果要關(guān)注網(wǎng)絡(luò)及授權(quán)驗(yàn)證事件,請(qǐng)?jiān)O(shè)定     generalDelegate參數(shù)
        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];
}

經(jīng)過上面的結(jié)構(gòu)整理,我們?cè)诙x一個(gè)引擎類----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

好了,到此為止,我們的結(jié)構(gòu)優(yōu)化算是完成了。這時(shí)候,我們?cè)倩氐?code>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];
}

現(xiàn)在,我們?nèi)绻胍袚Q地圖顯示,我們只需要在MapEngine類里面改變一下工廠類即可。這時(shí)候,我們甚至還可以接入服務(wù)器,讓服務(wù)配合,可以不修改客戶端任何代碼就實(shí)現(xiàn)地圖切換了。

結(jié)尾

  • 如果您有更好的思路歡迎交流。
  • 如果您有發(fā)現(xiàn)錯(cuò)誤或者有疑問的地方,歡迎交流,謝謝!!
  • 大神勿噴??!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,030評(píng)論 25 709
  • UML概述 UML簡(jiǎn)介 UML (Unified Modeling Language)為面向?qū)ο筌浖O(shè)計(jì)提供統(tǒng)一的...
    aron1992閱讀 607評(píng)論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評(píng)論 19 139
  • 有感于電影《夏洛特?zé)馈?,感嘆的核心是“節(jié)奏”。(純感嘆,無干貨) 看完《夏洛特?zé)馈返母杏X就是:語言夸張但表現(xiàn)自...
    鹽蔥蔥閱讀 427評(píng)論 0 3
  • 2017年7月2日,黨的生日剛過,美麗高唐書畫之鄉(xiāng)。來自各行各業(yè)的愛心人士組成一個(gè)大家庭的,經(jīng)常做一些送溫暖,獻(xiàn)愛...
    邢躍華Aa閱讀 224評(píng)論 0 0

友情鏈接更多精彩內(nèi)容