工厂方法模式

什么是工厂方法模式?(定义)

定义一个用于创建对象的统一的接口,然后由子类实现。

工厂方法模式->角色划分?

$\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简单工厂设计
两个角色
角色一:具体工厂(一个)
角色二:具体产品(多个)
工厂方法角色
角色一:抽象产品(一个)
角色二:具体产品(多个)
角色三:抽象工厂(一个)
角色四:具体工厂(多个)

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

推荐阅读更多精彩内容