iOS开发之工厂模式 (Factory Pattern)

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口(协议)来指向新创建的对象。

(一)简单工厂:

建模:

Step 1:

配置项目中用到的高德地图百度地图,请参照官方文档自行配置,这里不再阐述。

Step 2:

创建简单工厂类 MapFactory ,定义地图类型枚举。

typedef NS_ENUM(NSInteger, MapType) {
    MapTypeWithGaode,         // 高德地图
    MapTypeWithBaidu,         // 百度地图
 };

MapFactory.h 中定义两个方法:

/**
 配置地图

 @param type 地图类型
 */
- (instancetype)initWithType:(MapType)type;

/**
 返回一个地图对象

 @param frame frame
 @return 地图实例
 */
- (UIView *)getMapViewWithFrame:(CGRect)frame;

Step 3: 导入地图头文件,实现 MapFactory .m

// 高德地图
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <MAMapKit/MAMapKit.h>
// 百度地图
#import <BaiduMapAPI_Base/BMKBaseComponent.h>
#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface MapFactory()

/** 地图类型 */
@property(nonatomic,assign) MapType mapType;
/** 地图 */
@property(nonatomic,strong) UIView *mapView;

@end

@implementation MapFactory

- (instancetype)initWithType:(MapType)type {
    self = [super init];
    if (self) {
        _mapType = type;
        
        if (_mapType == MapTypeWithGaode) {
            [AMapServices sharedServices].apiKey = @"cf67bbca16a71b941da1df07550cc526";
        } else if (_mapType == MapTypeWithBaidu) {
            BMKMapManager* _mapManager = [[BMKMapManager alloc] init];
            BOOL ret = [_mapManager start:@"UfT4LGMjKAOB8fWL540hrslg2xVIfiUW"  generalDelegate:nil];
            if (!ret) {
                NSLog(@"manager start failed!");
            }
        }
    }
    
    return self;
}

- (UIView *)getMapViewWithFrame:(CGRect)frame {
    
    if (_mapType == MapTypeWithGaode) {
        _mapView = [[MAMapView alloc] initWithFrame:frame];
    } else if (_mapType == MapTypeWithBaidu) {
        _mapView = [[BMKMapView alloc]initWithFrame:frame];
    }

    return _mapView;
}

Step 4: 简单工厂的使用

在需要使用地图的 controller 中,#import "MapFactory.h"

// 修改type即可实现地图的切换
MapFactory *factory = [[MapFactory alloc] initWithType:MapTypeWithGaode];
UIView *mapView = [factory getMapViewWithFrame:self.view.bounds];
[self.view addSubview:mapView];

效果如下:
高德地图

百度地图

(二)工厂方法:

在简单工厂的基础之上进行了抽象(protocol).
定义一个用于创建对象的统一接口(protocol),然后由子类实现。

建模:

Step 1:

根据模型创建工厂方法协议 IComputerFactoryIComputer protocol。

// IComputerFactory
#import <Foundation/Foundation.h>
#import "IComputer.h"

@protocol IComputerFactory <NSObject>

- (id<IComputer>)getComputer;

@end
// IComputer
#import <Foundation/Foundation.h>

@protocol IComputer <NSObject>

- (void)printInfo;

@end

Step 2:

创建遵循 <IComputerFactory> 协议的电脑工厂类 AppleComputerFactory ,并实现协议方法。

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

// 苹果电脑工厂 -> 遵循电脑工厂协议<IComputerFactory>
@interface AppleComputerFactory : NSObject<IComputerFactory>
@end

// .m
#import "AppleComputerFactory.h"
#import "AppleComputer.h"

@implementation AppleComputerFactory
// 返回具体的电脑
- (id<IComputer>)getComputer {
    return [[AppleComputer alloc] init];
}

@end

Step 3:

创建遵循 <IComputer> 协议的电脑类 AppleComputer ,并实现协议方法。

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

// 苹果电脑 -> 遵循电脑协议<IComputer>
@interface AppleComputer : NSObject<IComputer>

@end

// .m
#import "AppleComputer.h"

@implementation AppleComputer

- (void)printInfo {
    NSLog(@"生产了一台处理器为2.9 GHz,内存 8GB的苹果电脑");
}

@end

Step 4:

在需要使用的地方,#import "AppleComputerFactory.h"

id<IComputerFactory> factory = [[AppleComputerFactory alloc] init];
id<IComputer> computer = [factory getComputer];
[computer printInfo];

控制台效果:

