工廠方法模式

什么是工廠方法模式?(定義)

定義一個用于創建對象的統一的接口,然后由子類實現。

工廠方法模式->角色劃分?

$\color{red}{4個核心角色}
角色一:抽象產品
角色二:具體產品
角色三:抽象工廠->依賴于抽象產品
角色四:具體工廠->返回的是具體產品的初始化

工廠方法模式->原理案例?

工廠創建電腦->富士康工廠
華為工廠、三星工廠、蘋果工廠、聯想工廠…
如何知道你制造出來的產品是電腦?
因為:電腦標準規范(協議、接口)->特點
角色一:抽象產品->定義產品規范(規格)->電腦規范
角色二:具體產品->具體實現(具體制造目標)->具體電腦
具體電腦:華為電腦、三星電腦、蘋果電腦…
角色三:抽象工廠->定義工廠規范和標準
角色四:具體工廠->華為工廠、三星工廠

定義角色?
角色一:抽象產品->ComputerProtocol

//
//  ComputerProtocol.h
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>

//電腦規范
@protocol ComputerProtocol<NSObject>

//處理器
-(void)cpu;

//顯卡
-(void)displaycard;

//主板
-(void)mainborad;

@end

角色二:具體產品->SXComputer、HWComputer、MacComputer…

//
//  SXComputer.h
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface SXComputer : NSObject<ComputerProtocol>

@end

//
//  SXComputer.m
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "SXComputer.h"

@implementation SXComputer

//處理器
-(void)cpu{
    NSLog(@"三星處理器");
}

//顯卡
-(void)displaycard{
    NSLog(@"三星顯卡");
}

//主板
-(void)mainborad{
    NSLog(@"三星主板");
}

@end

//
//  HWComputer.h
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface HWComputer : NSObject<ComputerProtocol>

@end
//
//  HWComputer.m
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "HWComputer.h"

@implementation HWComputer

//處理器
-(void)cpu{
    NSLog(@"華為處理器");
}

//顯卡
-(void)displaycard{
    NSLog(@"華為顯卡");
}

//主板
-(void)mainborad{
    NSLog(@"華為主板");
}

@end

角色三:抽象工廠->ComputerFactoryProtocol

//
//  ComputerFactoryProtocol.h
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

//電腦工廠標準
//程序中->引用關系
//判斷的依據
@protocol ComputerFactoryProtocol<NSObject>

//流水線
-(id<ComputerProtocol>)getComputer;

@end

角色四:具體工廠->SXComputerFactory、HWComputerFactory…

//
//  HWComputerFactory.h
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface HWComputerFactory : NSObject<ComputerFactoryProtocol>

@end

//
//  HWComputerFactory.m
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "HWComputerFactory.h"
#import "HWComputer.h"

@implementation HWComputerFactory

-(id<ComputerProtocol>)getComputer{
    return [[HWComputer alloc] init];
}

@end

//
//  SXComputerFactory.h
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface SXComputerFactory : NSObject<ComputerFactoryProtocol>

@end

//
//  SXComputerFactory.m
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "SXComputerFactory.h"
#import "SXComputer.h"

@implementation SXComputerFactory

-(id<ComputerProtocol>)getComputer{
    return [[SXComputer alloc] init];
}

@end

調用

//
//  main.m
//  Dream_20180702_Factory_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "HWComputerFactory.h"
#import "SXComputerFactory.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        //測試->面向協議變成
        id<ComputerFactoryProtocol> factory = [[SXComputerFactory alloc] init];
        id<ComputerProtocol> computer = [factory getComputer];
        [computer cpu];
        [computer displaycard];
        [computer mainborad];
    }
    return 0;
}
工廠方法模式->開發案例?

如何使用工廠方法模式?
聚合SDK設計(分享組件)
地圖案例舉例子?
工廠目的:用于創建對象的?
分析需求:在我們的開發當中,場景,很多時候開發地圖、分享功能、支付功能…?
發現問題:當我們的需求變更的時候,你會發現我們項目迭代很麻煩?
例如:早上我的項目用百度地圖、下午我用高德地圖?
早上用的是支付寶、下午用的是微信?
解決方案:優化代碼(項目重構)?
工廠方法模式重構

采用工廠方法模式?
動態切換地圖(一鍵切換)
最少量的代碼,切換強大功能

實現代碼:定義每一個類?
1、分析角色?->方法
從0開發寫框架
角色一:抽象產品->地圖規范?
MapViewProtocol

