软件设计-JS设计模式_第1页
软件设计-JS设计模式_第2页
软件设计-JS设计模式_第3页
软件设计-JS设计模式_第4页
软件设计-JS设计模式_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

JS设计模式

设计模式是对软件设计中普遍存在(反复出现)的各种问题,所

提出的解决方案。设计模式并不直接用来完成代码的编写,而是描述

在各种不同情况下,要怎么解决问题的一种方案。

1.设计模式是被反复验证的解决方案(最佳实践),可以减少代

码强耦合、硬编码,有效的提高代码的可扩展性和可维护性

2.设计模式是一种通用方案和思维,它不限制于特定编程语言

3.提供一种通用术语,方便交流,减少沟通中的理解成本。

设计模式的原则

做什么事都需要遵循一些准则,设计模式也不例外。我们在设计一些

设计模式时,一般遵循如下6项基本原则,它们分别是:

Single-responsibilityprinciple(单一职责原贝!J)

每个软件模块都有且只有一个需要被改变的理由。

单一职责能够降低模块的复杂度,减少功能变更引起的关联风险,提

高代码可读性和可维护性。

Open-closedprinciple(开放封,闭原则)

系统应该对扩展开放,对修改关闭。

如果软件系统想要更容易被改变,那么其设计就必须允许新增代码来

修改系统行为,而不是只能靠修改原来的代码。

Liskovsubstitutionprinciple(里斯科夫替代原则)

一个子类应该可以替换掉父类并且可以正常工作

Interfacesegregationprinciple(接口隔离原贝!J)

一个类对另一个类的依赖应该建立在最小的接口上。

主要告诫软件设计师应该在设计中避免不必要的依赖。

Dependencyinversionprinciple(依赖反转原贝!J)

高层策略性的代码不应该依赖实现底层细节的代码,相反,底层细节

代码应该依赖高层策略性的代码。

LawofDemeter(迪米特法则)

减少模块间的依赖。只有使各个模块之间的耦合尽量的低,才能提高

代码的复用率。

【创建型】

模块模式

模块模式是在传统软件工程中为类提供私有和公有封装的方法。

通过这种方式,让一个对象拥有私有和公有的方法/变量,有效控制

对外暴露的api接口,屏蔽底层处理逻辑,但是由于js曾经没有访

问修饰符,从技术的角度来说,我们不能称js变量为私有和公有。

所以我们需要使用IIFE(即时调用函数表达式)、闭包和函数作用

域的方式来实现js的模块模式。

