创建型设计模式
1、简单工厂模式
当类太多,并且这些类有很多相似之处,那么可以用一个工厂函数将这些类整合起来,以后想要创建这些类之一时,可直接调用工厂函数传入参数,来选择你想创建的类。
var Benz = function() {
this.brand = 'Benz';
}
Benz.prototype.getBrand = function() {}
var BMW = function() {
this.brand = 'BMW';
}
Benz.prototype.getBrand = function() {}
// 工厂函数
var createCar = function(type) {
switch(type) {
case 'Benz':
return new Benz();
case 'BMW':
return new BMW();
}
}
// ---也可以抽取相同点----------------
var createCar = function(brand) {
var o = new Object();
o.brand = brand;
o.getBrand = function() {};
if (brand === 'Benz') {
// ...
} else if (brand === 'BMW') {
// ...
}
return o;
}
2、工厂方法模式
简单工厂模式的缺点:当类很多,需求不断变动时,每添加一个类,都要在工厂函数添加判断,使得操作繁琐。
function Factory(type, content) {
// 安全模式,避免当有人调用Factory,没有使用new关键字时报错
if (this instanceof Factory) {
return new this[type](content);
} else {
return new Factory(type, content);
}
}
Factory.prototype = {
Benz: function(content) {
// ...
},
BMW: function(content) {
// ...
}
// ...
}
var a = Factory('Benz', '。。。');
使用工厂方法模式,当添加类时,只需在Factory.prototype上添加多一个属性即可
3、抽象工厂模式
简单工厂模式创建单一对象,工厂方法模式创建多类对象。而抽象工厂模式创建的是一个类簇。
简单工厂模式是一个小型的汽车工厂,它只创建几种款型的车型。
工厂方法模式就像是一个大型的汽车工厂,它生产各种款式品牌的汽车,并且汽车车型还会不断上新。
抽象工厂模式更像是一个大型制造厂,它管理汽车制造,也管理卡车制造等等,它并不直接生产汽车、卡车或其他,它只是管理维护制造的基本流程。
function VehicleFactory(subType, superType) {
if (typeof VehicleFactory[superType] === 'function') {
// 缓存类
function F() {};
F.prototype = new VehicleFactory[superType]();
subType.prototype = new F();
subType.prototype.constructor = subType;
} else {
throw new Error('未创建该抽象类');
}
}
VehicleFactory.Car = function () {
this.type = 'car';
}
VehicleFactory.Car.prototype = {
getPrice: function() {
return new Error('抽象方法不能调用');
},
// ...
}
VehicleFactory.Truck = function () {
this.type = 'truck';
}
VehicleFactory.Truck.prototype = {
getPrice: function() {
return new Error('抽象方法不能调用');
},
// ...
}
function Audi() {
this.name = 'audi';
}
VehicleFactory(Audi, 'Car');
Audi.prototype.getPrice = function() {
return 500000;
}
var audi = new Audi();
audi.getPrice(); // 500000
4、建造者模式
工厂模式主要是为了创建对象实例或者类簇,关心的是最终产出的结果,而不是过程。而建造者模式在创建对象时要更为复杂一些,虽然其目的也是为了创建对象,但是它更多关心的是创建这个对象的整个过程,更像是一个定制化过程。
var Car = function(params) {
this.brand = params && params.brand;
this.price = params && params.price;
}
Car.prototype = {
getBrand: function() {
return this.brand;
},
getPrice: function() {
return this.price;
}
}
// 选配设备
var Equipment = function(list) {
var equipmentMap = {
lighting: '环境氛围照明系统',
GPS: '实景穿越导航',
},
arr = [];
for (let key of list) {
if (equipmentMap[key]) {
arr.push(equipmentMap[key]);
}
}
this.equipment = arr;
}
// 汽车外观
var Appearance = function(color) {
var that = this;
(function(color, that) {
switch(color) {
case 'blue':
that.color = '蓝色';
that.colorDescription = '星野蓝色';
break;
case 'white':
that.color = '白色';
that.colorDescription = '次元白色';
break;
case 'red':
that.color = '红色';
that.colorDescription = '溶岩红色';
break;
}
})(color, that)
}
Appearance.prototype.changeColor = function(color) {
this.color = color;
}
Appearance.prototype.changeColorDecription = function(desc) {
this.colorDescription = desc;
}
var CustomCar = function(basic={}, option={}) {
var _car = new Car(basic);
_car.color = new Appearance(option.color);
_car.equipment = new Equipment(option.equipment);
return _car;
}
var myCar = new CustomCar(
{
brand: 'Benz',
price: 1000000,
},
{
color: 'white',
equipment: ['lighting']
}
)
console.log(myCar);
5、原型模式
原型模式就是将可复用的、可共享的、耗时大的从基类中提出来然后放在原型中,然后子类通过组合继承或寄生组合式继承而将方法和属性继承下来,对于子类中那些需要重写的方法进行重写,这样子类创建的对象既具有子类的属性和方法也共享了基类的原型方法。
// 图片轮播类
var LoopImages = function(imgArr, container) {
this.imagesArray = imgArr;
this.container = container;
}
LoopImages.prototype = {
createImage: function() {},
// 切换图片
changeImage: function() {
console.log('LoopImages');
}
}
// 上下滑动切换类
var SlideLoopImages = function(imgArr, container) {
// 构造函数继承
LoopImages.call(this, imgArr, container);
}
SlideLoopImages.prototype = new LoopImages();
// 重写继承的切换图片方法
SlideLoopImages.prototype.changeImage = function() {
console.log('SlideLoopImages');
}
// 渐变切换类
var FadeLoopImages = function(imgArr, container, arrow) {
// 构造函数继承
LoopImages.call(this, imgArr, container);
// 切换箭头私有变量
this.arrow = arrow;
}
FadeLoopImages.prototype = new LoopImages();
// 重写继承的切换图片方法
FadeLoopImages.prototype.changeImage = function() {
console.log('FadeLoopImages');
}
var slideImg = new SlideLoopImages(['1.png', '2.png'], 'box');
console.log(slideImg);
/*
{
container: "box",
imagesArray: ["1.png", "2.png"],
__proto__: {
changeImage: function() { console.log('FadeLoopImages') },
container: undefined,
imagesArray: undefined,
__proto__: {
changeImage: function() { console.log('LoopImages') },
createImage: function() {},
__proto__: Object
}
}
}
*/
原型对象是一个共享的对象,那么无论是父类的实例对象或者是子类的继承,都是对它的一个指向引用,所以原型对象才会被共享。既然被共享,那么对原型对象的扩展,不论是子类或者父类的实例对象都会继承。
LoopImages.prototype.getContainer = function() {
return this.container;
}
console.log(slideImg.getContainer()); // 'box'
6、单例模式
将一类功能方法放在一个对象中
var A = {
Util: {
util_method1: function() {},
util_method2: function() {},
},
Tool: {
tool_method1: function() {},
tool_method2: function() {},
},
// ...
}
惰性单例
var LazySingle = (function() {
// 单例实例引用
var _instance = null;
function Single() {
// 私有属性
var type = 'single';
return {
getType: function() {
return type;
},
publicMethod: function() {},
publicProperty: '1.0',
}
}
return function() {
if (!instance) {
_instance = Single();
}
return _instance;
}
})()
最后
本文是看了《JavaScript设计模式》(作者:张容铭)的第二篇章后所做的笔记,理解可能有误,望指出。