文档章节

JavaScript 常用的设计模式之工厂模式

w-rain
 w-rain
发布于 2016/08/29 15:49
字数 1496
阅读 36
收藏 1

工厂模式的介绍

      一个类或对象中往往会包含别的对象。在创建这种成员对象时,你可能会使用常规方式,也即用new关键字和类构造函数。问题在于这会导致相关的两个类之间产生依赖性。工厂模式有助于消除这两个类之间的依赖性的模式,它使用一个方法来决定究竟决定要实例化哪个具体的类。简单工厂模式使用一个类(通常是一个单体)来生成实例,复杂工厂模式则使用子类来决定一个成员变量应该使用哪个具体的类的实例。

    简单工厂

           假设你准备开几个自行车商店,每个店都有几种型号的自行车出售,这可以用一个Bicycle类来标识,假如你要出售某种型号的自行车,只需要调用sellBicycle方法即可:

/*BicycleShop class*/

var BicycleShop = function(){};

BicycleShop.prototype = {

	sellBicycle:function(model){

		var bicycle;
		switch(model){
			case 'The Speedster':
			bicycle = new Speedster();
			break;
			case 2:
			bicycle = ...;
			break;
			default:
			bicycle = ...;
		}

		Interface.ensureImplements(bicycle,Bicycle);

		bicycle.assemble();

		bicycle.wash();

		return bicycle;
	}

};

/* The Bicycle interface*/

var Bicycle = new Interface('Bicycle',['assemble','wash','ride','repair']);

/*Speedster class*/

var Sppedster = function(){
 	// implements Bicycle
 	...
 };

 Speedster.prototype = {

 	assemble:function(){ ... },

 	wash: function(){ ... },

 	ride:function(){ ... },

 	repair:function(){ ... }

 };

 /* 出售The Speedster型号的自行车*/

 var giantCruusers = new BicycleShop();

 var myNewBike = giantCruusers.sellBicycle('The Speedster');

            当我们需要在供货目录中新加入一款车型,我们不用修改BicycleShop的代码,只需要将sellBicycle方法中“创建新实例”的这部分工作转交给一个简单的工厂对象。BicycleFactory 是一个单体,将createBicycle方法封装在一个命名空间中,然后你可以照常进行组装和清洗。这个BicycleFactory对象可以提供各种类来创建新的自行车实例。

 /* BicycleFactory namespace*/

 var BicycleFactory = {

 	createBicycle:function(model){

 		var bicycle;

 		switch(model){
 			case 'The Speedster':
 			bicycle = new Speedster();
 			break;
 			case 2:
 			bicycle = ...;
 			break;
 			default:
 			bicycle = ...;
 		}

 		Interface.ensureImplements(bicycle, Bicycle);

 		return bicycle;
 	}
 };

 /* BicycleShop class, improved*/

 var BicycleShop = function(){};

 BicycleShop.prototype = {

 	sellBicycle:function(){

 		var bicycle = BicycleFactory.createBicycle(model);

 		bicycle.assemble();

 		bicycle.wash();


 		return bicycle;
 	}
 };

            BiycleFactory就是简单工厂模式的例子,这种模式把成员对象的创建工作转交给一个外部对象。

    工厂模式

            真正的工厂模式和简单工厂模式区别在于,它不是另外使用一个类或对象来创建自行车,而是使用一个子类。现在我们打算让各自自行车店自行决定从哪个生产厂家进货。因此,单单一个BicycleFactory对象无法提供需要的所有自行车实例,我们把BicycleShop设计为抽象类,让之类根据各自的进货渠道实现其createBicycle方法:

/* BicycleShop class (abstract)*/

var BicycleShop = function(){};

BicycleShop.prototype = {

	sellBicycle: function(model){

		var bicycle = this.createBicycle(model);

		bicycle.assemble();

		bicycle.wash();

		return bicycle;
	},

	createBicycle: function(model){
		throw new Error('Unsupported operation on an abstract class. ');
	}
};

        设计一个自行车生产厂家的子类需要扩展BicycleShop,重定义其中的createBicycle方法。其中一个是从Acme公司进货,另一个是从General Products公司进货。

/*AcmeBicycleShop class*/

var AcmeBicycleShop = function() {};

extend(AcmeBicycleShop, BicycleShop);

AcmeBicycleShop.prototype.createBicycle = function(model) {

    var bicycle;

    switch (model) {
        case 'The Speedster':
            bicycle = new AcmeSpeedster();
            break;

            ...
    }

    Interface.ensureImplements(bicycle, Bicycle);

    return bicycle;
};


/*GeneralProductsBicycleShop class*/

var GeneralProductsBicycleShop = function() {};

extend(GeneralProductsBicycleShop, BicycleShop);

GeneralProductsBicycleShop.prototype.createBicycle = function(model) {

    var bicycle;

    switch (model) {
        case 'The Speedster':
            bicycle = new GeneralProductsSpeedster();
            break;

            ...
    }

    Interface.ensureImplements(bicycle, Bicycle);

    return bicycle;
};


/*商店可以是Acme或General Products的自行车专卖店*/

var acmeCruisers = new AcmeSpeedster();

var myNewBike = acmeCruisers.sellBicycle('The Speedster');


var generalCruisers = new GeneralProductsSpeedster();

