设计模式概念
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
设计模式分为三种类型,共23种:创建型模式、结构性模式、行为性模式。
创建型设计模式
简单工厂模式
简单工厂模式又叫静态工厂模式,由一个工厂对象决定创建某一种产品对象类的实例。主要用来创建同一类对象,无需关心其具体的实现。
// 创建篮球基类 var Basketball = function(){ this.info = '篮球盛行于美国'; } // 为篮球基类添加原型方法 Basketball.prototype = { getName(){ console.log('Basketball') } } // 创建足球基类 var Football = function(){ this.info = '足球流行与世界' } Football.prototype = { getName(){ console.log('Football') } } // 创建网球基类 var Tennis = function(){ this.info = '网球' } Tennis.prototype = { getName(){ console.log('Tennis') } } var SportsFactory = function(name){ switch(name){ case 'NBA': return new Basketball(); case 'wordCup': return new Football(); case 'FrenchOpen': return new Tennis(); } } // 创建一个足球类 var football = SportsFactory('wordCup'); football.getName(); // Football
工厂方法模式
工厂方法模式:通过对产品类的抽象使其创建业务主要负责用于创建多累产品的实例。其本意是将实际创建对象工作推迟到子类当中,这样核心类就成为了抽象类。
// 使用安全模式创建基类 var Factory = function(type, info){ if(this instanceof Factory){ this.name = info.name return this[type](info) }else{ return new Factory(type, info); } } Object.assign(Factory.prototype, { Bicycle(info){ this.price = 20; this.getName = function(){ console.log(this.name) } }, Motorcycle(type){ }, ElectricCar(type){ } }) var bicycle = Factory('Bicycle', {name: 'bicycle'});
这样在以后需要添加其他类时只需要在Factory这个工厂类的原型中添加就可以了,不需要像简单工厂模式一样重新创建一个新的类。
适用性
-
当一个类不知道它所必须创建的对象的类的时候。
-
当一个类希望由它的子类来指定它所创建的对象的时候。
-
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
抽象工厂模式
抽象工厂模式:通过对类的工厂抽象使其业务用于对类产品簇的创建,而不负责其一类产品的实例。
// 抽象工厂 var VehicleFactory = function(subClass, superClass){ // 判断抽象工厂中是否有该抽象类 if(typeof VehicleFactory[superClass] === 'function'){ // 缓存类 function F(){} // 继承父类的方法和属性 F.prototype = new VehicleFactory[superClass](); // 将子类的constructor指向子类 subClass.constructor = subClass; // 子类继承父类 subClass.prototype = new F(); } } // 抽象类 VehicleFactory.Car = function(){ this.type = 'car' } VehicleFactory.Car.prototype = { getPrice(){ return new Error('抽象类方法不能使用') }, getSpeed(){ return new Error('抽象类方法不能使用') } } VehicleFactory.Bus = function(){ this.type = 'bus' } VehicleFactory.Bus.prototype = { getPrice(){ return new Error('抽象类方法不能使用') }, getSpeed(){ return new Error('抽象类方法不能使用') } } VehicleFactory.ElectricCar = function(){ this.type = 'ElectricCar' } VehicleFactory.ElectricCar.prototype = { getPrice(){ return new Error('抽象类方法不能使用') }, getSpeed(){ return new Error('抽象类方法不能使用') } } // 调用 // 创建子类 var Tesla = function(price, name){ this.price = price this.name = name } VehicleFactory(Tesla, 'ElectricCar'); Tesla.prototype = { getPrice(){ console.log(this.price) } } var tesla = new Tesla(600000, 'tesla'); tesla.getPrice()
抽象工厂其实是一个实现子类继承父类的方法,在这个方法中需要通过传递子类以及要继承的父类(抽象类)的名称,并在抽象工厂方法中增加一次对抽象类存在性的判断,如果存在,则子类继承父类的方法(子类通过寄生式继承父类)。
适用性
-
-
一个系统要独立于它的产品的创建、组合和表示时。
-
一个系统要由多个产品系列中的一个来配置时。
-
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
-
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
-
建造者模式
建造者模式:将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示。
var Human = function(param){ this.skill = param && param.skill || '保密'; this.hobby = param && param.hobby || '保密'; } Human.prototype = { getSkill(){ return this.skill; }, getHobby(){ return this.hobby; } } var Person = function(name){ var _person = new Human(); _person.name = name; return _person } var person = new Person('xiaohong'); console.log(person.name) console.log(person.getHobby())
适用性
-
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
-
当构造过程必须允许被构造的对象有不同的表示时。
原型模式
原型模式:用原型实例指向创建对象的类,使用于创建新的对象的类共享原型对象的属性以及方法。
var Human = function(){ } Human.prototype = { eat(){ console.log(`${this.name} eating`) }, say(){ console.log(`${this.name}`) }, run(){ `${this.name} runing` } } var Student = function(name, age){ Human.call(this) this.name = name this.age = age } Student.prototype = new Human(); var Teacher = function(name, age){ Human.call(this) this.name = name this.age = age } Teacher.prototype = new Human(); var s1 = new Student('xiaoming', 14); var t1 = new Teacher('laoli', 33); console.log(s1.name) s1.say()
原型对象是一个共享的对象,那么无论是父类的实例对象或者是子类的继承,都是对它的一个指向引用,所以原型对象才会被共享。那么对原型对象的拓展,无论是子类或者是父类的实例对象都会被继承下来。所以说原型对象模式有一个特点就是在任何时候都可以对基类或者子类进行方法的拓展,而且所有被实例化的对象或者类都能获取这些方法,这样就给予我们对功能拓展的自由性。
适用性
-
当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者
-
为了避免创建一个与产品类层次平行的工厂类层次时;或者
-
当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
单例模式
单例模式:又被称为单体模式,是只允许实例化一次的对象类。
var Person = (function(){ var info = { NAME: 'xiaoming', Age: 20, JOB: 'teacher' } return { get(){ console.log(info.NAME) } } })() Person.get()
class Person{
static pp(){
if(Person.nnn === null){
return Person.nnn = [1,2,3,4]
}else{
return Person.nnn
}
}
constructor(){
this.newp = Person.pp()
}
}
Person.nnn = null
var h = new Person();
var hh = new Person()
console.log(h.newp === hh.newp) // true
适用性
-
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
-
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
参考资料:
JavaScript设计模式 张容铭著
设计模式——百度百科