摘要:假设有一个生产交通工具的工厂类,它包含生成多种交通工具实例的方法。在使用这个类生产对象的时候,传入参数,在参数中的属性规定我们需要的类型,构造函数就能够返回我们需要的对象类型了。
一般来说,创建对象的时候我们都习惯使用new关键字来调用constructor构造函数,但使用这种方式会有一些缺点,首先构造器函数的创建本身就是为了模仿其他一些面向对象语言的特性,有些人觉得这是non-sense;另一方面,在一个类中用new关键字调用其他类的构造函数,会造成两个类之间的耦合,设计模式应该要尽量避免这些影响代码可重用性的问题。
简单工厂模式一个工厂可以生产同一类的多种物品,具体生产哪种就看客户下什么订单了。工厂模式也是一样,我们创建一个工厂类,它可以创建多种实例,由开发者指定。
假设有一个生产交通工具的工厂类Vehicle,它包含生成多种交通工具实例的方法。
function Vehicle() {} Vehicle.prototype = { createVihicle: function(options) { var vehicle; switch(options.type) { case "car": vehicle = new Car(); break; case "truck": vehicle = new Truck(); break; default: vehicle = new Bike(); } return vehicle; } };
在使用这个类生产对象的时候,传入option参数,在参数中的type属性规定我们需要的类型,构造函数就能够返回我们需要的对象类型了。使用这种方法,如果我们要添加新的交通工具类型也是很方便的,在工厂的switch中直接添加一个case就可以了。
switch(options.type) { case "car": vehicle = new Car(); break; case "truck": vehicle = new Truck(); break; case "plane": vehicle = new Plane(); break; default: vehicle = new Bike(); }
通过这种方式,将成员对象的创建工作转交给外部对象,可以像上述代码一样转交给独立的命名空间,像Car,Truck,Plane等,如果外部对象属于同一类的话,将它们组织为一个大类中的子类比较合理。
工厂模式以上介绍的是简单工厂模式,简单工厂模式会把创建工作交给外部的类来做,这实际上会增加类的数量,并不利于代码的组织。真正的工厂模式会把创建工作交给子类来完成,父类只对创建过程中的一般性问题进行处理,这些处理会影响到每个子类,而子类之间相互独立,可以对创建过程进行一些定制化操作。
还是以生产交通工具为例,将交通工具父类改写为一个抽象类,它不负责直接生产交通工具,而是通过它派生出一些子类,这些子类代表不同的国家,不同的国家可以生产自己的交通工具。
将父类抽象化:
function Vehicle() {} Vehicle.prototype = { createVihicle: function(options) { // 这里不直接生产,如果直接调用会抛出错误 throw new Error("Unsupported operation on an abstract class.") } };
不同的国家作为子类,子类首先对父类进行继承,然后实现自己的createVehicle方法。
function China() {} // 继承方法 extend(China, Vehicle); // 实现自己的createVehicle方法 China.prototype.createVehicle = function(options) { var vehicle; switch(options.type) { case "car": vehicle = new Car(); break; case "truck": vehicle = new Truck(); break; default: vehicle = new Bike(); } return vehicle; }
以后要生产交通工具的时候就调用China子类的createVehicle方法就可以了。
var chinaVehicle = new China(); var myCar = chinaVehicle.createVehicle({ type: "Car" });
一般性的代码集中在父类中,个性化的代码在子类中多带带定制。
工厂模式适用场合子类的共同点是它们都实现了同一批接口,尽管内部细节并不尽相同。生产对象的方法有一个选择性的过程,这种选择可以是开发者自定的,比如需要生产何种交通工具,也可以是自动选择的,比如根据浏览器环境生产合适的XHR对象。对于相似性很高,实现了同一类接口的对象,工厂模式是比较合适的。
另外的一大好处就是子类的一些设置代码可以全部放在父类的构造器函数中,不需要在每个子类的构造函数中重复运行同样的代码,只需要在父类的代码中实现一次就好。子类只需要专注于实现自己的方法,不用考虑别的问题。
最后一点则是如果一个类中包含了很多更小的子类作为自己的组成部分,那么替换这些子类的工作会很简单,因为工厂模式降低了模块之间的耦合度,一个模块并不会依赖于其某一组成部分。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/87528.html
摘要:三种使用构造函数创建对象的方法和的作用都是在某个特殊对象的作用域中调用函数。这种方式还支持向构造函数传递参数。叫法上把函数叫做构造函数,其他无区别适用情境可以在特殊的情况下用来为对象创建构造函数。 一、工厂模式 工厂模式:使用字面量和object构造函数会有很多重复代码,在此基础上改进showImg(https://segmentfault.com/img/bVbmKxb?w=456&...
摘要:使用构造器有个严重的危害,如果在调用构造器函数的时候忘记使用前缀,不仅不会绑定到新对象,还会污染全局变量原型模式原型模式中,我们采用对象来继承。 构造器调用模式 当一个函数对象被创建时,Function构造器会运行类似这样的代码: this.prototype = {constructor: this} new一个函数事会发生: Function.method(new, functio...
命名空间 var MYNAMESPACE = MYNAMESPACE || {}; //构造函数 MYNAMESPACE.Child = function () {} // 变量 MYNAMESPACE.mystr= 6-ara forerer MYNAMESPACE.Person = function(name) { this.name = name; }; //原型 MYNAMES...
摘要:继承的是超类型中构造函数中的属性,如上继承了属性,但没有继承原型中的方法。上述造成的结果是子类型实例中有两组超类型的构造函数中定义的属性,一组在子类型的实例中,一组在子类型实例的原型中。 ECMAScript只支持实现继承,主要依靠原型链来实现。与实现继承对应的是接口继承,由于script中函数没有签名,所以无法实现接口继承。 一、原型链 基本思想:利用原型让一个引用类型继承另一个引用...
摘要:具体检查方式则是检查对象是否实现了接口所声明的所有方法。组合模式将对象群体与组成对象同等对待。装饰者模式透明地为另一对象提供包装,实现相同的接口。 Javascript 中模仿接口的三种方法 1. 注释描述 /* interface Composite { function add(child); function remove(child); function ge...
阅读 3185·2021-11-23 09:51
阅读 3540·2021-11-09 09:46
阅读 3558·2021-11-09 09:45
阅读 2919·2019-08-29 17:31
阅读 1798·2019-08-26 13:39
阅读 2690·2019-08-26 12:12
阅读 3567·2019-08-26 12:08
阅读 2175·2019-08-26 11:31