本篇中,来聊聊以下几个模式:
①、门面模式
②、建造者模式
③、代理模式
8、门面模式
门面模式,也称之为外观模式,门面门面,只关注外观与结果,不在意细节与过程,谓之门面。一个最最简单的门面模式就是我们最常见的桌面快捷方式,快捷方式本身并不做任何事情,但会将你引导至对应的客户端,无论做什么事,你需要的操作仅仅就是在桌面上点点点。
再比如说——建房子,你攒够了乡下一栋楼的钱,你要建房子,但房子需要打桩、浇灌水泥钢筋搭建房屋骨架、砌墙、牵水管、拉电线、装门窗、吊板刮涂。
因为你不是专业的,无论是材料上,工艺上,你不知道如何选,甚至不知道如何去联系这些水泥工,木工,电工等等,而假如此时有一个包工头过来,报给你一个总价,而这个过程中你不用再去探究各个细节,也不用一一去和各个领域的专业工匠谈价钱,而是都由包工头帮你去联系,既省心也省力,而这就是门面模式。
看一看代码,这段代码实际上只有一个用于干造房子这件事的包工头,实际的应用可能还会有医院一条龙服务的接待员,复杂鸡尾酒的调酒师等等多个应用用途的门面。
class Building {
constructor () {
this.baoGongTou();
}
// 包工头
baoGongTou () {
this.piling();
this.mainStructure();
this.wall();
this.waterPipe();
this.eletricwire();
this.windowDoors();
this.hangerPlate();
this.coated();
}
piling () {
// console.log('打桩');
this.first = '打桩';
}
mainStructure () {
// console.log('搭建主体结构');
this.second = '搭建主体结构';
}
wall () {
// console.log('砌墙');
this.third = '砌墙';
}
waterPipe () {
// console.log('牵水管');
this.fourth = '牵水管';
}
eletricwire () {
// console.log('拉电线');
this.fifth = '拉电线';
}
windowDoors () {
// console.log('装门窗');
this.sixth = '装门窗';
}
hangerPlate () {
// console.log('吊板');
this.seventh = '吊板';
}
coated () {
// console.log('刮涂');
this.eighth = '刮涂';
}
}
new Building();
门面模式的应用也很广泛,无论是作为程序统一化输出的总线或规范化访问都起着非常重要的作用。一般一个程序中,作为工具的工具包,比如说util,其实现有时候就是一个门面模式,可能你的调用是这样:UI.util.XXX方法,你会有种统一化调用与规范化输出之感。你调用到的这个util里面的某个方法,可能实际上是好几个内部方法的集合,就犹如刚刚造房子的包工头。
再来说下门面模式另一个非常常见的应用——日志系统。日志系统,是后台排错,跟踪数据流走向的重要依据,也是前端监控里必不可少的一环。日志系统的管理的思想其实就是一个门面模式,这怎么理解?后端的日志跟前端简单的一句console.XX打印至控制台有很大的不同,它实际上需要根据不同的日志级别,比如error、info、debug等等,落地到不同的日志文件中,甚至不同的日志目录中,而假如这些没有一个门面来统一化管理,这时候打印日志就不仅需要打印不同类型的日志,还需要开发知道得打印到哪里,而这些都由开发一一去在每次的日志打印代码中实现,那会非常累,代码也非常冗余。而假如此时通过门面模式将这些通用的复杂的内部落地方式一一实现,并通过暴露出不同的方法来给外部调用,这时候外部只需要传入需要打印的内容,而不必去关心到底落地到了哪,假如在某一时间需要修改目录或文件,也只需要在该方法里修改,而调用到该方法的所有操作自然而然也跟着变动,是不是方便了太多太多?
9、建造者模式
建造者,顾名思义,就是将一种种的建筑材料建造成最终的建筑,也就是说,将一个个简单的对象一步步构建出复杂的对象。这个模式其实跟工厂方法模式很像,同样是一个输入原料并最终输出一个产品的过程。但工厂方法模式关注的是整体,也就是它关注的是最终产品的整体构造,颗粒性其实比较粗糙,但建造者模式则是从简单的一个个部件一步步构建成完成产品的过程,它不仅关注每个部件甚至有时候还关注建造的顺序,建造过程中可能产生的异常等等,即使是相同的部件,但建造时的顺序不同,最终也可能产生不同的成品。
简单的联系一下应用,作为前端,JavaScript是我们最熟悉的一门语言,由于这门语言特别是在JQuery诞生之后,一个方法内部直接返回它本身这个对象(this)的缘故,可以一直不断的链式调用,简单的像split、join、replace、splice、substr、map、filter、reduce…尽管这些虽然都是非常简单的一个个的部件,但这些部件通过点啊点,你可以完成几乎你能想到的各种数据结构的转化变种。而这个链式调用的一个个方法的使用,实际上就是建造者模式一个个的建造环节,这与工厂方法模式一个个的小工厂最终合并成一个集团公司,只关注每个厂长每个时间段的结果汇报是不一样的。
比如我们这里来设计一个人,或者说建造一个Person。
// 建造者模式
class Person {
constructor () {
this.name = '';
this.age = 0;
this.tag = '';
this.skill = '';
this.interest = '';
}
base (name, age) {
this.name = name;
this.age = age;
return this;
}
tags ( tag ) {
this.tag = tag;
return this;
}
others (skill, interest) {
this.skill = skill;
this.interest = interest;
return this;
}
build () {
return {
name: this.name,
age: this.age,
tag: this.tag,
skill: this.skill,
interest: this.interest
}
}
}
new Person()
.base('dorsey', 25)
.tags('简单 执着 有爱')
.others('编程', '乒乓球 游戏')
.build();
10、代理模式
说到代理,对于我们前端来说,可能第一反应就是解决跨域,比如Nginx和node http-proxy,但这里的代理尽管思想上是一致的,但它却不局限于此。先来顺便谈谈Nginx,Nginx可以说是现在最常见的中间处理机制,用于请求转发,负载均衡,用于做高并发,高可用集群时的分发总线,当然也顺便做一些反向代理解决跨域等问题。这个过程中,作为中间媒介,也就是这个代理,尽管实际上并不处理任何的业务或逻辑,它只负责当一个转接员,但它的重要性不言而喻。
代理模式正如其名,代理,在你完成你想要完成的事时,你不一定亲力亲为,而是部分跑腿的工作交给代理,这个代理可以是海外代购,可以是物业,也可以是中介,甚至还可以是淘宝或京东。代理层后续的各个逻辑,实际上犹如嗷嗷待哺的小猪,张着嘴等待代理将原料送到嘴边,并最终将这些原料转化成猪肉,猪排骨等等营养丰富的食物或产品,而这个过程中,代理实际上也可以做一些与逻辑上无关的事情,比如响应超时处理,隐藏真实IP保护客户,缓存,格式校验,白名单等等。
说到代理proxy这个英文单词,怎么感觉有种隐隐约约的熟悉?你的感觉没有错,那就是Vue3.0中采用的ES6+新特性——Proxy机制。Vue3.0中在重写对象getter和setter方法时采用了新的机制Proxy来替换之前对象属性定义Object.defineProperty,而这个Proxy机制的英文翻译其实就是代理,这不禁让我们联系,到底跟代理模式有没有联系?
答案是肯定的,而且Proxy就是代理模式的一种体现,其实就是通过一个中间代理实例来代理原对象,并通过修改中间代理实例来修改原对象,其实这个也很好理解,对象,数组等等非值类型的数据,实际上它并没有重新开辟一块新的内存空间并分配新的指针,所以操作了其中一个引用,其他地方的引用自然而然也跟着变动,而代理模式当然是通过非深拷贝的方式复制出来的。可以看看Proxy的一个简单应用。
let obj = {
a : 520
}
let proxy = new Proxy(obj, {
get(target, prop) {
console.log('get 即“读”的方法被触发了');
return prop in target ? target[prop] : 0
},
set(target,prop,value) {
console.log('set 即“写”的方法被触发了');
target[prop] = value;
return true;
}
})
console.log(proxy.a); // get 即“读”的方法被触发了 520
console.log(proxy.b); // get 即“读”的方法被触发了 0
proxy.a = 1314; // set 即“写”的方法被触发了
console.log(proxy.a) // get 即“读”的方法被触发了 1314
console.log(obj); // obj里的值a被彻彻底底改变了。 {a: 1314}