IOS设计模式浅析之工厂方法模式(Factory Method)
概述
在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。
如何隔离出这个易变对象的变化,使得系统中“其它依赖该对象的对象”不随着需求的改变而改变,这就是本章要说的Factory Method模式了。
定义
“定义创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。”
- 最初的定义出现于《设计模式》(Addison-Wesley,1994)。
结构图

抽象产品Product(可以是接口或者抽象类)定义了工厂方法创建的对象的接口和产品的共性;ConcreteProduct实现了Product。Creator定义了返回Product类型对象的工厂方法;ConcreteCreator实现了Creator,返回具体的ConcreteProduct的实例。
从结构图可以看出,在工厂方法模式中,核心的工厂类(Creator)不再负责所有产品的创建,而是将具体创建工作交给子类(ConcreteCreator)去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。与直接创建新的具体产品相比,工厂方法模式让客户程序可以要求由工厂方法创建的对象拥有一组共同的行为。这样往类层次结构中引入新的具体产品时,并不需要修改客户端代码,因为返回的任何具体对象的接口都跟客户端一直在用的从前的接口相同。从结构图也可以看到,工厂方法模式中的工厂类与产品类往往具有平行的等级结构,它们之间一一对应。
示例
根据工厂方法模式的定义和结构图,现在将简单工厂模式中的示例,用工厂方法模式来实现,先看使用工厂方法模式实现的结构图:

