工厂模式

GOF是这样描述工厂模式的:

“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

简单工厂模式

简单工厂使用场景

  1. 简化生产流程
  2. 隔离生产产品的细节
  3. 不同类型的产品之间有着一些共同的功能
  4. 一个具体的工厂

抽象工厂模式

工厂方法把生产产品的方式封装起来了,但是一个工厂只能生产一类对象,当一个工厂需要生产多类产品的时候,就需要使用抽象工厂了。抽象工厂(AbstractFactory)类定义了一组标准的实现接口,这些接口一般都是和具体的产品类继承层次对应的。如createProductA接口只能生产抽象产品类(AbstratctProductA)的子类产品,因此抽象工厂的具体实现类之间的关系就是个生产了一批不同产品族的组合。这样通过抽象工厂模式可以方便的更换产品族,代码修改的代价只需要更换一个具体的工厂对象就可以了。因此直观上可以把抽象工厂看作一组工厂方法,它的每一个接口都可以提取出一个单独的工厂方法。不过抽象工厂除了反映出这些含义外,还隐含着多类产品之间有种内在的联系,如按钮、菜单、滚动条都是GUI组件。
举例:
对于可以随意更换GUI组件库的需求,抽象工厂就可以完成类似的功能。抽象工厂类(AbstractFactory)封装了GUI组件库必须提供的接口,如创建按钮、菜单、滚动条等。GUI组件类会根据不同的窗口系统而派生具体的组件类,实现抽象工厂的具体类具体工厂类会根据不同的窗口系统选择对应的组件进行生产。这样当更换窗口系统的时候,只需要更换工厂类就能方便的实现运行时窗口系统的更换。按照这样的描述,我们用C++实现的代码如下:

//产品类继承层次
class Button
{
     public:
     virtual void click()=0;
     virtual ~Button(){}
};

class WindowsButton:public Button
{
    public:
    virtual void click()
    {
        cout<<"单击了Windows按钮"<<endl;
    }
};

class MacButton:public Button
{
   public:
   virtual void click()
   {
       cout<<"单击了Mac按钮"<<endl;
   }
};

class Menu
{
    public:
    virtual void select()=0;
    virtual ~Menu(){}
};

class WindowsMenu:public Menu
{
    public:
    virtual void select()
    {
        cout<<"选择了Windows菜单"<<endl;
    }
};

class MacMenu:public Menu
{
    public:
    virtual void select()
    {
         cout<<"选择了Mac菜单"<<endl;
    }
};

//抽象工厂
class GUIFactory
{
    public:
    virtual Button*createButton()=0;
    virtual Menu*createMenu()=0;
    virtual ~GUIFactory(){}
};

//具体的工厂
class WindowsGUIFactory:public GUIFactory
{
    public:
    virtual Button*createButton()
    {
          return new WindowsButton();
    }

    virtual Menu*createMenu()
    {
         return new WindowsMenu();
    }
};

class MacGUIFactory:public GUIFactory
{
    public:
    virtual Button*createButton()
    {
         return new MacButton();
    }

    virtual Menu*createMenu()
    {
         return new MacMenu();
    }
};

如果我们使用这段代码创建组件,就会这么写了:

GUIFactory*factory=new WindowsGUIFactory();//创建工厂
Button*btn=factory->createButton();//创建按钮
Menu*menu=factory->createMenu();//创建菜单
btn->click();//调用组件函数
menu->select();
delete menu;
delete btn;
delete factory;

从代码中看出我们无法看到看到具体创建的组件,因为我们只需要用抽象类Button、Menu使用标准的接口就可以了,具体的实现被工厂封装起来了。如果我们要更换所有的一批组件的话,只需要修改第一行代码,换一个工厂就可以了。

下面用Objective-C语言写个抽象工厂的例子。
工厂父类:抽象工厂

#import <Foundation/Foundation.h>
#import "BasePhone.h"
#import "BaseWatch.h"

@interface BaseFactory : NSObject

/**
  *  创建手机
  *
  *  @return 手机
  */
- (BasePhone *)createPhone;

/**
  *  创建手表
  *
  *  @return 手表
  */
 - (BaseWatch *)createWatch;

@end

#import "BaseFactory.h"

@implementation BaseFactory

- (BasePhone *)createPhone {

     return nil;
}

- (BaseWatch *)createWatch {

     return nil;
}

@end

工厂子类:具体工厂

// 苹果工厂
#import "BaseFactory.h"

@interface AppleFactory : BaseFactory

@end

#import "AppleFactory.h"
#import "iPhone.h"
#import "AppleWatch.h"

@implementation AppleFactory

- (BasePhone *)createPhone {

     return [[iPhone alloc] init];
}

- (BaseWatch *)createWatch {

     return [[AppleWatch alloc] init];
}

// 谷歌工厂
#import "BaseFactory.h"

@interface GoogleFactory : BaseFactory

@end

#import "GoogleFactory.h"
#import "Android.h"
#import "AndroidWatch.h"

@implementation GoogleFactory

- (BasePhone *)createPhone {

    return [[Android alloc] init];
}

- (BaseWatch *)createWatch {

     return [[AndroidWatch alloc] init];
}

@end

具体的设备也是先创建设备的父类BasePhone和BaseWatch,再创建继承自它们俩的子类iPhone,Android,AppleWatch,AndroidWatch。

工厂管理类

#import <Foundation/Foundation.h>
#import "BaseFactory.h"
#import "AppleFactory.h"
#import "GoogleFactory.h"