varobj=(function(){

varcount=0;

return{

addCount:function(){count++},

getCount:function(){returncount}

})()

IIFE使得obj会获得function中返回的对象,同时只有对象中的函

数可以闭包访问到内部的count变量,达到私有的目的。

最终外部采用调用模块的公有属性/方法来访问和操作私有变量

obj.addCount()//1

obj.getCount()//1

obj.count//undefined

・应用场景:

o需要管理大量私有变量/方法,希望屏蔽内部处理逻辑,

只对外暴露接口的独立模块

・优点:

o采用封装的思想,只有本模块才能享有私有变量,不会暴

露于外部模块

。减少对全局作用域的影响,避免命名空间污染;

O模块化有助于保持代码的整洁、隔离和条理性。

・缺点:

O无法访问方法调用后产生的私有变量

揭示模块模式

某位同学(ChristianHeilmann)不满模块模式中必须创建新的公

共函数来调用私有函数和变量,所以略微改进了模块模式为揭示模块

模式:在本模块的私有作用域范围内定义所有的方法和变量,将把

返回对象的属性映射到我们想要公开的私有函数。

varobj=(function(){

varcount=0;

functionaddCount(){count++}

functiongetCount(){returncount)

return{

addCount:addCount,

getCount:getCount

})0

于模块模式相比

•优点:

O方法从private改为public非常简单,只需要改属性映

O返回的对象不包含任何函数定义,公开的函数和变量一目

了然,有助于提高代码的可读性

・缺点:

o导致私有函数升级困难。如果一个私有函数引用一个公有

函数,在需要打补丁时,公有函数是不能被覆盖的。eg:

functionrmpUrIBuiIder(){

varurlBase=〃http://my.default,domain/”;

var_build=function(relUrl){

returnurlBase+relUrl;

return{

urlBase:_urlBase,

build:build}

)

varbuilder=newrmpUrIBuiIder();

builder.urlBase=/zhttp://stackoverflow,com”;

console.log(builder.build('/questions");

//打印结果是"http://my.default,domain/questions”

//而不是//http://stackoverflow,com/questions^

单例模式

单例模式限制某个类只能被创建一次,并且需要提供一个全局的访问

点。如果一个类的实例不存在,单例模式就会创建一个新的类实例。

如果实例存在,它只返回对该对象的引用。对构造函数的任何重复调

用都会获取相同的对象。

js中单例模式可以使用构造函数实现,例如:

letinstance=nulljfunctionUser(){

if(instance){

returninstance;

instance=this;

this,name='Peter';

this,age=25;

returninstance;

)

constuserl=newUser();

constuser2=newUser();

console,log(userl===user2);

//打印true

当调用这个构造函数时,它会检查实例对象是否存在。如果对象不存

在,它就将这个变量赋给实例变量。如果对象存在,它只返回那个对

象。

单例也可以使用模块模式实现,例如:

constsingleton=(function(){

letinstance;

functioninit(){

return(

name:'Peter',

age:24,};

return{

getlnstance:function(){

if(!instance){

instance=init();

returninstance;

)|

})0;

constinstanceA=singleton,getlnstance();

constinstanceB=singleton,getlnstance();

console.log(instanceA===instanceB);//打印true

在上面的代码中,我们通过调用singleton,getlnstance方法来创

建一个新实例。如果实例已经存在,则该方法只是返回这个实例,如

果实例不存在,则调用initO函数创建一个新的实例。

小结

・应用场景:

O应用中有对象需要是全局的且唯一。比如页面全局蒙层。

・优点:

o适用于单一对象,只生成一个对象实例,避免频繁创建和

销毁实例,减少内存占用。

・缺点:

O不适用动态扩展对象,或需创建多个相似对象的场景

简单工厂模式

简单工厂模式是一种创建型模式,它不需要指定所创建对象的确

切类或构造函数。由工厂对象提供对外提供通用的工厂方法,然后根

据我们的特定需求/条件,生成不同的对象,在创建对象的过程中不

用公开实例化的逻辑。

举例:在系统通知中我们会发送多种类型的消息,如邮件、微信、

短信、电话等。我们在创建不同消息的时候,可以采用工厂模式。通

过传入的参数不同,输出不同的消息对象。

classEmail{

constructor(options){

this,message=options,message||'我是emial信息';

this,type=options,type||'email',

this.sender=options,user;

this.receiver=options.receiver;

this.sendTime=options.sendTime|newDate()

Ml

I

classWeixin{

constructor(options){

this,msg=options,messageII'我是微信信息';

this,type=options,type||'weixin',

this.sender=options,user;

this.receiver=options,receiver;

classMessageFactory{

create(options){

switch(option,type){

case'emaiT:

returnnewEmail(options);

case'weixin':

returnnewWeixin(options);

default:

returnnull;

Ml

)

在这里我创建了一"1、Email类和一个Weixin类(带有一些默认

值),用于创建新的Email和Weixin对象。我还定义了一个

MessageFactory类,基于options对象中接收到的type属性创建

和返回一个新的对象。

constfactory=newMessageFactory();

constemailMsg=factory,create({

type:'email',

message:'你好,有兴趣了解下安利吗’,

user:'xiaojia',

receiver:'xxl',

});

constweixinMsg=factory,create({

type:'weixin',

message:‘im卖保险',

user:'xiaojia',

receiver:'xx2',

});

我已经创建了一个新的MessageFactory类的对象工厂。之后,我们

可以调用factory,create方法,传入一个type属性值为email

或weixin的options,来创建不同的消息对象。

・应用场景:

o需要处理共享多个相同属性的小型对象/组件

。可以根据不同的环境/参数生成对象的不同实例

o对象的类型已知、有限

・优点:

O能解决创建多个相似对象的问题。

・缺点:

O违背了开放封闭原则。每增加一个产品,都需要修改工厂

类的代码

o对象的类型不知道

工厂模式

在简单工厂模式中,一个工厂类负责所有产品对象的创建,这个

工厂类的职责大大增加,可能客户端对于某些产品的创建方式会有不

同的要求,这样的话,就要不断的修改工厂类,增加相应的判断逻辑,

不利于后期的代码维护。所以我们将简单工厂模式进一步抽象化,实

现工厂模式:让工厂子类去实现抽象工厂类的接口,由每个具体的工

厂类负责创建单独的产品,如果有新的产品加进来,只需要增加一个

具体的创建产品工厂类和具体的产品类就可以了,不会影响到已有的

其他代码,代码量也不会变大,后期维护更加容易,增加了系统的可

扩展性。

我们基于上述MessageFactory的代码进行修改

classMessageFactory{

create(options){

thrownewErrorC需要create方法’)

I

classEmaiIMsgFactoryextendsMessageFactory{

create(options){

returnnewEmail(options)

HH

)

・应用场景:

o需要处理多个复杂产品对象

。不同的工厂和产品可以提供客户端不同的服务或功能

o产品对象的类型会动态增加

・优点:

O克服了简单工厂违背开放-封闭原则的缺点,后期维护更

加容易。

・缺点:

o每增加一个产品,相应的也要增加一个子工厂,加大了额

外的开发量

原型模式

原型模式主要是用于创建重复的对象。通俗点讲就是创建一个共享的

原型,并通过拷贝这些原型创建新的对象。

js中可以通过Object,create来实现

varmyCar={

name:"FordEscort”,

drive:function(){

console,log("Weeee.I'mdriving!,z);

I^H

panic:function(){

console.logC^Wait.Howdoyoustopthisthing?");

HH

);

//UseObject,createtoinstantiateanewcar

varyourCar=Object,create(myCar);

//Nowwecanseethatoneisaprototypeoftheother

console.log(yourCar.name);

・应用场景:

o需要大量复制已存在的对象,对象间又相互独立

・优点:

o/实现功能吧,没想出什么优点

・缺点:

【结构型】

代理模式

代理模式的核心是为对象提供一个代理对象,来控制对目标对象的访

问,客户其实访问的是这个代理对象。这样代理对象就可以对请求做

出一些处理之后,再将请求转交给本体对象。

代理模式中常见的有保护代理、虚拟代理、缓存代理。

保护代理主要是限制了访问主体的行为。下面以过滤消息中的敏感信

息作为简单的例子

//主体,发送消息functionsendMsg(msg){

console,log(msg);

|

//代理,对消息进行过滤functionproxySendMsg(msg){

//无消息则直接返回

if(typeofmsg==='undefined'){

console.log(,deny,);

return;

//有消息则进行过滤

msg=(''+msg).replace(/敏感信息/g,'****');

sendMsg(msg);

sendMsg('敏感信息');〃敏感信息

proxySendMsgC敏感信息');//****

proxySendMsgO;//deny

虚拟代理主要是在访问行为中加入一些额外操作,最常见的例子有函

数防抖。我们的目的是去触发fn,但是debounce函数会对清除老的

timer,并且将fn放到新的timer中。

//函数防抖,频繁操作中不处理,直到操作完成之后(再过delay的

时间)才处理functiondebounce(fn,delay){

delay=delay||200;

vartimer=null;

returnfunction(){

vararg=arguments;

//每次操作时,清除上次的定时器

clearTimeout(timer);

timer=null;

//定义新的定时器,一段时间后进行操作

timer=setTimeout(function(){

fn.apply(this,arg);

delay);

IH

};

另外,ES6所提供Proxy构造函数也能够让我们轻松的使用代理模式。

・应用场景:

O访问对象比较复杂,并且需要对访问行为进行控制

・优点:

O依托代理,可额外添加扩展功能,而不修改本体对象,符

合”开发-封闭原则”

O对象职能粒度细分,函数功能复杂度降低

・缺点:

O额外代理对象的创建,增加部分内存开销

o处理请求速度可能有差别,非直接访问存在开销

适配器模式

在生活中我们常常会用到电源适配器、Type-C转接头,这些器件

都是为了不同的设备能够兼容协作。

适配器模式的目的也是这样:将一个对象的接口(方法或属性)

转化成客户希望的另外一个接口(方法或属性),使得原本由于接口

不兼容而不能一起工作的那些对象可以正常协作。

工作中最常见的就是各种数据格式的转换,以传递给不同的插件

方法。

functiondataConvenrt(data){

//dosomething

returndealData

)

适配器模式也非常适用于跨浏览器兼容,例如强大的jQuery封

装了事件处理的适配器,解决跨浏览器兼容性问题,极大简化我们日

常编程操作。

functionon(target,event,callback){

if(target.addEventListener){

//标准事件监听

target.addEventListener(event,callback);

}elseif(target.attachEvent){

//IE低版本事件监听

target.attachEvent(event,callback)

}else{

//低版本浏览器事件监听

target['on${

event

}']=callback

)

,与代理模式的差异:

O两者都会在访问原始对象前对请求数据进行处理。但是适

配器的目的是为了兼容不同对象的接口/属性,而代理模

式是为了控制访问行为。

・应用场景:

o需要兼容不同对象的接口。比如跨浏览器兼容、整合第三

方SDK、新老接口兼容

・优点:

。兼容性好,保证外部可统一接口调用

・缺点:

O额外对象的创建,非直接调用,存在一定的开销(且不像

代理模式在某些功能点上可实现性能优化)。

装饰器模式

我们在打游戏时,游戏角色会带上各种buff、debuffo这种属性并

不是继承而来,而是游戏过程中动态增加的。这种场景就非常适合装

饰器模式。

装饰器模式可以动态地给对象添加一些新功能。它是一种“即用即付”

的方式,能够在不改变对象自身的基础上,在程序运行期间给对象动

态地添加职责。

JS中最简单的装饰器就是重写对象的属性

varA={

score:10

);

A.score='分数:'+A.score;

也可以通过构造函数和原型的方式来实现装饰器,并且经过多重包装

可以形成一条装饰链

functionPerson(){}

Person,prototype,skill=function(){

console.logC(数学');

);

//装饰器,还会音乐functionMusicDecorator(person){

this,person=person;

I

MusicDecorator.prototype,skill=function(){

this,person,skill();

console.log('音乐’);

};

//装饰器,还会跑步functionRunDecorator(person){

this.person=person;

|

RunDecorator.prototype,skill=function(){

this,person,skill();

console,log('跑步');

);

varperson=newPerson();

//装饰一下

varpersonl=newMusicDecorator(person);

//再装饰一下

personl=newRunDecorator(personl);

person,skill();//数学

personl.skill();//数学音乐跑步

最新的ECMA中有装饰器(Decorator)的提案,它是一种与类(class)

相关的语法,用来注释或修改类和类方法。有兴趣的同学可以看下阮

一峰的介绍

・应用场景:动态地给对象添加一些新功能,并且不改变对象本

身。

・优点:同上

・缺点:/

组合模式

组合模式是为了解决大型/复杂对象的结构问题,用小的子对象来

构建更大的对象,而这些小的子对象本身也许是由更小的“孙对象”

构成的。

这种组合有具有一定的要求和条件:1.对象可以用树形结构来表

示;2.根对象和叶对象属于同一类,需要具有相同的接口。

最常见的例子有递归扫描文件夹中的文件

//文件夹组合对象functionFolder(name){

this,name=name;

this,parent=null;

this,files=口;

|

Folder,prototype={

constructor:Folder,

add:function(file){

file,parent=this;

this,files,push(file);

returnthis;

),

scan:function(){

//委托给叶对象处理

for(vari=0;i<this,files,length;++i){

this.files[i].scan();

HI

remove:function(file){

if(typeoffile===,undefined(){

this,files=[];

return;

for(vari=0;i<this,files.length;++i){

if(this,files[i]===file){

this,files.splice(i,1);

};

//文件叶对象functionFile(name){

this,name=name;

this,parent=null;

Ftotype={

constructor:File,

add:function(){

console.log(,文件里面不能添加文件’);

I^H

scan:function(){

varname=[];

varparent=this,parent;

while(parent){

name,unshift(parent,name);

parent=parent,parent;

console,log(name.join(,/'));

);

我们在构造组合对象和叶对象后进行实例化,插入数据

varweb=newFolder('Web');

varfe=newFolder('前端');

varcss=newFolder('CSS');

varjs=newFolder('js');

varrd=newFolder('后端');

web.add(fe).add(rd);

varfilel=newFile('HTML权威指南.pdf');

varfile2=newFile('CSS权威指南.pdf');

varfile3=newFile('JavaScript权威指南.pdf');

varfile4=newFile('MySQL基础.pdf');

varfile5=newFile('Web安全.pdf');

varfile6=newFile('Linux菜鸟.pdf');

css.add(file2);

fe.add(filel).add(file3).add(css).add(js);

rd.add(file4).add(file5);

web.add(file6);

rd.remove(file4);

//扫描

web.scan();

//结果

//Web/前端/HTML权威指南.pdf

//Web/前端/JavaScript权威指南.pdf

//Web/前端/CSS/CSS权威指南.pdf

//Web/后端/Web安全.pdf

//Web/Linux菜鸟.pdf

・应用场景:

O可以组合成树形结构的复杂对象,并且需要对外提供一致

性的操作接口。

O优化处理递归或分级数据结构

・优点:

。忽略组合对象和单个对象的差别,对外一致接口使用;

O解耦调用者与复杂元素之间的联系,处理方式变得简单。

・缺点

O树叶对象接口一致,无法区分,只有在运行时方可辨别;

外观模式

外观模式是一种非常简单而又无处不在的模式。外观模式对外提

供一个统一高层的方法,来访问子系统中的一群接口,能够隐藏其底

层的复杂性。

通俗点来解释这个模式:今天瑞瑞准备叫外卖。单点是一种方式,

但面对各种单品也是无从下手,这时瑞瑞就会选择看套餐,因为这个

是已经搭配好的,并且没有选择纠结。这个套餐就是我们的外观模式

雏型,把一些细碎的东西收起来,统一对外开放。

举个

fcuntiontosllpload(){

//先获取上传token

//执行上传

//上传后将附件数据发送给业务后台服务

•优点:

O简化接口,易于使用

O使用者与底层代码解耦

.缺点:

O隐藏底层逻辑,不易调试

O子系统需要能够提供稳定服务

・和组合模式的差别:外观模式内部需要知道具体哪几个对象,

组合模式是取全量叶节点

・和中介模式的差别:外观模式处理的是类之间的复杂依赖关系,

中介模式处理的是对象之间复杂的通信机制

【行为型】

观察者模式

观察者模式是一种行为型模式,关注的是对象之间的通讯,观察者模

式就是观察者和被观察者之间的通讯,主要用于一个对象(目标)去

维持多个依赖于它的对象(观察者),将相关变更的事件自动通知给

他们的场景。

functionSubject(){this.observerList=[]//初始化观察者

队列}functionObserver(){this,update=

function(ctx){//dosomethingwihtctx}}//增加

观察者Subject,prototype.addObserver=

function(observer){this.observerList.push(observer)}//

通知观察者Subject,prototype,notify=

function(ctx){this.observerList.forEach(observer=>{

observer.update(ctx)})}

・应用场景:

o对一个对象状态的更新,需要其他对象同步更新,而且其

他对象的数量动态可变。

O对象仅需要将自己的更新通知给其他对象而不需要知道

其他对象的细节。

。比如采购中,寻源结果审批通过后,会要通知相关采购负

责人、自动创建合同信息等后续操作。

・优点:

O观察者模式在被观察者和观察者之间建立一个抽象的耦

合。被观察者角色所知道的只是一个具体观察者列表,每

一个具体观察者都符合一个抽象观察者的接口。

O观察者模式支持广播通讯。被观察者会向所有的登记过的

观察者发出通知,

・缺点:

O如果一个被观察者对象有很多的直接和间接的观察者的

话,同步通知花费时间会很长。

。如果在被观察者之间有循环依赖的话,被观察者会触发它

们之间进行循环调用,导致系统崩溃。

发布订阅模式

其实24种基本的设计模式中并没有发布订阅模式,他只是观察者

模式的一个别称。但是经过时间的沉淀,似乎他已经强大了起来,已

经独立于观察者模式,成为另外一种不同的设计模式。

在现在的发布订阅模式中,称为发布者的消息发送者不会将消息

直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在

发布者和订阅者之间存在第三个组件,称为调度中心或事件通道,它

维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相

应地分发它们给订阅者。

举一个例子,你在微博上关注了A,同时其他很多人也关注了A,

那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发

布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往

来的,全是通过微博来协调的(你的关注,A的发布动态)。

我们每个人在编程的时候都用过发布订阅模式,比如DOM事件绑定

addEventListener^vue数据双向绑定。

考虑到面试经常问到,我就不写demo代码了。。

优点:

O相较于观察者模式,发布/订阅发布者和订阅者的耦合性

更低

O事件通知分发是异步的

・缺点:

O发布者不知道所有订阅者是否成功收到通知

・和观察者模式的区别:

O在观察者模式中直接通信。然而在发布订阅模式中只有

通过消息代理进行通信。

O发布/订阅模式相比于观察者模式多了一个中间媒介,因

为这个中间媒介,发布者和订阅者的关联更为松耦合

O观察者模式大多数时候是同步的,比如当事件触发,

Subject就会去调用观察者的方法。而发布-订阅模式大

多数时候是异步的。

策略模式

策略模式的意义是定义一系列的算法,把它们一个个封装起来,

并且使它们可相互替换。具体实现是由多个策略类实现具体算法,然

后由一个环境类来通过请求参数决定使用哪些策略。

策略模式利用组合、委托等方法,可以有效避免多个if条件语句。

适合用于组合一系列算法,或者组合一系列相同目的的业务规则。

举个业务场景,我们如果要根据不同销售等级来计算工资,可能

会写出这么僵硬的代码:

varcalculateBouns=function(salary,level){

if(level==='A'){

returnsalary*4;

if(level==='B'){

returnsalary*3;

if(level==='C'){

returnsalary*2;

)

};

//调用如下:

console.log(calculateBouns(4000,'A());//16000

console,log(calculateBouns(2500,'B'));//7500

这段代码包含多个if-else,并且也缺乏弹性。如果还来个D等

级,或者A等级的计算规则需要改变,那么就需要在calculateBouns

方法中去修改,违背了开-闭原则。

我们基于策略模式重构一下。现在我们将具体策略封装起来,可

以看到代码职责更新分明,代码变得更加清晰。并且代码的可拓展性

更强,增加/修改策略,只需要在策略集合。bj中去维护.

varobj={

"A":function(salary){

returnsalary*4;

“B〃:function(salary){

returnsalary*3;

“C〃:function(salary){

returnsalary*2;

IH

);

varcalculateBouns=function(level,salary){

returnobj[level](salary);

E

console,log(calculateBouns,10000));//40000

策略模式也常用于表单验证,定义不同的规则校验方法,调用验证的

时候只需要传入规则名即可。

・应用场景:

O调用方依赖1个或多个策略

O业务场景有多种条件处理方案

・优点:

O减少if-else,代码更整洁直观

O提供开放-封闭原则,代码更容易理解和扩展

・缺点:

O策略集合通常会比较多,需要事先了解定义好所有的情况

。使用方必须理解不同策略的区别

模板模式

模板模式为了解决不同对象的相同行为的场景,它由两部分组成:

抽象父类+具体的实现子类。抽象父类定义抽象方法和具体运行策

略,来制定子类方法的运行顺序和机制;具体子类来重写父类的抽象

方法,实现不同的处理逻辑。

举个业务场景例子:在头条面试的流程是:笔试-技术面-leader

面-hr面。百度的面试流程也是这样。那我们就可以用模板模式,创

建一个抽象的面试类,在面试类中定义面试的流程,然后由头条面试

/百度面试对象继承和重写具体的面试步骤内容,比如说头条笔试是

考算法、百度笔试是考css。并且可以通过钩子函数来解决是否需要

某些运行步骤。

定义面试抽象类,init为具体子类方法运行策略,其他方法是抽

象方法。

//面试functionInterview(companyName){

this.companyName=companyName

|

Interview,prototype={

constructor:Interview,

//模板,按顺序执行

init:function(){

this.writtenTest();

this.techTest();

this.leaderTest();

if(this.needHrTest()){//钩子函数

this.hrTest();

//笔试

writtenTest:function(){

■thrownewError('必须传递writtenTest方法');

//面试

techTest:function(){

■thrownewError('必须传递techTest方法');

//leader面

leaderTest:function(){

■thrownewError('必须传递leaderTest方法');

//是否需要hr面

needHrTest:function(){

Ireturntrue

//hr面

hrTest:function(){

thrownewError('必须传递hrTest方法');

};

子类实现具体抽象方法,并调用init方法执行面试行为。

varTouTiaoInterview=function(){};

TouTiaoInterview.prototype=newInterview();

//子类重写方法实现自己的业务逻辑

TouTiaoInterview.prototype.writtenTest=function(){

console,log(〃先来个红黑树〃);

I

TouTiaoInterview.prototype.techTest=function(){

console,log(〃你对什么比较了解“);

)

TouTiaoInterview.prototype.leaderTest=function(){

console,log("leader谈笑风生“);

|

TouTiaoInterview.prototype.hrTest=function(){

console,log(〃人力资源太不给力了,我等的花儿都谢了!!〃);

|

varTouTiaoInterview=newTouTiaoInterview();

TouTiaoInterview.init();

・应用场景:

O在多个子类拥有相同的方法,并且这些方法逻辑相同时

O在程序的主框架相同,细节不同的场合下

・优点:

O利用模板模式可以将相同处理逻辑的代码放到抽象父类

中,提高了代码的复用性。

O将不同的逻辑放到不同的子类中,通过子类的扩展增加新

的行为,提高了代码的扩展性。

・缺点:

O类数量增加间接增加了系统的复杂性

O因为继承关系的自身缺点,如果父类添加一个新的抽象方

法,所有子类都要实现一遍。

状态模式

对象的状态会影响对象的行为,并且行为中伴随着状态的改变时,

就非常适合状态模式。把事物的每种状态都封装成单独的类,跟此种

状态有关的行为都被封装在这个类的内部

我们每天也都处于状态模式下:工作=>睡觉=>工作=>睡觉。那我

们可以定一个person对象和work、sleep两种状态

functionPerson(name){

this,name=namethis,currentstate=null;

//状态

this.workState=newWorkState(this)this.sleepState=new

SleepState(this)

this,init()

|

Person,prototype,init=function(){

this,currentstate=this.workState;//设置初始状态

this,currentstate,behaviour0;//开始初始状态的行为

E

Person,prototype.setState=function(state){

this,currentstate=state;

this,currentstate,behaviour();

|

//工作状态functionWorkState(person){

this,person=person

I

WorkState.prototype,behaviour=function(){

console.log(this.person,name+'上班摸鱼了8小时')

//触发[睡觉]状态

setTimeout(()=>{

this,person.setState(this,person.sleepState);

},

2*1000);

|

//睡觉状态functionSleepState(person){

this,person=person

|

SleepStotype,behaviour=function(){

console.log(this.person,name+'睡了了14小时')

//触发[睡觉]状态

setTimeout(()=>{

this,person.setState(this,person.workState);

I^H

2*1000);

varperson=newPerson('老王')

・应用场景:

o对象和外部互动时,会改变内部状态,并且不同的状态会

发生不同的行为

o在运行过程中这个对象的状态会经常切换

・优点

O一个状态状态对应行为,封装在一个类里,更直观清晰,

增改方便

O状态与状态间,行为与行为间彼此独立互不干扰

。避免事物对象本身不断膨胀,条件判断语句过多

•缺点:

O需要将事物的不同状态以及对应的行为拆分出来,有时候

会无法避免动作拆不明白了,过度设计

O与策略模式的不同:状态模式经常会在处理请求的过程中

更改上下文的状态,而策略模式只是按照不同的算法处理

算法逻辑

中介者模式

程序中存在对象,所有这些对象都按照某种关系和规则来通信。

当程序的规模增大,对象会越来越多,它们之间的关系也越来越复杂,

难免会形成网状的交叉引用。当改变或删除其中一个对象的时候,很

可能需要通知所有引用到它的对象。这样的硬编码方式会导致代码和

对象的逻辑关系难以维护。

□中介者对象可以让各个对象之间不需要显示的相互引用,从而使

其耦合松散,而且可以独立的改变它们之间的交互。所有的相关对象

都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改

变时,只需要通知中介者对象即可

「采购部就是一个典型的中介者模式。业务部门A找采购部提采购

需求,由采购部去发布公告召集B、C、D

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论