从图中可以看到,在简单工厂模式中,由工厂类(ChartFactory)根据参数负责创建具体的产品(线形图、饼状图);而在工厂方法模式中,工厂类(Factory)只定义了一个创建产品的抽象接口,创建具体产品的工作由具体的工厂(线形图工厂、饼状图工厂)来实现。如果需要增加其他类型的图形绘制,那么使用简单工厂模式实现的话,首先需要增加一个其他图形绘制的类,例如柱状图(BarChart),然后修改工厂类(ChartFactory),在里面加分支语句来判断;使用工厂方法模式实现的话,不仅需要增加图形绘制类,还需要增加具体工厂类(BarFactory)。看到这里,可能大家会感觉到,工厂方法模式不但没有减少难度,反而增加了一些类和复杂度。这样来看,是不是没有必要使用工厂方法模式?咱们再回顾一下开篇介绍的六大设计原则,有一个原则是“开放-关闭原则”,简单工厂模式不仅对扩展开放,而且对修改也开放,违反了“开放-关闭原则”。工厂方法模式是简单工厂模式的进一步抽象,它保持了简单工厂模式的优点(去除了客户端与具体产品的依赖),而且克服了它的缺点(违反开放-关闭原则”)。它的缺点是每增加一个产品,就需要加一个产品工厂的类,增加了额外的开发工作量。理论分析就到这里,接下来看看代码:
IChart.h:
@protocol IChart <NSObject> - (void)drawing;
LineChart.m(部分代码):
- (void)drawing
{
NSLog(@"LineChart drawing.");
}
PieChart.m(部分代码):
- (void)drawing
{
NSLog(@"PieChart drawing.");
}
Factory.h:
@protocol Factory <NSObject> - (id<IChart>)createChart;
LineFactory.m(部分代码):
- (id<IChart>)createChart
{ return [[[LineChartalloc] init] autorelease]; }
PieFactory. .m(部分代码):
- (id<IChart>)createChart
{ return [[[PieChartalloc] init] autorelease]; }
客户端调用代码:
id<Factory> factory = [[[LineFactoryalloc] init] autorelease];
// id<Factory> factory = [[[PieFactory alloc] init] autorelease];
id<IChart> chart = [factory createChart];
[chart drawing];
从调用代码可以看出,工厂方法模式从代码中消除了对应用程序特有类的耦合。代码秩序处理Product抽象接口(这里是id<IChart>),这样同一代码就可以复用。
思考
从上面的客户端调用代码看到,如果有多处调用绘图的地方,我们需要每处都进行修改,这样的话,实际上也没有达到我们的效果:应对变化,尽可能少的修改代码。那么该怎样处理这种情况呢?
下面一种方式可以做到:
// id<Factory> factory = [[[LineFactory alloc] init] autorelease];
// id<Factory> factory = [[[PieFactory alloc] init] autorelease];
id<Factory> factory = [[[NSClassFromString(@"PieFactory") alloc] init] autorelease]; id<IChart> chart = [factory createChart];
[chart drawing]; [NSNumber numberWithBool:YES];
这样的话,我们可以将@"PieFactory"放到配置文件中,当我们需要绘制线形图的时候,只需要修改配置文件即可,客户端的所有代码都不需要改变。
何时使用工厂方法模式
- 编译时无法准确预期要创建的对象的类;
- 类想让其子类决定在运行时创建什么;
- 类有若干辅助类为其子类,而你想将返回哪个子类这一信息局部化。
IOS设计模式浅析之工厂方法模式(Factory Method)的更多相关文章
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- 设计模式-03工厂方法模式(Factory Method Pattern)
插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...
- 【设计模式】工厂方法模式 Factory Method Pattern
在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...
- 二十四种设计模式:工厂方法模式(Factory Method Pattern)
工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...
- 工厂方法模式-Factory Method(Java实现)
工厂方法模式-Factory Method 工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法让实例化的具体内容交给子类工厂来进行. 本文中的例子是这样的. 生产一个身份证, ...
- 设计模式之工厂方法模式(Factory Method Pattern)
一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...
- 设计模式之 - 工厂方法模式 (Factory Method design pattern)
1. 模式意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...
- 大话设计模式--工厂方法模式 Factory Method -- C++实现
1. 工厂方法模式 定义一个用于创建对象的接口, 让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 和简单工厂模式相比: A: 简单工厂模式最大的优点在于工厂类中包含有必要的逻辑判断, ...
- 《JAVA设计模式》之工厂方法模式 (Factory)
在阎宏博士的<JAVA与模式>一书中开头是这样描述工厂方法模式的: 工厂方法模式是类的创建模式,又叫做虚拟构造子(Virtual Constructor)模式或者多态性工厂(Polymor ...
随机推荐
- Python全栈之路3--set集合--三元运算--深浅拷贝--初识函数
一.上节课的重点回顾: 1.类名加括号其实就是执行类的__init__方法: 2.int a.创建方式 n1 = 123 #根据int类创建了一个对象 n2 = int(123) #根据int类创建一 ...
- GIS开发环境全面升级10.1
最近,因为公司开发的需要,对开发环境进行全面的升级,在这其中也遇到了不少问题,在之后将陆续整理出来,以便以后查看. 之前开发环境:VS2008,ArcGIS9.3,ArcEngine9.3,Oracl ...
- Python.Scrapy.11-scrapy-source-code-analysis-part-1
Scrapy 源代码分析系列-1 spider, spidermanager, crawler, cmdline, command 分析的源代码版本是0.24.6, url: https://gith ...
- sqlserver,mysql,oracle通用的模拟和改进的全文搜索算法
问:数据库效率最低的地方是什么? 答:表扫描 问:表扫描常见的情况是 答:like '%a%' 这类查询 如果使用全文检索引擎,又无法满足我们的需求的时候怎么办,比如要从 一个商品名称 "农 ...
- github的一些指令
- NGINX下配置404错误页面的方法分享
NGINX下配置自定义的404页面是可行的,而且很简单,只需如下几步,需要的朋友可以参考下 1. 创建自己的404.html页面 2.更改nginx.conf在http定义区域加入: fastcg ...
- Contacts群组添加成员,多选列表过滤已添加数据
Group添加联系人时,Contacts默认设计不会过滤已分组的联系人.之前看到小米,oppo都做过过滤,一直懒得改. 最近客户要求group添加成员时,不显示已分组的联系人,故记录一下实现过程. p ...
- Oracle列操作(增加列,修改列,删除列)
Oracle列操作 增加一列: alter table emp4 add test varchar2(10); 修改一列: alter table emp4 modify test varchar2( ...
- 【洛谷P3258】松鼠的新家
很好的一道题 LCA+树上前缀和 sum数组是前缀和数组, 分类讨论一下, 1.访问到一个点p1,若下一个点p2需要往儿子下面找的话,那么lca就是这个点p1,则sum[p1]--; sum[p2]+ ...
- Jade之Includes
Includes jade允许利用include将其他文件(支持filters所支持的类型)中的代码嵌入当前代码中. jade: //- index.jade doctype html html in ...