//
//  MapViewProtocol.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import <UIKit/UIKit.h>

//面試時候->講不清楚邏輯關系(過程)
//地圖標準
@protocol MapViewProtocol<NSObject>

- (instancetype)initWithFrame:(CGRect)frame;

//規范->父類的引用指向子類的實例對象
-(UIView*)getView;

//...地圖類型、地圖語言、是否開啟交通....
//先忽略...

@end

百度地圖:BMKMapView?
BMKMapView : UIView
高德地圖:MAMapView?
MAMapView : UIView
結論:
1、所有的地圖MapView都是UIView子類
2、所有的地圖MapView都有類型
地圖類型、地圖語言、是否支持平移
共性問題、差異問題,先解決共性問題,再解決差異問題
定義一個協議

  • 角色二:具體產品->具體地圖
    例如:百度地圖、高德地圖…
    百度地圖->BaiduMapView
    高德地圖->GaodeMapView
//
//  GaodeMapView.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface GaodeMapView : NSObject<MapViewProtocol>

@end

//
//  GaodeMapView.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "GaodeMapView.h"

//具體高德地圖
@implementation GaodeMapView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super init];
    if (self) {
        //初始化高德地圖了
    }
    return self;
}

-(UIView*)getView{
    return nil;
}

@end

//
//  BaiduMapView.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface BaiduMapView : NSObject<MapViewProtocol>

@end

//
//  BaiduMapView.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "BaiduMapView.h"

//具體百度地圖
@implementation BaiduMapView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super init];
    if (self) {
         //初始化百度地圖了
    }
    return self;
}

-(UIView*)getView{
    return nil;
}

@end

  • 角色三:抽象工廠->生成地圖
    具體是什么工廠->地圖標準
    MapFactoryProtocol
//
//  MapFactoryProtocol.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

//面試時候->講不清楚邏輯關系(過程)
//地圖工廠標準
@protocol MapFactoryProtocol<NSObject>

//地圖標準
-(id<MapViewProtocol>)getMapViewWithFrame:(CGRect)frame;


@end

  • 角色四:具體工廠->具體地圖
    例如:百度工廠、高德工廠…
    BaiduMapFactory、GaodeMapFactory
//
//  GaodeMapFactory.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface GaodeMapFactory : NSObject<MapFactoryProtocol>

@end

//
//  GaodeMapFactory.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "GaodeMapFactory.h"
#import "GaodeMapView.h"

@implementation GaodeMapFactory

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

@end

//
//  BaiduMapFactory.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface BaiduMapFactory : NSObject<MapFactoryProtocol>

@end

//
//  BaiduMapFactory.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "BaiduMapFactory.h"
#import "BaiduMapView.h"

@implementation BaiduMapFactory

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

@end

動態切換?發現問題:還是需要修改客戶端的代碼?
達到目的:不修改客戶端代碼就能夠達到要求?
解決方案:
1、用plist文件配置?->iOS自帶的配置文件(特殊有規范的xml文件)
Config.map.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<map>
    <!---APPKEY放這里,等一下來填寫--->
    <!---百度地圖平臺--->
    <platform id="1" isOpen="NO" factoryName="BaiduMapFactory" appkey="" />
    <!---高德地圖平臺--->
    <platform id="2" isOpen="NO" factoryName="GaodeMapFactory" appkey="" />

</map>

解析xml

//
//  Platform.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Platform : NSObject

@property(nonatomic, strong) NSString* mapId;

@property(nonatomic, strong) NSString* appKey;

@property(nonatomic, strong) NSString* factoryName;

@property(nonatomic, strong) NSString* isOpen;

@end

//
//  Platform.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "Platform.h"

@implementation Platform

@end

//
//  PlatformXmlParser.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface PlatformXmlParser : NSObject

-(NSMutableArray*)parser;

@end

//
//  PlatformXmlParser.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "PlatformXmlParser.h"
#import "Platform.h"

@interface PlatformXmlParser()<NSXMLParserDelegate>

@property(nonatomic, strong) NSMutableArray* array;

@end

@implementation PlatformXmlParser

- (instancetype)init{
    self = [super init];
    if (self) {
        _array = [[NSMutableArray alloc] init];
    }
    return self;
}

