什么是工廠方法模式?(定義)
定義一個用于創建對象的統一的接口,然后由子類實現。
工廠方法模式->角色劃分?
$\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簡單工廠設計
兩個角色
角色一:具體工廠(一個)
角色二:具體產品(多個)
工廠方法角色
角色一:抽象產品(一個)
角色二:具體產品(多個)
角色三:抽象工廠(一個)
角色四:具體工廠(多個)