本文从简单工厂模式的缺点说起,引入工厂方法模式,介绍的工厂方法模式的基本知识,实现要点和应用场景,最后举例进行说明工厂方法模式的应用。
在之前的《Javascript设计模式理论与实战:简单工厂模式》这篇文章中,我们介绍了简单工厂的知识和一些应用。简单工厂模式存在一个唯一的工厂类,它的优点是所有产品类的实例化集中管理,便于理解,但这既是优点也是缺点。如果
产品类的数量较少并且不会经常发生变化,我们可以直接利用简单工厂模式,但是有的时候,需求是随时在变的,产品类也可能随时在增加,如果使用简单工厂模式,就不可避免的要去修改工厂类的代码。要解决这个问题,就要提到今天要说的工厂方法模式。

基本概念

工厂方法模式:不再有一个唯一的工厂类就创建产品,而是将不同的产品交给对应的工厂子类去实现。每个产品由负责生产的子工厂来创造。如果添加新的产品,需要做的是添加新的子工厂和产品,而不需要修改其他的工厂代码。

工厂方法模式主要有三种类组成:
1.抽象工厂类:负责定义创建产品的公共接口。
2.产品子工厂:继承抽象工厂类,实现抽象工厂类提供的接口
3.每一种产品各自的产品类

工厂方法模式的实现

首先,我们对《Javascript设计模式理论与实战:简单工厂模式》一文中简单工厂模式的代码进行改造。下面是简单工厂公式的代码:

 var productEnums = {
flight: "flight",
hotel: "hotel"
};
function Flight() {
console.log("This is Flight");
}
function Hotel() {
console.log("This is Hotel");
}
var productFactory = (function () {
var productFactories = {
"flight": function () {
return new Flight();
},
"hotel": function () {
return new Hotel();
}
}; return {
createProduct: function (productType) {
return productFactories[productType]();
}
}
})();
function User() {
this.shopCart = [];
}
User.prototype = {
constructor: User,
order: function (productType) {
this.shopCart.push(productFactory.createProduct(productType));
}
}

要将上面的代码修改成工厂方法模式,首先要构造一个抽象工厂类。在JS中,由于我们抽象类的概念,我们无法做到像Java,C#的抽象工厂类,但是我们可以去模拟它。代码如下

 function AbstractFactory() {
}
AbstractFactory.prototype.createProduct = function () {
throw "没有实现该方法";
}

在这段代码中,定义了一个工厂类,然后定义了它的一个方法CreateProduct,这个方法模拟抽象方法,不提供具体实现,而是抛出错误,继承的工厂类就要去实现具体方法,否则会抛错,这就模拟了一个抽象工厂类。
定义完抽象工厂类后,现在我们要做的就是定义子工厂去实现它,我们分别定义两个子工厂FlightFactory和HotelFactory。

 function FlightFactory() {
AbstractFactory.call(this);
}
FlightFactory.prototype = new AbstractFactory();
FlightFactory.prototype.createProduct = function () {
return new Flight();
}
function HotelFactory() {
AbstractFactory.call(this);
}
HotelFactory.prototype = new AbstractFactory();
HotelFactory.prototype.createProduct = function () {
return new Hotel();
}

以上代码分别定义了两个子工厂类,每个子类继承抽象工厂类,然后实现createProduct方法,每一种产品在各自的工厂类里创建。
在客户端怎么调用呢?

 var factory = new FlightFactory();
factory.createProduct();
factory = new HotelFactory();
factory.createProduct();

疑点解答

首先我们要理解一个概念:开放封闭原则。
软件实体应该是可扩展但不可修改的,就是对扩展是开放但是对修改是封闭的。体现在两个方面:
(1)对扩展开放,产品有新需求或变活时,可以对现有代码进行扩展,以适应新变化
(2)对修改封闭,类一旦设计完成,就不应该对其进行修改。

下面来说说几个疑点
1、相比于简单工厂模式,工厂方法模式增多了一个抽象工厂类和多个子工厂类,这样代码不是更复杂了吗?
确实,代码比简单工厂模式复杂了,引入了抽象层,还有子工厂,这会增加代码的复杂度和理解难度。但是相比于简单工厂模式,代码的维护性和扩展性提高了,新增产品时,只需要增加对应的产品类和产品工厂类,不需要修改到抽象工厂类和其他子工厂。更加符合面向对象的开放封闭原则。
当然具体场景具体分析,复杂性和扩展性相比如何舍去,在使用的时候要结合实际场景去分析。
2、在客户端调用的时候,每一种产品还是需要知道具体的工厂类来调用,好像区别不大?
和简单工厂模式的区别在于:我们将判断使用哪一个产品类的代码从工厂类转移到了调用的客户端这里,如果有新功能要添加,我们要修改的是客户端的代码而不是工厂类的代码,这样才符合开放封闭原则。

总结

实现要点

