js设计模式有很多种,知道不代表会用,更不代表理解,为了更好的理解每个设计模式,对每个设计模式进行总结,以后只要看到总结,就能知道该设计模式的作用,以及模式存在的优缺点,使用范围。
本文主要参考张容铭著的《JavaScript设计模式》。
1、简单工厂模式
由一个工厂对象决定创建某一种产品对象类的实例,主要用来创建同一类对象。
举例子:1、比如不同的弹出框,有警告框,提示框,确认框等。我们创建一个大类包含包含其共有的部分,比如显示,内容等,再根据创建是选择的类型,再将差异部分添加进去。
2、体育店里面有很多商品,及相关介绍,我们要买的时候,只要体育店有,就会得到相关产品和信息。先创建不同产品的基类,然后再用一个大类(也就是所谓的工厂)来包容这些基类。可用switch来选择确定要创建什么。
总结:第一种是通过创建一个新对象然后包装增强其属性和功能实现的。第二种是通过类的实例化实现的。前一种因为共享父类,所以父类的方法方法属性是可以共用的,后者就不行了。简单工厂模式使用场合通常也限制在创建单一对象。
2、工厂方法模式
工厂方法模式:通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例。将实际创对象工作推迟到子类中,这样核心类就成了抽象类。
其中涉及到一个安全模式类:
var demo = function(){ if(!(this instanceof demo)){ return new demo(); } }
通过判断this是不是实例来进行实例化。这样就可以避免漏掉new关键字。
var Factory=function(type,content){ if(this instanceof Factory){ var s=new this[type](content); }else{ return new Factory(type,content) } } Factory.prototype={ java:function(content){ //...... }, php:function(content){ //...... }, //...... }
在原型上添加不同类型的方法,然后在调用子类的时候实例化。如果采用简单工厂模式的话,用类实例化方法,但是这样需要修改工厂方法和添加基类,也就是要修改两个地方。而采用上面的方法,只需要在原型上添加方法就可以了。
避免了使用者和对象类之间的耦合,用户不用关心创建该类的具体类,只需要调用工厂方法就可以。
3、抽象工厂模式
抽象类并不是用来创建具体的类,而是用来当做父类来创建一些子类。创建的是一个类簇,它制定了类的结构。其实就是先创建一个大类,然后在细分下,添加小类的实现方法,将小类的方法挂到小类的原型上。
4、建造者模式
将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示。
工厂模式主要是为了创建对象实例或者类簇(抽象工厂),关心的是最终产出(创建)的是什么。不关心创建的过程,仅仅需要创建的最终结果。所以工厂模式得到的是对象实例或者类簇。而建造者模式再创建对象的时候更为复杂,虽然其目的也是创建对象,但是其更多的是关心创建的整个过程,甚至于创建对象的每一个细节,比如创建一个人,我们不仅要得到人的实例,还要关心穿什么衣服,男的女的,兴趣爱好等等。
举例子:创建一个求职者。我们先创建三个类,Human,Named,Work类。然后在建造者类中调用这三个类的组合,创建一个完整的应聘者对象。
var Person=function(name,work){ var _person=new Human(); _person.name=new Named(name); _person.work=new Work(work); return _person; }
在建造者模式中将创建的对象类模块化,这样使得每个模块都可以得到灵活的运用与高质量的复用。但是如果对象粒度很小,或者模块间复用率很低且变动不大,我们最好还是创建整体对象。
5、原型模式
用原型实例指向创建者对象的类,使用于创建新的对象的类共享原型对象的属性以及方法。
原型拓展:就是在prototype上进行拓展。
6、单例模式
只允许实例化对象一次。,有时我们也用一个对象来规划一个命名空间,井井有条的管理对象上的属性和方法。
var sing=(function(){ var instance=null; function Single(){} return function(){ if(!instance){ instance=Single; } return instance; } })();
7、外观模式
//外观模式:为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更加容易。在JavaScript中,有时也会用于对底层结构兼容性做统一封装来简化用户使用。 //实现 function addEvent(dom,type,fn){ if(dom.addEventListener){ dom.addEventListener(type,fn,false); }else if(dom.attachEvent){ dom.attachEvent("on"+type,fn); }else{ dom["on"+type]=fn; } }
8、适配器模式
//适配器模式:将一个类(对象)的接口(方法或者属性)转化为另一个接口,以满足用户的需求,使类之间的接口的不兼容问题通过适配器得以解决。 //举例子:其实就是为了两个代码库所写的代码兼容运行而书写的额外代码。这样我们就不需要特意地重写以前的功能代码了。 //参数适配器:比如某个函数要传入很多参数 function dosomething(name,title,age,color,size,prize){}; //那么我们要记住这些参数的顺序是很困难的,因此常用的做法是以一个参数对象方式传入的。 function dosomething(obj){}; //即使这样,还是存在一个问题,就是我们不知道参数是不是完整的,如果一些参数没有传入,需要使用默认值等等。此时我们通常的做法就是用适配器来适配传入的这个参数对象。 function dosomething(obj){ var _adapter={ name:"me", title:"设计", age:24, color:"pink", } }