当前位置: 首页 > news >正文

《JavaScript设计模式》——9.10 Factory(工厂)模式

本节书摘来自异步社区《JavaScript设计模式》一书中的第9章,第9.10节, 作者: 【美】Addy Osmani 译者: 徐涛 更多章节内容可以访问云栖社区“异步社区”公众号查看。

9.10 Factory(工厂)模式

Factory模式是另一种创建型模式,涉及创建对象的概念。其分类不同于其他模式的地方在于它不显式地要求使用一个构造函数。而Factory可以提供一个通用的接口来创建对象,我们可以指定我们所希望创建的工厂对象的类型(见图9-9)。
screenshot

假设有一个UI工厂,我们要创建一个UI组件的类型。不需要直接使用new运算符或者通过另一个创建型构造函数创建这个组件,而是要求Factory对象创建一个新的组件。我们通知Factory需要什么类型的对象(如“按钮”、“面板”),它会进行实例化,然后将它返回给我们使用。

如果对象创建过程相对比较复杂,这种方法特别有用,例如,如果它强烈依赖于动态因素或应用程序配置的话。

可以在ExtJS等UI库中找到此模式的示例,其中创建对象或组件的方法也有可能被归入子类了。

下面这个示例构建在之前的代码片段之上,使用Constructor模式逻辑来定义汽车。它展示了如何使用Factory模式来实现vehicle工厂:

// Types.js –本例构造函数的存放文件
// 定义Car构造函数

function Car(options) {
  // 默认值
  this.doors = options.doors || 4;
  this.state = options.state || "brand new";
  this.color = options.color || "silver";
}

// 定义Truck构造函数

function Truck(options) {
   this.state = options.state || "used";
   this.wheelSize = options.wheelSize || "large";
   this.color = options.color || "blue";
}

// FactoryExample.js
// 定义vehicle工厂的大体代码

function VehicleFactory() { }

// 定义该工厂factory的原型和试用工具,默认的vehicleClass是Car

VehicleFactory.prototype.vehicleClass = Car;

// 创建新Vehicle实例的工厂方法

VehicleFactory.prototype.createVehicle = function (options) {
   if (options.vehicleType === "car") {
       this.vehicleClass = Car;
   } else {
       this.vehicleClass = Truck;
   }
   return new this.vehicleClass(options);
};

// 创建生成汽车的工厂实例

var carFactory = new VehicleFactory();
var car = carFactory.createVehicle({
               vehicleType: "car",
               color: "yellow",
               doors: 6});

// 测试汽车是由vehicleClass的原型prototype里的Car创建的
// 输出: true

console.log(car instanceof Car);

// 输出: Car对象,color: "yellow", doors: 6,state:"brand new"

console.log(car);

在方法 1 中,我们修改了VehicleFactory实例来使用Truck类:

var movingTruck = carFactory.createVehicle({
                      vehicleType: "truck",
                      state: "like new",
                      color: "red",
                      wheelSize: "small"});

// 测试卡车是由vehicleClass的原型prototype里的Truck创建的
// 输出: true

console.log(movingTruck instanceof Truck);

// 输出: Truck对象,color :"red", state:"like new" ,wheelSize:"small"

console.log(movingTruck);

在方法2中,我们把VehicleFactory归入子类来创建一个构建Truck的工厂类:

function TruckFactory() { }
TruckFactory.prototype = new VehicleFactory();
TruckFactory.prototype.vehicleClass = Truck;
var truckFactory = new TruckFactory();
var myBigTruck = truckFactory.createVehicle({
                      state: "omg..so bad.",
                      color: "pink",
                      wheelSize: "so big"});

// 确认myBigTruck是由原型Truck创建的
// 输出: true

console.log(myBigTruck instanceof Truck);

// 输出:Truck对象,color: pink", wheelSize: "so big", state: "omg. so bad"

console.log(myBigTruck);

9.10.1 何时使用Factory模式
Factory模式应用于如下场景时是特别有用的:

当对象或组件设置涉及高复杂性时
当需要根据所在的不同环境轻松生成对象的不同实例时
当处理很多共享相同属性的小型对象或组件时
在编写只需要满足一个API契约(亦称鸭子类型)的其他对象的实例对象时。对于解耦是很有用的。
9.10.2 何时不应使用Factory模式
如果应用错误,这种模式会为应用程序带来大量不必要的复杂性。除非为创建对象提供一个接口是我们正在编写的库或框架的设计目标,否则我建议坚持使用显式构造函数,以避免不必要的开销。

