<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生成器模式</title>
</head>
<body> <script>
/**
* 生成器模式
*
* 定义:
* 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
*
* 本质:
* 分离整体构建算法和部件构造。
* 生成器模式的重心在于分离整体构建算法和部件构造,而分步骤构建对象不过是整体构建算法的一个简单实现,或者说是一个附带产物。
*
* 要实现同样的构建过程可以创建不同的表现,那么一个自然的思路就是先把构建过程独立出来,在生成器模式中把它称为指导者,由它来指导装配过程,但是不负责每步具体的实现。当然,光有指导者是不够的,必须要有能具体实现每步的对象,在生成器模式中称这些实现对象为生成器。
* 这样一来,指导者就是可以重用的构建过程,而生成器是可以被切换的具体实现。
*
* 功能:
* 主要功能是构建复杂的产品,而且是细化的,分步骤的构建产品,也就是生成器模式中在一步一步解决构造复杂对象的问题。更为重要的是,这个构建的过程是统一的,固定不变的,变化的部分放到生成器部分了,只要配置不同的生成器,那么同样的构建过程,就能构建出不同的产品来。
* 生成器模式的重心在于分离构建算法和具体的构造实现,从而使得构建算法可以重用。具体的构造实现可以很方便地扩展和切换,从而可以灵活的组合来构造出不同的产品对象。
*
* 构成:
* 1.一个部分是Builder接口,这里是定义了如何构建各个部件,也就是知道每个部件功能如何实现,以及如何装配这些部件到产品中去。
* 2.另外一个部分是Director,Director是知道如何组合来构建产品,也就是说Director负责整体的构建算法,而且通常是分步骤地来执行。
* 不管如何变化,Builder模式都存在这么两个部分,一个部分是部件构造和产品装配,另一个部分是整体构建的算法。
*
* 使用:
* 应用生成器模式的时候,可以让客户端创造Director,在Director里面封装整体在、构建算法,然后让Director去调用Builder,让Builder来封装具体部件的构建功能。
* 还有一种退化的情况,就是让客户端和Director融合起来,让客户端直接去操作Builder,就好像是指导者自己想要给自己构建产品一样。
*
* 何时使用:
* 1.如果创建对象的算法,应该独立于该对象的组成部分以及它们的装配方式时。
* 2.如果同时一个构建过程有着不同的表示时。
*
*/ // 示例代码 // 生成器对象,创建一个产品对象所需的各个部件的操作
var Builder = function(){
// 生成器最终构建的产品对象
var resultProduct; // 获取生成器最终构建的产品对象
this.getResult = function(){
return resultProduct;
}; this.buildPart = function(){
// 构建某个部件的功能处理
};
} // 指导者,指导使用生成器的接口来构建产品的对象
// 传入生成器对象
var Director = function(builder){
this.builder = builder;
};
Director.prototype = {
// 通过使用生成器接口来构建最终的产品对象
construct: function(){
this.builder.buildPart();
}
}; (function(){ // 生成器接口,定义创建一个输出文件对象所需的各个部件的操作
var Builder = function(){};
Builder.prototype = {
// 构建输出文件的Header部分
buildHeader: function(ehm){},
// 构建输出文件的Body部分
buildBody: function(mapData){},
// 构建输出文件的Footer部分
buildFooter: function(efm){}
}; // 实现到处数据到文本文件的生成器对象
var TxtBuilder = function(){
this.stringBuffer = '';
};
TxtBuilder.prototype = {
__proto__: Builder.prototype, buildBody: function(mapData){
var tblName, edm;
for(tblName in mapData) {
this.stringBuffer += tblName + "\n"; for(edm in mapData[tblName]) {
this.stringBuffer += edm.getProductId() + ',' +
edm.getPrice() + ',' + edm.getAmount() + '\n';
}
}
},
buildFooter: function(efm){
this.stringBuffer += efm.getExportUser();
},
buildHeader: function(ehm){
this.stringBuffer += ehm.getDepId() + ',' +
ehm.getExportDate() | '\n';
},
getResult: function(){
return new Buffer(this.stringBuffer);
}
}; // 实现导出数据到XML文件的生成器对象
var XmlBuilder = function(){
this.stringBuffer = '';
};
XmlBuilder.prototype = {
__proto__: Builder,
buildBody: function(){},
buildFooter: function(){},
buildHeader: function(){},
getResult: function(){}
}; // 指导者,指导使用生成器的接口来构建输出的文件的对象
var Director = function(builder){
// 传入生成器对象
this.builder = builder;
};
Director.prototype = {
// 指导生成器构建最终的输出的文件的对象
construct: function(ehm, mapData, efm){
this.builder.buildHeader(ehm);
this.builder.buildBody(mapData);
this.builder.buildFooter(efm);
}
}; var textBuilder = new TxtBuilder();
var director = new Director(textBuilder);
director.construct(ehm, mapData, efm); var xmlBuilder = new XmlBuilder();
var director2 = new Director(director);
director2.construct(ehm, mapData, efm); }()); /*
生成器模式的实现 1。生成器的实现
实际上在Builder接口的实现中,每个部件构建的方法里面,除了部件装配外,也可以实现如何具体地创建各个部件对象。也就是说每个方法都可以由两部分功能,一部分是创建部件对象,另一部分是组装部件。
在构建部件的方法里面可以实现选择并创建具体的部件对象,然后再把这个部件对象组装到产品对象中去。这样一来,Builder就可以和工厂方法配合使用了。
再进一步,如果在实现Builder的时候,只有创建对象的功能,而没有组装的功能。那么这个时候的Builder实现跟抽象工厂的实现是类似的。
这种情况下,Builder接口就类似抽象工厂的接口,Builder的具体实现就类似于具体的工厂,而且Builder接口里面定义的创建各个部件的方法也是有关联的,这些方法是构建一个复杂对象所需要的部件对象。 2.指导者的实现
在生成器模式里面,指导者承担的是整体构建算法部分,是相对不变的部分。因此在实现指导者的时候,把变化的部分分离出去很重要。
其实指导者分离出去的变化部分,就到了生成器那里,指导者知道整体的构建算法,却不知道如何具体的创建和装配部件对象。
因此真正的指导者实现,并不仅仅是简单地按照一定的顺序调用生成器的方法来生成对象。应该是有较为复杂的算法和运算过程,在运算过程中根据需要,才会调用生成器的方法来生成部件对象。 3.指导者和生成器的交互
在生成器模式里面,指导者和生成器的交互是通过生成器的buildPart方法来完成的。
指导者通常会实现比较复杂的算法或者是运算过程,在实际开发中很可能会有以下的情况:
1) 在运行指导者的时候,会按照整体构建算法的步骤进行运算,可能先运行前几步运算,到了某一步骤,需要具体创建某个部件对象了,然后就调用Builder中创建相应部件的方法来创建具体的部件。同时,把前面运算得到的数据传递给Builder,因为在Builder内部实现创建和组装部件的时候,可能会需要这些数据。
2) Builder创建完具体的部件对象后,会把创建好的部件对象返回给指导者,指导者继续后续的算法运算,可能会用到已经创建好的对象。
3)如此反复下去,知道整个构建算法运行完成,那么最终的产品对象也就创建好了。 可以看出指导者和生成器是需要交互的,方式就是用过生成器方法的参数和返回值,来回地传递数据。事实上,指导者使用过委托的方式把功能交给生成器去完成。 4.返回装配好的产品的方法
标准的生成器模式中,在Builder实现里面会提供一个返回装配好的产品的方法,在Builder接口上是没有的。它考虑的是最终的对象一定要通过部件构建和装配,才算真正创建了,而具体干活的就是Builder实现,虽然指导者也参与了,但是指导者是不负责具体的部件创建和组装的,因此客户端是从Builder实现里面获取最终装配好的产品。 5.关于被构建的产品的接口
在使用生成器模式的时候,大多数情况下是不知道最终构建出来的产品是什么,所以一般不需要对产品定义抽象接口,因为最终构建的产品千差万别,给这些产品定义公共接口几乎是没有意义的。
*/ // 使用生成器模式构建复杂对象 var InsuranceContract = (function(){
// 保险合同对象
var InsuranceContract = function(builder){
this.contractId = builder.getContractId();
this.personName = builder.getPersonName();
this.companyName = builder.getCompanyName();
this.beginDate = builder.getBeginDate();
this.endDate = builder.getEndDate();
this.otherDate = builder.getOtherDate();
};
InsuranceContract.prototype = {
someOperation: function(){
console.log('Now in Insurance Contract someOperation = ' + this.contractId);
}
}; // 构造保险合同对象的构造器
var ConcreteBuilder = function(contractId, beginDate, endDate){
this.contractId = contractId;
this.beginDate = beginDate;
this.endDate = endDate;
};
ConcreteBuilder.prototype = {
setPersonName: function(personName){
this.personName = personName;
return this;
},
setCompanyName: function(companyName){
this.companyName = companyName;
return this;
},
setOtherDate: function(otherData){
this.otherData = otherData;
return this;
},
getContractId: function(){
return this.contractId;
},
getPersonName: function(){
return this.personName;
},
getCompanyName: function(){
return this.companyName;
},
getBiginDate: function(){
return this.beginDate;
},
getEndDate: function(){
return this.endDate;
},
getOtherData: function(){
return this.otherData;
}, // 构建真正的对象并返回
// 添加一些约束规则
build: function(){
if(!this.contractId || this.contractId.trim().length === 0) {
throw new Error('合同编号不能为空');
}
var signPerson = this.personName && this.personName.trim().length > 0;
var signCompany = this.companyName && this.companyName.trim().length > 0; if(signPerson && signCompany) {
throw new Error('一份合同不能同时与人和公司签订');
} if(!signPerson && !signCompany) {
throw new Error('一份合同不能没有签订对象');
} if(this.beginDate <= 0) {
throw new Error('合同必须有保险开始生效的日期');
} if(this.endDate <= 0) {
throw new Error('合同必须有保险失效的日期');
} if(this.endDate <= this.beginDate) {
throw new Error('保险失效的日期必须大于生效日期');
} return new InsuranceContract(this);
}
}; // 把构建对象和被构建对象合并
InsuranceContract.ConcreteBuilder = ConcreteBuilder; return InsuranceContract;
}()); var builder = new InsuranceContract.ConcreteBuilder('001', 123456, 6789);
var contract = builder.setPersonName('luke').setOtherData('test').build();
contract.someOperation(); /*
相关模式 1.生成器模式与工厂方法模式 这两个模式可以组合使用。
生成器模式的Builder实现中,通常需要选择具体的部件实现。一个可行的方案就是实现成为工厂方法,通过工厂方法来获取具体的部件对象,然后再进行部件的装配。 2.生成器模式与抽象工厂模式 这两个模式既相似又有区别,也可以组合使用。
区别:抽象工厂模式的主要目的是创建产品簇,这个产品簇里面的单个产品就相当于是构成一个复杂对象的部件对象,抽象工厂对象创建完成后就立即返回整个产品簇;而生成器模式的主要目的是按照构造算法,一步一步来构建一个复杂的产品对象,桐城要等到整个构建过程结束以后没才会得到最终的产品对象。
组合使用:在生成器模式的Builder实现中,需要创建各个部件对象,而这些部件对象是有关联的,通常是构成一个复杂对象的部件对象。也就是说,Builder实现中,需要获取构成一个复杂对象的产品簇,就可以使用抽象工厂模式来实现。有抽象工厂模式负责部件对象创建,Builder实现里面则主要负责产品对象整体的构建了。 3.生成器模式和模板方法模式 这也是两个非常相似的模式。
模板方法模式主要是用来定义算法的骨架,把算法中某些步骤延迟到子类中实现。生成器模式Director用来定义整体的构建算法,把算法中某些涉及到具体部件对象的创建和装配功能,委托给具体的Builder来实现。
从实质上看,都是定义一个固定的算法骨架,然后把算法中的某些具体步骤交给其他类来实现,都能实现整体算法步骤和某些具体步骤实现的分离。
区别:
1).目的:生成器模式用来构建复杂对象。模板模式用来定义算法骨架,尤其是一些复杂的业务功能的处理算法的骨架;
2)。实现:生成器模式采用委托的方法,模板模式采用继承的方法。
3)。复杂度:生成器模式需要组合Director和Builder对象,然后才能开始构建,要等构建后才能获得最终的对象,而模板方法就没这么麻烦,直接使用子类对象即可。 4.生成器模式和组合模式 可以组合使用。
对于复杂的组合结构,可以使用生成器模式来一步一步构建。
*/ // http://www.dofactory.com/javascript-builder-pattern.aspx function Shop() {
this.construct = function(builder) {
builder.step1();
builder.step2();
return builder.get();
}
} function CarBuilder() {
this.car = null;
this.step1 = function() {
this.car = new Car();
};
this.step2 = function() {
this.car.addParts();
};
this.get = function() {
return this.car;
};
} function TruckBuilder() {
this.truck = null;
this.step1 = function() {
this.truck = new Truck();
};
this.step2 = function() {
this.truck.addParts();
};
this.get = function() {
return this.truck;
};
} function Car() {
this.doors = 0;
this.addParts = function() {
this.doors = 4;
};
this.say = function() {
log.add("I am a " + this.doors + "-door car");
};
} function Truck() {
this.doors = 0;
this.addParts = function() {
this.doors = 2;
};
this.say = function() {
log.add("I am a " + this.doors + "-door truck");
};
} // log helper
var log = (function () {
var log = "";
return {
add: function (msg) { log += msg + "\n"; },
show: function () { alert(log); log = ""; }
}
})(); function run() {
var shop = new Shop(); var carBuilder = new CarBuilder();
var truckBuilder = new TruckBuilder(); var car = shop.construct(carBuilder);
var truck = shop.construct(truckBuilder); car.say();
truck.say(); log.show();
}
</script>
</body>
</html>