typedef NS_ENUM(NSUInteger, EFactoryType) {

     kApple   = 0x11,
     kGoogle,

};

@interface FactoryManager : NSObject

/**
  *  获取工厂
  *
  *  @param factoryType 工厂类型
  *
  *  @return 创建出的工厂
  */
 + (BaseFactory *)factoryWithBrand:(EFactoryType)factoryType;

 @end

 #import "FactoryManager.h"

 @implementation FactoryManager

 + (BaseFactory *)factoryWithBrand:(EFactoryType)factoryType {

      BaseFactory *factory = nil;

      if (factoryType == kApple) {
    
           factory = [[AppleFactory alloc] init];
    
      } else if (factoryType == kGoogle) {

           factory = [[GoogleFactory alloc] init];
      }

      return factory;
}

@end

具体工厂的创建方法如下:

// 获取工厂
BaseFactory *factory = [FactoryManager factoryWithBrand:kGoogle];

// 创建商品
BasePhone *phone = [factory createPhone];
BaseWatch *watch = [factory createWatch];

简单工厂模式

手机协议
#import <Foundation/Foundation.h>

@protocol PhoneProtocol <NSObject>

@required

/**
  *  打电话
  */
- (void)phoneCall;

/**
  *  发短信
  */
- (void)sendMessage;

@end

设备父类
BaseDevice.h
#import <Foundation/Foundation.h>
#import "PhoneProtocol.h"

@interface BaseDevie : NSObject <PhoneProtocol>

@end

BaseDevice.m
#import "BaseDevie.h"

@implementation BaseDevie

- (void)phoneCall {

}

- (void)sendMessage {

}

@end

具体设备
iPhone设备
#import "BaseDevie.h"

@interface iPhoneDevice : BaseDevie

/**
  *  指纹识别
  */
- (void)fingerprintIndetification;

@end

#import "iPhoneDevice.h"

@implementation iPhoneDevice

- (void)phoneCall {

     NSLog(@"iPhone phoneCall");
}

- (void)sendMessage {

     NSLog(@"iPhone sendMessage");
}

- (void)fingerprintIndetification {

     NSLog(@"iPhone fingerprintIndetification");
}

@end

Android设备
#import "BaseDevie.h"

@interface AndroidDevice : BaseDevie

/**
 *  定制主题
 */
- (void)customTheme;

@end

#import "AndroidDevice.h"

@implementation AndroidDevice

- (void)phoneCall {

     NSLog(@"Android phoneCall");
}

- (void)sendMessage {

     NSLog(@"Android sendMessage");
}

- (void)customTheme {

     NSLog(@"Android customTheme");
}

@end

手机设备工厂
#import <Foundation/Foundation.h>
#import "BaseDevie.h"
#import "iPhoneDevice.h"
#import "AndroidDevice.h"

typedef NS_ENUM(NSUInteger, EDevieType) {

     kiPhone   = 0x11,
     kAndroid,

} ;

@interface DeviceFactory : NSObject

/**
 *  根据用户提交的指令创建出具体的手机
 *
 *  @param type 创建的指令
 *
 *  @return 创建出的手机
 */
+ (BaseDevie <PhoneProtocol> *)deviceFactoryWithDevieType:(EDevieType)type;

@end

#import "DeviceFactory.h"

@implementation DeviceFactory

+ (BaseDevie <PhoneProtocol> *)deviceFactoryWithDevieType:(EDevieType)type {

    BaseDevie <PhoneProtocol> *device = nil;

    if (type == kiPhone) {
    
        device = [[iPhoneDevice alloc] init];
    
    }  else if (type == kAndroid) {

        device = [[AndroidDevice alloc] init];
    
    }  

    return device;
}

@end

简单工厂实现

// 工厂中创建出具体产品
iPhoneDevice *iPhone = (iPhoneDevice *)[DeviceFactory deviceFactoryWithDevieType:kiPhone];

// 使用产品的功能
[iPhone fingerprintIndetification];

工厂模式是最重要的模式,因为大多数模式都需要用到工厂模式。如果不能正确的运用工厂模式,那么可以说无法成为合格的架构师。

工厂方法模式:

一个抽象产品类,可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:

多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。

区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

在iOS的系统类库中也有一种方式使得开发者不必关注类中具体的存储实现,但可以根据不同需求场景创建出合适的对象来。

在iOS中有很多类都是使用了工厂模式,例如
Foundation:
NSNumber,
NSArray,
UIKit:
UIButton等类。

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

推荐阅读更多精彩内容

  • 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一...
    justCode_阅读 1,181评论 1 6
  • 设计原则: 要依赖抽象,不要依赖具体类 目录 本文的结构如下: 什么是抽象工厂模式 为什么要用该模式 模式的结构 ...
    w1992wishes阅读 1,102评论 0 6
  • 一、工厂模式介绍 工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类实例化,不必事先知道每...
    端木轩阅读 12,686评论 1 20
  • 早晨起床,我收拾一堆好洗的衣服。往洗手间走的路上不小心掉了一件“宝贝儿,能帮妈妈把地上的衣服放到洗衣机上吗?”我边...
    相信就会看到阅读 176评论 0 1
  • 2017年11月3日,星期五,微风正好,阳光稍燥。 下午后两节兴趣课,跟振玲姐商议在室外绿茵场上两个班进行...
    生如霞霞花阅读 613评论 2 1