在JS中,我们实现工厂方法模式主要包括3个角色:
1.抽象工厂类:提供工厂方法的声明
2.子工厂类:实现抽象工厂类的工厂方法
3.产品类:具体的产品类

优缺点

优点:克服了简单工厂模式的缺点。如果需要增加新的产品类,无须修改现有系统,只需要增加新的工厂类和产品类;每个工厂类封装了产品对象的创建细节,系统具有良好的灵活性和可扩展性。
缺点:增加新产品的同时需要增加新的工厂,导致系统类的个数成对增加,在一定程度上增加了系统的复杂性。

原文地址:http://luopq.com/2015/11/10/design-pattern-factory-method/

Javascript设计模式理论与实战:工厂方法模式的更多相关文章

  1. Javascript设计模式理论与实战:桥接模式

    桥接模式将抽象部分与实现部分分离开来,使两者都可以独立的变化,并且可以一起和谐地工作.抽象部分和实现部分都可以独立的变化而不会互相影响,降低了代码的耦合性,提高了代码的扩展性. 基本理论 桥接模式定义 ...

  2. Javascript设计模式理论与实战:状态模式

    在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将其抽象出来称为状态,我们平时开发时本质上就是对应用程序的各种状态进行切换并作出相应处理.状态模式就是一种适合多种状态场景下的设计模式 ...

  3. Javascript设计模式理论与实战:组合模式

    我们平时开发过程中,一定会遇到这种情况:同时处理简单对象和由简单对象组成的复杂对象,这些简单对象和复杂对象会组合成树形结构,在客户端对其处理的时候要保持一致性.比如电商网站中的产品订单,每一张产品订单 ...

  4. 前端读者 | Javascript设计模式理论与实战:状态模式

    本文来自 @狼狼的蓝胖子:链接:http://luopq.com/2015/11/25/design-pattern-state/ 在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将 ...

  5. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

  6. 重学 Java 设计模式:实战工厂方法模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  7. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  8. 设计模式(三)工厂方法模式(Factory Pattern)

    一.引言 在简单工厂模式中讲到简单工厂模式的缺点,有一点是——简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过于复杂,然而本专题介绍的工厂方法模式可以 ...

  9. 设计模式(2)工厂方法模式(Factory Method)

    设计模式(0)简单工厂模式 设计模式(1)单例模式(Singleton) 源码地址 0 工厂方法模式简介 0.0 工厂方法模式定义 工厂方法模式是在简单工厂模式基础上,为解决更复杂的对象创建问题而衍生 ...

随机推荐

  1. [转]Spring 之 Bean 生命周期

    Spring 容器中可以注册多个后处理器,只要它们同时实现 org.springframework.core.Ordered 接口. 下载文件 :内容来自 <精通Spring+4.x++企业应用 ...

  2. sql之强制索引

    1.今天我遇到一个问题,在处理百万级数据查询的时候,一般查询会很慢. 2.第一时间想到是建立联合索引,但是数据库存在多条索引的情况下,索引的执行是全部执行. 3.所以这里要按照特定的索引执行,就必须使 ...

  3. ACM刷题踩坑记录

    2017-12-26: 1.再次被写法坑了好长一会,调了半天的bug,还是没找出来.最后,发现,又坑在这个小细节上了.这样子写,第一个if和第三个else在一次循环中都会执行,然后,就GG了. 要注意 ...

  4. MySQL 存储配置

  5. poj-3253-Fence Repair(哈夫曼)

    /* Fence Repair Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 19914 Accepted: 6314 Desc ...

  6. 代理Servlet过滤器

    Spring Security借助一些列Servlet 过滤器 来提供 各种 安全性功能. 我们只需要在应用中的 web.xml 中配置 一个过滤器. <filter> <filte ...

  7. php接收base64编码的文件内容并保存

    <?php header('Content-type:text/html;charset=utf-8'); //读取图片文件,转换成base64编码格式 $image_file = './fac ...

  8. SecureCRT 8.1使用经验总结

    1.反空闲设置: 2.文件上传下载 上传 sudo rz -y 文本文件勾选Upload files as ASCII,图片或其他飞文本文件,去掉勾选.采用默认binary 3.文件下载 sudo s ...

  9. 跟我学算法-图像识别之图像分类(上)(基础神经网络, 卷积神经网络(CNN), AlexNet,NIN, VGG)

    1.基础神经网络: 输入向量x,权重向量w, 偏置标量b, 激活函数sigmoid(增加非线性度) 优化手段: 梯度下降优化, BP向后传播(链式规则) 梯度下降优化: 1. 使用得目标函数是交叉熵  ...

  10. VUE项目 - IE报vuex requires a Promise polyfill in this browser问题解决

    第一步: 安装 babel-polyfill . babel-polyfill可以模拟ES6使用的环境,可以使用ES6的所有新方法 npm install --save babel-polyfill ...