由于对象创建的过程实际上是藏身接口之后抽象出来的,单元测试也可能带来问题,这取决于对象创建的过程有多复杂。

9.10.3 Abstract Factory(抽象工厂)
了解抽象工厂模式也是有用的,它用于封装一组具有共同目标的单个工厂。它能够将一组对象的实现细节从一般用法中分离出来。

应当使用抽象工厂模式的情况是:一个系统必须独立于它所创建的对象的生成方式,或它需要与多种对象类型一起工作。

既简单又容易理解的示例是车辆工厂,它定义了获取或注册车辆类型的方法。抽象工厂可以命名为AbstractVehicleFactory。抽象工厂将允许对像car或truck这样的车辆类型进行定义,具体工厂只需要实现履行车辆契约的类(如Vehicle.prototype.drive和Vehicle.prototype.breakDown)。

var AbstractVehicleFactory = (function () {
// 存储车辆类型
  var types = {};
  return {
       getVehicle: function ( type, customizations ) {
            var Vehicle = types[type];
            return (Vehicle) ? return new Vehicle(customizations) : null;
       },
       registerVehicle: function ( type, Vehicle ) {
            var proto = Vehicle.prototype;
            // 只注册实现车辆契约的类
            if ( proto.drive && proto.breakDown ) {
                  types[type] = Vehicle;
            }
            return AbstractVehicleFactory;
        }
  };
})();
// 用法:
AbstractVehicleFactory.registerVehicle( "car", Car );
AbstractVehicleFactory.registerVehicle( "truck", Truck );
// 基于抽象车辆类型实例化一个新car对象
var car = AbstractVehicleFactory.getVehicle( "car" , {
             color: "lime green",
             state: "like new" } );
// 同理实例化一个新truck对象
var truck = AbstractVehicleFactory.getVehicle( "truck" , {
                wheelSize: "medium",
                color: "neon yellow" } );

相关文章:

  • 以太网帧格式、IP数据报格式、TCP段格式+UDP段格式 详解
  • webgis实现技术分析
  • 《Oracle数据库性能优化方法论和最佳实践》——第3章 流程分析之数据库登录流程 3.1 数据库登录导致业务系统性能恶化案例分享...
  • 《Cisco BGP-4 命令与配置手册》——导读
  • 《Tableau 8权威指南》—— 导读
  • 《Python和Pygame游戏开发指南》——2.8 关于函数、方法、构造函数和模块中的函数(及其差别)的一些提示...
  • DataFormatString 属性语法
  • 《树莓派渗透测试实战》——1.6 树莓派的优点和缺点
  • 在HttpHandlers中使用Session
  • 《机器人爱好者(第3辑)》——导读
  • 《Android 应用案例开发大全(第3版)》——第2章,第2.4节壁纸的实现
  • c#学习网址
  • 《敏捷软件开发:原则、模式与实践(C#版.修订版)》一1.4 参考文献
  • 分钱单算法
  • 《C和C++代码精粹》——1.16 语句声明
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • java中的hashCode
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • Object.assign方法不能实现深复制
  • Python学习笔记 字符串拼接
  • SpringBoot 实战 (三) | 配置文件详解
  • SwizzleMethod 黑魔法
  • 二维平面内的碰撞检测【一】
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 入口文件开始,分析Vue源码实现
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 手写一个CommonJS打包工具(一)
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 我是如何设计 Upload 上传组件的
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • hi-nginx-1.3.4编译安装
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • #FPGA(基础知识)
  • #NOIP 2014# day.1 T2 联合权值
  • #pragma multi_compile #pragma shader_feature
  • #每日一题合集#牛客JZ23-JZ33
  • $forceUpdate()函数
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)计算机毕业设计高校学生选课系统
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (十)c52学习之旅-定时器实验
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)Linux下编译安装log4cxx
  • (转)shell调试方法
  • .NET Core 成都线下面基会拉开序幕
  • .net core使用ef 6
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .Net的C#语言取月份数值对应的MonthName值