var myNewBike = generalCruisers.sellBicycle('The Speedster');

 

工厂模式的适用场合

    1.动态实现

         在考虑到返回的连接对象的类型取决于所探查到的带宽和网路延时等因素,通常要与一系列实现了同一个接口、可以被同等对待的类打交道。

    2.节省设置开销

        如果对象需要进行复杂并且彼此相关的设置,那么使用工厂模式可以减少每种对象所需的代码量。如果这种设置只需要为特定类型的所有实例执行一次即可,这种作用尤其突出。工厂模式可以在实例化所有需要的对象之前先一次性地进行设置。无论有多少不同的代码会被实例化,这种方法都可以设置代码集中在一个地方。如果使用的类要求加载外部库的话,尤其有用。

    3.用许多小型对象组成一个大对象

        工厂方法可以创建封装了许多较小单独的对象。大对象的构造函数不依赖于某种特定的小对象,保证对象自己的松耦合。

工厂模式的优劣

    优势:

            工厂模式的好处在于消除对象间的耦合。通过使用工厂模式而不是new关键字及具体类,你可以把所有的实例化代码集中在一个位置。简化更换所用类或在运行期间动态选择所用类的工作,在派生子类方面它提供了更大的灵活性。使用工厂模式,你可以先创建一个抽象的父类,然后再子类中创建工厂的方法,从而把成员对象的实例化推迟到更专业化的子类中进行。

      面向对象设计的两条原则:弱化对象间的耦合;防止代码重复。在一个方法中进行类的实例化,可以消除重复性的代码,这是在用一个对接口的调用取代一个具体的实现,有助于创建模块化的代码。

    劣势:

            如果根本不可能另外换用一个类,或者不需要再运行期间在一系列可互换的类中进行选择,那就不应该使用工厂方法。大多数类最好使用new关键字和构造函数公开地进行实例化。

 

参考资料

【美】Ross Harmes 、Dustin Diaz 著《JavaScript 设计模式》

 

转载时请注明:来自w-rain的个人博客

© 著作权归作者所有

下一篇: css 单位
w-rain
粉丝 27
博文 54
码字总数 46502
作品 0
成都
程序员
私信 提问
《JavaScript设计模式与开发实践》原则篇(2)—— 最少知识原则

最少知识原则(LKP)说的是一个软件实体应当尽可能少地与其他实体发生相互作用。这 里的软件实体是一个广义的概念,不仅包括对象,还包括系统、类、模块、函数、变量等。 单一职责原则指导我们...

嗨呀豆豆呢
2018/12/30
0
0
《JavaScript设计模式与开发实践》最全知识点汇总大全

系列文章: 《JavaScript设计模式与开发实践》基础篇(1)—— this、call 和 apply 《JavaScript设计模式与开发实践》基础篇(2)—— 闭包和高阶函数 《JavaScript设计模式与开发实践》模式...

嗨呀豆豆呢
01/04
0
0
JavaScript设计模式总结

之前看过《JavaScript设计模式与开发实践》这本书,对书中的设计模式和一些相关案例也有了一定的了解,同时把这些设计模式的应用对应在在一些其他的项目中,进行了一些整理,如下仅供参考: ...

jefferyE
03/26
0
0
JavaScript 中常见设计模式-单例模式

     单例模式两个条件   确保只有一个实例   可以全局访问   适用   适用于弹框的实现,全局缓存   实现单例模式      JavaScript 中的单例模式   因为 JavaScript 是无...

webstack前端栈
2018/05/19
0
0
JavaScript 常见设计模式

前言 设计模式,这一话题一直都是程序员谈论的"高端"话题之一。许多程序员从设计模式中学到了设计软件的灵感和解决方案。 有人认为设计模式只在 C++或者 Java 中有用武之地,JavaScript 这种...

YeeWang王大白
03/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

带你了解 Java内存模型

Java内存模型的规定: 1、所有变量存储在主内存中; 2、每个线程都有自己的工作内存,且对变量的操作都是在工作内存中进行; 3、不同线程之间无法直接访问彼此工作内存中的变量,要想访问只能...

linux-tao
23分钟前
4
0
.net c# datetime转string 时间转字符串

.net c# datetime转string 时间转字符串 .net c# datetime转string 时间转字符串 刚开始接触net 时间转换字符串 一搜索出来的全是 字符串转时间,要么就是系统当前时间转字符串 就没有一个指...

青峰Jun19er
24分钟前
4
0
hbase demo

HbaseDao public class HbaseDao {@Testpublic void insertTest() throws Exception {Configuration conf = HBaseConfiguration.create();conf.set("hbase.zookeeper.qu......

Garphy
34分钟前
3
0
IT兄弟连 HTML5教程 HTML5表单 多样的输入类型2

4 range range类型用于包含一定范围内数字值的输入域,跟number一样,我们还可以对数值设置限定,range类型显示为滑动条用法如下: 上述代码使用了range类型输入框,为该类型设置了数值范围为...

老码农的一亩三分地
34分钟前
3
0
对比不同的数据库连接的异同

博主在学习和使用数据库连接时,遇到的问题, 这个几个数据库连接究竟有什么不同? 到底什么时候该使用哪个会更好一点? 带着这个问题我们先去了解常见的数据库连接 1. 常见的数据库连接有哪些?...

理性思考
36分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部