-(NSMutableArray*)parser{
    //綁定delegate
    NSString* filePath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"map.xml"];
    NSURL* url = [[NSURL alloc] initFileURLWithPath:filePath];
    NSXMLParser* xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    xmlParser.delegate = self;
    //解析
    [xmlParser parse];
    return _array;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict{
    //解析xml
    if([elementName isEqualToString:@"platform"]){
        NSString* mapId = attributeDict[@"id"];
        NSString* appKey = attributeDict[@"appkey"];
        NSString* factoryName = attributeDict[@"factoryName"];
        NSString* isOpen = attributeDict[@"isOpen"];
        Platform* platform = [[Platform alloc] init];
        platform.mapId = mapId;
        platform.appKey = appKey;
        platform.factoryName =factoryName;
        platform.isOpen = isOpen;
        //保存
        [_array addObject:platform];
    }
}

@end

2、用xml配置文件(自定義xml文件)
3、用json文件配置
4、宏定義也行
如何實現?
確定方案:用xml配置文件(自定義xml文件)
1、分析文件結構?
加載地圖需要哪些參數?
1、第一個規范
百度地圖->key
高德地圖->key
這個key就是公共屬性(標簽)
2、第二個規范
key->對應地圖->對應工廠
baidu->key->BaiduMapFactory
geode->key->GaodeMapFactory
工廠屬性:factory = "BaiduMapFactory"
3、第三個規范->需要編號
id = 1,id = 2
4、第四個規范
百度地圖、高德地圖、google地圖…加載哪一個?
開關按鈕(控制加載哪一個地圖)
isOpen = "YES"
如果用戶所有的地圖都設置了"YES",默認啟
用第一個地圖
2、實現代碼?->簡單工廠模式
首先:定義Model
其次:實現解析類
最后:簡單工廠模式來了
角色一:具體工廠 (一個類)
地圖引擎->MapEngine
作用:動態創建工廠(動態管理工廠)
解決客戶端修改代碼的問題

//
//  MapEngine.h
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

//地圖引擎創建誰?->工廠標準我們是知道的
@interface MapEngine : NSObject

-(id<MapFactoryProtocol>)getFactoryWithFrame:(CGRect)frame;

@end

//
//  MapEngine.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

#import "MapEngine.h"
#import "PlatformXmlParser.h"
#import "Platform.h"

@interface MapEngine()

@property(nonatomic, strong) NSMutableArray* array;

@end

//MapEngine你可以標準寫法是單利模式(課后自己優化)
@implementation MapEngine

- (instancetype)init{
    self = [super init];
    if (self) {
        [self loadXml];
    }
    return self;
}

-(void)loadXml{
    PlatformXmlParser* parser = [[PlatformXmlParser alloc] init];
    _array = [parser parser];
}

-(id<MapFactoryProtocol>)getFactoryWithFrame:(CGRect)frame{
    for (Platform* platform in _array) {
        if ([platform.isOpen isEqualToString:@"YES"]) {
            return [[NSClassFromString(platform.factoryName) alloc] initWithFrame:frame];
        }
    }
    return nil;
}

@end

調用

//
//  ViewController.m
//  Dream_20180702_Factory_LBS_Demo
//
//  Created by Dream on 2018/7/2.
//  Copyright ? 2018年 Tz. All rights reserved.
//

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

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
//    id<MapFactoryProtocol> factory = [[BaiduMapFactory alloc] init];
//    id<MapViewProtocol> mapView = [factory getMapViewWithFrame:self.view.frame];
//    [self.view addSubview:[mapView getView]];
    
    MapEngine* engine = [[MapEngine alloc] init];
    id<MapFactoryProtocol> factory = [engine getFactoryWithFrame:self.view.frame];
    id<MapViewProtocol> mapView = [factory getMapViewWithFrame:self.view.frame];
    [self.view addSubview:[mapView getView]];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

角色二:具體產品(類多了)
也可以通過服務器配置,返回xml解析(需求)
代碼是可配置的
地圖具體實現 + 抽象工廠模式
plist文件配置,自己實現
梳理一下->繪制一個UML

簡單工廠模式和工廠方法模式區別?

核心:類結構(角色上面區別)
簡單工廠->抽象第一步->工廠方法
工廠方法->抽象第二步->抽象工廠
簡單工廠角色?->MapEngine簡單工廠設計
兩個角色
角色一:具體工廠(一個)
角色二:具體產品(多個)
工廠方法角色
角色一:抽象產品(一個)
角色二:具體產品(多個)
角色三:抽象工廠(一個)
角色四:具體工廠(多個)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容