建造者模式(Builder):将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示。
工厂模式主要是为了创建对象实例或者类簇(抽象工厂),关心的是最终产出(创建)的是什么。不关心创建的整个过程,仅仅需要知道创建的最终结果。所以通过工厂模式我们得到的都是对象实例或者类簇。然而建造者模式在创建对象时要更为复杂一些,虽然其目的也是为了创建对象,但是它更多关心的是创建这个对象的过程,甚至于创建对象的每一个细节,比如创建一个求职者,我们创建的结果不仅仅是要得到求职者的实例,还要关注创建求职者过程中,他所期望的职位是什么,手机号保密不保密,专业技能是什么,兴趣爱好有哪些,等等。所以说建造者模式更注重的是创建的细节。
模式讲解
- 指挥者(Director)直接和客户(Client)进行需求沟通
- 沟通后指挥者将客户创建产品的需求划分为各个部件的建造请求(Builder)
- 将各个部件的建造请求委派到具体的建造者(ConcreteBuilder)
- 各个具体建造者负责进行产品部件的构建
- 最终构建成具体产品(Product)
有一天,我们运营的公众号积累了很多粉丝,拥有了巨大的流量,会有很多商业合作,当然也会有很多求职者来找我们帮助发布简历。但是这些简历有一个要求,除了可以将他们的兴趣爱好以及一些特长发布在页面里,其他信息,如联系方式和年龄不能随便发布在公众号上。要让招聘公司来找我们,不过话又说回来,他们想找的工作是可以分类的,比如对于写代码的人来说他们要找的职位就是工程师,修图做图的找的职位是设计师,当然这里可能还有一些关于工作职位的描述。
// 创建求职人员类
var People = function (info) {
this.age = (info && info.age) || "保密";
this.phone = (info && info.phone) || "保密";
};
// 求职人员类原型方法
People.prototype = {
getAge: function () {
return this.age;
},
getPhone: function () {
return this.phone;
},
};
// 解析姓名
var Name = function (name) {
var _this = this;
(function (name, that) {
that.fullName = name;
if (name.indexOf(" ") > -1) {
that.firstName = name.slice(0, name.indexOf(" "));
that.lastName = name.slice(name.indexOf(" ") + 1);
}
})(name, _this);
};
// 职位类
var Work = function (job) {
var _this = this;
(function (job, that) {
switch (job) {
case "code":
that.job = "程序员";
that.jobDescription = "沉醉于代码无法自拔";
break;
case "UI":
case "UE":
that.job = "设计师";
that.jobDescription = "沉醉于艺术无法自拔";
break;
case "teacher":
that.job = "教师";
that.jobDescription = "沉醉于教学无法自拔";
break;
default:
that.job = job;
that.jobDescription = "暂时没有您选择职位的相关描述";
}
})(job, _this);
};
Work.prototype.changeJob = function (job) {
this.job = job;
};
Work.prototype.changeJd = function (description) {
this.jobDescription = description;
};
/**
* 求职者建造者(类)
* @param {string} name
* @param {string} job
*/
var Employees = function (name, job) {
// 创建求职用户缓存对象
var employee = new People();
// 创建姓名解析对象
employee.name = new Name(name);
// 创建职位对象
employee.job = new Work(job);
return employee;
};
// 创建一个求职应聘者
var employee = new Employees("li ming", "code");
console.log(employee.phone); // 保密
console.log(employee.getAge()); // 保密
console.log(employee.name.lastName); // ming
console.log(employee.job.job); // 程序员
console.log(employee.job.jobDescription); // 沉醉于代码无法自拔
employee.job.changeJd("编程让世界更美好");
console.log(employee.job.jobDescription); // 编程让世界更美好
使用 ES6S 实现
class People {
constructor(age, phone) {
this.age = age || "保密";
this.phone = phone || "保密";
}
// 解析姓名
createName(name) {
if (name.indexOf(" ") > -1) {
this.firstName = name.slice(0, name.indexOf(" "));
this.lastName = name.slice(name.indexOf(" ") + 1);
}
return this;
}
// 求职职位
judgeWork(job) {
switch (job) {
case "code":
this.job = "程序员";
this.jobDescription = "沉醉于代码无法自拔";
break;
case "UI":
case "UE":
this.job = "设计师";
this.jobDescription = "沉醉于艺术无法自拔";
break;
case "teacher":
this.job = "教师";
this.jobDescription = "沉醉于教学无法自拔";
break;
default:
this.job = job;
this.jobDescription = "暂时没有您选择职位的相关描述";
}
return this;
}
}
const employee = new People(21).createName("xiao ming").judgeWork("code");
console.log(employee);
// People {
// age: 21,
// phone: '保密',
// firstName: 'xiao',
// lastName: 'ming',
// job: '程序员',
// jobDescription: '沉醉于代码无法自拔'
// }
优缺点
优点:
- 使用建造者模式可以使产品的创建和产品的表现分离,也就是将产品的创建算法和产品组成的实现隔离,访问者不必知道产品内部实现细节。
- 扩展方便,如果希望生产一个装配方式不同的新产品,直接新建一个指挥者即可,不用修改既有代码,符合开闭原则。
- 更好的复用性,建造者模式将产品的创建算法和产品组成的实现分离,所以产品创建的算法可以复用,产品部件的实现也可以复用,带来很大的灵活性。
缺点:
- 建造者模式一般适用于产品之间组成部件类似的情况,如果产品之间差异性很大、复用性不高,那么不要使用建造者模式。
- 实例的创建增加了许多额外的结构,无疑增加了许多复杂度,如果对象粒度不大,那么我们最好直接创建对象。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。