工厂方法模式
什么是工厂方法模式?(定义)
定义一个用于创建对象的统一的接口,然后由子类实现。
工厂方法模式->角色划分?
$\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简单工厂设计
两个角色
角色一:具体工厂(一个)
角色二:具体产品(多个)
工厂方法角色
角色一:抽象产品(一个)
角色二:具体产品(多个)
角色三:抽象工厂(一个)
角色四:具体工厂(多个)