javascript设计模式-生成器模式(Builder)的更多相关文章

  1. C#设计模式——生成器模式(Builder Pattern)

    一.概述在软件系统中,有时候面临着复杂的对象创建,该对象由一定算法构成的子对象组成,由于需求变化,这些子对象会经常变换,但组合在一起的算法却是稳定的.生成器模式可以处理这类对象的构建,它提供了一种封装 ...

  2. 第9月第6天 push pop动画 生成器模式(BUILDER)

    1. https://github.com/MichaelHuyp/QQNews 2.生成器模式(BUILDER) class MazeBuilder { public: virtual void B ...

  3. 跟着实例学习设计模式(6)-生成器模式builder(创建型)

    生成器模式是创建型设计模式. 设计意图:将一个复杂的类表示与其构造相分离,使得同样的构建过程可以得出不同的表示. 实例类图: IVehicleBuilder:抽象建造者.为创建一个Vehicle对象并 ...

  4. 【设计模式】- 生成器模式(Builder)

    生成器模式 建造者模式.Builder 生成器模式 也叫建造者模式,可以理解成可以分步骤创建一个复杂的对象.在该模式中允许你使用相同的创建代码生成不同类型和形式的对象. 生成器的结构模式 生成器(Bu ...

  5. 设计模式十: 生成器模式(Builder Pattern)

    简介 生成器模式属于创建型模式的一种, 又叫建造者模式. 生成器模式涉及4个关键角色:产品(Product),抽象生成器(builder),具体生成器(ConcreteBuilder),指挥者(Dir ...

  6. 设计模式—建造者模式(Builder)

    title: 设计模式-建造者模式 建造者模式(Builder)是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节.建造者模式属于对 ...

  7. TypeScript实现设计模式——生成器模式

    生成器模式是一种在TypeScript/JavaScript中非常常见的创建型设计模式,它使你能够分步骤创建复杂对象.当你需要创建一个可能有许多配置选项的对象时, 该模式会特别有用. 问题 假设我们需 ...

  8. javascript 设计模式-----策略模式

    在<javascript设计模式>中,作者并没有向我们介绍策略模式,然而它却是一种在开发中十分常见的设计模式.最常见的就是当我们遇到一个复杂的表单验证的时候,常常需要编写一大段的if和el ...

  9. JavaScript设计模式 - 迭代器模式

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

随机推荐

  1. .Net之美

    第1章 C#类型基础 1.1 值类型和引用类型值类型和引用类型是以它们在计算机内存中是如何被分配的来划分的.值类型包括了结构和枚举,引用类型则包括了类. 接口. 委托等. 还有一种特殊的值类型,称为简 ...

  2. SQL Server 基础:子查询

    1.子查询的概念:子查询就是嵌套在主查询中的查询.子查询可以嵌套在主查询中所有位置,包括SELECT.FROM.WHERE.GROUP BY.HAVING.ORDER BY.2.子查询的分类:2.1按 ...

  3. 【转】 BSS段 数据段 代码段 堆栈 指针 vs 引用

    原文:http://blog.csdn.net/godspirits/article/details/2953721 BSS段 数据段 代码段 堆栈 (转+) 声明:大部分来自于维基百科,自由的百科全 ...

  4. 对java面试文章的技术漫谈的C#技术理解

    .NET人技术太菜的话,要好好学习啊,所以看到Java届的面试对话文章,不经意想用C#的知识想做一些回应(其实也没有什么了不起的). 楼下知识文章扩展一览,外加自己接触到的扩展.水太深! static ...

  5. Java 控制台执行带自定义包定义的类,出现“Exception in thread "main" java.lang.NoClassDefFoundError: ConnectSQLServer (wrong name: sine/ConnectSQLServer)”

    1.先说明一下代码实现:自定义package sine, 源代码保存路径为:E:\JSP\HibernateDemo\HibernateDemoProject\src\sine\ConnectSQLS ...

  6. Node.js中的模块化

    每天一篇文章来记录记录自己的成长吧.大二,该静心了.加油~ 好了,废话不多说,今天说说nodejs中的模块化.(注:此文为自己对书nodejs实战的总结) nodejs一个重要的特性就是模块化,模块就 ...

  7. SoundCloud 的开发功能

    SoundCloud开发功能:https://developers.soundcloud.com/docs     来自为知笔记(Wiz)

  8. JavaScript 编码风格指南

    A.1  缩进 // 4个空格的层级缩进 if (true) { doSomething(); } A.2  行的长度 // 每行限于80个字符,超出则在运算符后换行,缩进2个层级(8个空格) doS ...

  9. IBM X3650 M4安装win 2008 Server操作指南

    由于IBM服务器是IBM原有的Linux系统,所以需要在此硬件上安装Win 2008 Server系统(以下简称win8),中间遇到了很多坑,在下面的描述中会阐述.以下是安装的整个步骤: 一.所需工具 ...

  10. Linux下如何使CP命令不提示覆盖

    在Linux下使用CP命令,经常会提示是否覆盖,如果是太批量的文件覆盖,老是这么提示,会很烦的.那如何解决这个问题呢? 我们先来看一下原因吧! 一般我们使用的命令是cp -rf sourcefile ...