通过简单工厂和工厂方法的对比,大家有没有发现简单工厂的一些弊端呢?

  • 拓展性比较差,都在一个类中,不便于多人协同开发;
  • 代码冗余,耦合度比较高;

当然了,没有绝对完美的设计模式,只有适合的设计模式。我们需要根据实际项目需求采用合理的设计模式。

我在demo中的 FactoryMethod-Map 文件夹下实现了地图的工厂方法,感兴趣的可以在文章底部下载代码查看。

(三)抽象工厂:

在工厂方法之上进行了再次抽象(protocol).
为创建一组相关或相互依赖的对象提供一个接口(protocol),而且无需指定他们的具体类。

抽象工厂和工厂方法的区别:

  • 抽象工厂是为创建一组相关或相互依赖的对象提供一个接口(protocol),工厂方法是一个;

建模:

Step 1:

根据模型创建抽象工厂协议 IAbsComputerFactoryIAbsComputerGraphicsCardIAbsComputerCpu protocol。

// IAbsComputerFactory
#import <Foundation/Foundation.h>
#import "IAbsComputerCpu.h"
#import "IAbsComputerGraphicsCard.h"

// 抽象工厂 电脑统一的抽象接口
@protocol IAbsComputerFactory <NSObject>
// CPU
- (id<IAbsComputerCpu>)getCpu;
// 显卡
- (id<IAbsComputerGraphicsCard>)getGraphicsCard;
@end
// IAbsComputerGraphicsCard
#import <Foundation/Foundation.h>

// 抽象电脑显卡接口
@protocol IAbsComputerGraphicsCard <NSObject>
// 打印电脑显卡信息
- (void)printInfo;
@end
// IAbsComputerCpu
#import <Foundation/Foundation.h>

// 抽象电脑Cpu接口
@protocol IAbsComputerCpu <NSObject>
// 打印电脑Cpu信息
- (void)printInfo;
@end

Step 2:

创建遵循 <IAbsComputerFactory> 协议的电脑工厂类 AbsAppleComputerFactory ,并实现协议方法。

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

// 遵循协议 <IAbsComputerFactory> 的实现类
@interface AbsAppleComputerFactory : NSObject<IAbsComputerFactory>

@end

// .m
#import "AbsAppleComputerFactory.h"
#import "AbsAppleComputerGraphicsCard.h"
#import "AbsAppleComputerCpu.h"

@implementation AbsAppleComputerFactory

// CPU
- (id<IAbsComputerCpu>)getCpu {
    return [[AbsAppleComputerCpu alloc] init];
}
// 显卡
- (id<IAbsComputerGraphicsCard>)getGraphicsCard {
    return [[AbsAppleComputerGraphicsCard alloc] init];
}

@end

Step 3:

创建遵循 <IAbsComputerCpu> 协议的实现类 AbsAppleComputerCpu ,并实现协议方法。

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

// 遵循协议 <IAbsComputerCpu> 的实现类
@interface AbsAppleComputerCpu : NSObject<IAbsComputerCpu>

@end

// .m
#import "AbsAppleComputerCpu.h"

@implementation AbsAppleComputerCpu

- (void)printInfo {
    NSLog(@"生产了一个苹果电脑的CPU。");
}

@end

Step 4:

创建遵循 <IAbsComputerGraphicsCard> 协议的实现类 AbsAppleComputerGraphicsCard ,并实现协议方法。

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

// 遵循协议 <IAbsComputerGraphicsCard> 的实现类
@interface AbsAppleComputerGraphicsCard : NSObject<IAbsComputerGraphicsCard>

@end

// .m
#import "AbsAppleComputerGraphicsCard.h"

@implementation AbsAppleComputerGraphicsCard

- (void)printInfo {
    NSLog(@"生产了一个苹果电脑的显卡。");
}

@end

Step 5:

在需要使用的地方,#import "AbsAppleComputerFactory.h"

id<IAbsComputerFactory> factory = [[AbsAppleComputerFactory alloc] init];
id<IAbsComputerCpu> cpu = [factory getCpu];
[cpu printInfo];
id<IAbsComputerGraphicsCard> graphicsCard = [factory getGraphicsCard];
[graphicsCard printInfo];

控制台效果:

生产联想电脑的类与上面所述的苹果类如出一辙,这里就不再阐述了。如果以后要拓展其他电脑类,只需要按照这种模式实现就可以了,简直不要太方便~


demo放在GitHub上了,想查看的小伙伴可以->戳这里。


千里之行,始于足下。

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