JavaScript中常见的设计模式
工厂模式
提供一个创建实例的功能,不需要关心具体的实现。被创建的实例的类型可以是接口,也可以是抽象类或者具体类。
命名规范
类名称:模块名称+Factory
方法名称:get+接口名称或者create + 接口名称
简单工厂
例如:假设这是一个汽车店,多种型号的汽车出售
function CarShop(){}
CarShop.prototype = {
carsell:function(model){
var cars;
switch (model) {
//类型A
case "The A":
cars = new $A();
break;
case 'The B':
cars = new $B();
break;
case "The C":
default:
cars = new $C();
}
cars.assemble();
cars.wash();
return cars
}
};
/* $A */
function $A(){};
$A.prototype = {
assemble:function(){console.log(111)},
wash:function(){},
ride:function(){},
repair:function(){}
}
//需要出售某个型号,直接调用CarShop
var a = new CarShop();
var yourNeed = a.carsell('The a');
在供货目录中增加新型号的汽车,不用更改CarShop,直接把carsell中创建实例的工作外包给工厂对象
/* $A */
function $A(){};
$A.prototype = {
assemble:function(){console.log(111)},
wash:function(){},
ride:function(){},
repair:function(){}
}
/*
在供货目录中增加新型号的汽车,不用更改CarShop,直接把carsell中创建实例的工作外包给工厂对象
*/
var CarsFactory = {
createCar:function(model){
var cars;
switch (model) {
case 'The A':
cars = new $A();
break;
case 'The B':
cars = new $B();
break;
// 新增加的类型
case 'The D':
cars = new $D();
break;
case 'The C':
default:
cars = new $C()
}
return cars;
}
};
var CarShop = function(){}
CarShop.prototype = {
carssell:function(model){
var cars = CarsFactory.createCar(model);
cars.assemble();
cars.wash();
return cars;
}
}
var californiaCruisers = new CarShop();
var yourNewBike = californiaCruisers.carssell('The A');
简单工厂模式实现登陆模块
function createPop(type,text){
//创建一个对象,并进行拓展属性和方法
var o = new Object();
o.content = text;
o.show = function(){
//显示的方法
};
if (type =='alert') {
//警示框差异部分
}
if (type =='prompt') {
//提示框差异部分
}
if (type == 'confirm') {
//确认框差异部分
}
return o;
}
var userNameAlert = createPop("alert","用户名只能是26个字母和数字");
console.log(userNameAlert.content)
工厂方法模式
定义一个用于创建对象的接口,子类决定实例化哪个类。把实际创建对象的工作推迟到子类中。那么核心类就成了抽象类,
安全模式类:屏蔽错误使用这对类造成的错误。例如一个类的创建,前面需要new关键词,在其他人不知道这对象是一个类时,往往会忽略new关键字直接执行类,造成了错误。
通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例
把CarShop设计为抽象类,要么使用Creator对象,要么使用Creator创建对象。
/* $A型号的汽车的服务类型 */
function $A(){};
$A.prototype = {
//组装
assemble:function(){console.log(111)},
//清洗
wash:function(){},
//维修
repair:function(){}
}
//自己的汽车店
var CarShop = function(){}
CarShop.prototype = {
carssell:function(model){
var cars = this.createCar(model);
cars.assemble();
cars.wash();
return cars;
},
createCar:function(){
throw new Error('NO')
}
}
//两个子类,分别从zh,gy公司进货
function extend(subClass,superClass){
function F(){}
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
if (superClass.prototype.constructor === Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
//hz class
var hzCarShop = function(){}
extend(hzCarShop,CarShop);
hzCarShop.prototype.createCar = function(model){
var car;
switch (model) {
case 'The A':
cars = new $A();
break;
case 'The B':
cars = new $B();
break;
// 新增加的类型
case 'The D':
cars = new $D();
break;
case 'The C':
default:
cars = new $C()
}
return cars;
}
//gy class
var gyCarShop = function(){};
extend(gyCarShop,CarShop);
gyCarShop.prototype.createCar = function(model){
var cars ;
switch (model) {
case 'The A':
cars = new $A();
break;
case 'The B':
cars = new $B();
break;
// 新增加的类型
case 'The D':
cars = new $D();
break;
case 'The C':
default:
cars = new $C()
}
return cars;
};
var californiaCruisers = new hzCarShop();
var yourNewBike = californiaCruisers.carssell('The A');
工厂模式的适用场景:
1、动态实现,创建不同的方式来实现同一接口
2、节省设置开销:若对象需要进行复杂并且多次相关的设置,使用工厂模式可以减少每个类型对象的代码量
3、多个小型对象组成大的对象
工厂模式消除对象之间的耦合,可以把所有的代码集中一起,这样简化了更换所有类或者在运行期间动态选择所用的类的工作。在工厂模式中,可以先创建一个抽象的父类,在子类中创建工厂方法,把成员对象的实例化延迟到子类中进行。
然而并不是所有场景都要使用工厂模式,如果在运行期间不需要在一系列可互换的类中进行选择,则不应该使用工厂模式。使用new关键字和构造函数公开进行实例化,可以让代码简单易读。
简单工厂和抽象工厂
简单工厂用来选择实现的,可以选择任意接口的实现,简单工厂可以有多个用于选择并且创建对象的方法,,多个方法创建的对象可以有关系或者没关系。
抽象工厂是一个实现子类继承父类的方法,需要传递子类以及继承父类的名称,
抽象工厂模式用来选择产品系列的实现,抽象工厂里面有多个用于选择并且创建对象的方法,但是这些方法创建的对象是有联系的,它们可以构建成了一个产品系列所需的部件对象。
/**
* 抽象工厂方法
* 参数subType 子类
* 参数superType 父类
*/
var VehicleFactory = function(subType,superType){
//判断抽象工厂中是否有该抽象类
if (typeof VehicleFactory[superType] === 'function') {
//缓存类
function F(){};
//继承父类属性和方法
F.prototype = new VehicleFactory[superType]();
//把子类的constructor指向子类
subType.constructor = subType;
//子类继承父类
subType.prototype = new F();
}else{
throw new Error("未创建该抽象类");
}
}
//抽象工厂实例
VehicleFactory.Car = function(){
this.type = 'car';
};
VehicleFactory.Car.prototype = {
getPrice:function(){
return new Error("抽象方法不能使用");
},
getSpeed:function(){
return new Error("抽象方法不能使用");
}
};
VehicleFactory.Bus = function(){
this.type = "bus";
};
VehicleFactory.Bus.prototype = {
getPrice:function(){
return new Error("该抽象方法不能调用")
},
getPassengerNum:function(){
return new Error("该抽象方法不能调用")
}
};
VehicleFactory.Truck = function(){
this.type = "truck";
};
VehicleFactory.Truck.prototype = {
getPrice:function(){
return new Error("该抽象方法不能调用")
},
getTrainload:function(){
return new Error("该抽象方法不能调用")
}
};
//宝马汽车子类
var BMW = function(price,speed){
this.price = price;
this.speed = speed;
};
VehicleFactory(BMW,'Car');
BMW.prototype.getPrice = function(){
return this.price;
}
BMW.prototype.getSpeed = function(){
return this.speed;
}
//
var Lamborghini = function(price,speed){
this.price = price;
this.speed = speed;
};
VehicleFactory(Lamborghini,"Car");
Lamborghini.prototype.getPrice = function(){
return this.price
}
Lamborghini.prototype.getSpeed = function(){
return this.speed;
}
var YUTONG = function(price,passenger){
this.price = price;
this.passenger = passenger;
}
//抽象工厂实现对Bus抽象类的继承
VehicleFactory(YUTONG,"Bus");
YUTONG.prototype.getPrice = function(){
return this.price;
}
YUTONG.prototype.getPassengerNum = function(){
return this.passenger;
}
//奔驰汽车子类
var BenzTruck = function(price,trainLoad){
this.price = price;
this.trainLoad = trainLoad;
}
VehicleFactory(BenzTruck,"Truck");
BenzTruck.prototype.getPrice = function(){
return this.price;
}
BenzTruck.prototype.getTrainload = function(){
return this.trainLoad
}
//测试代码
var truck1 = new BenzTruck(1000000,250000);
console.log(truck1.getPrice());//1000000
console.log(truck1.type) //Truck
简单工厂和工厂方法模式
工厂方法也是用来选择实现的,区别在于工厂方法是把选择具体实现的功能延迟到子类中进行。若是工厂方法中选择实现放在父类中进行,它就成为了简单工厂模式。
简单工厂和创建对象实例的模式
简单工厂可以和其他任何可以创建对象实例的模式搭配使用。
示例:
//XHR
/*根据浏览器的不同来生成一个XMLhttpRequest或者ActiveXObject实例*/
var AjaxHandler = new Interface('AjaxHandler',['request','createXhrObject']);
var $handler = function(){};
$handler.prototype = {
request:function(method,url,callback,postVar){
var xhr = this.createXhrObject();
xhr.onreadystatechange = function(){
if (xhr.readystate !== 4) {
return ;
}
((xhr.status>=200 && xhr.status<300) || xhr.status === 304 ?callback.success(xhe.responseText,xhr.responseXML) : callback.failure(xhr.status))
};
xhr.open(method,url,true);
if (method !== "POST") {
postVar = null;
}
xhr.send(postVar)
},
createXhrObject:function(){
var methods = [
function(){
return new XMLHttpRequest();
},
function(){
return new ActiveXObject('MSXML2.XMLHTTP.3.0');
},
function(){
return new ActiveXObject('MSXML.XMLHTTP')
},
function(){
return new ActiveXObject('Microsoft.XMLHTTP')
}
];
for(var i=0,len=methods.length;i<len;i++){
try {
methods[i]();
} catch (e) {
continue;
}
this.createXhrObject = methods[i];
return methods[i]();
}
throw new Error("Handler:Could not create an XHR object.");
}
}
//发起一个请求的过程
var myHandler = new $handler();
var callback = {
success:function(responseText){
alert("Success:"+responseText);
},
failure:function(statusCode){
alert('Failure:'+statusCode)
}
};
myHandler.request('GET','url',callback);
//专用型连接对象
function QueueHandler(){
this.queue = [];//请求队列 保存
this.requestInprogress = false;//请求进程,
this.retryDelay = 10;//延迟
}
extend(QueueHandler,$handler);
/**
@param override 覆盖请求
*/
QueueHandler.prototype.request = function(method,url,callback,postVar,override){
if (this.requestInprogress && !override) {
//其他请求正在进行,不覆盖
this.queue.push({
method:method,
url:url,
callback:callback,
postVar:postVar
});
}else{
//没有请求在进行,立即执行该请求,成功后递归
this.requestInprogress = true;
var xhr = this.createXhrObject();
var that = this;
xhr.onreadystatechange = function(){
if (xhr.readystate !== 4) {
return;
}
if ((xhr.status >= 200 && xhr.status<300) || xhr.status === 304) {
//请求成功
callback.success(xhr.responseText,xhr.responseXML);
that.adanceQueue();
}else{
callback.failure(xhr.status);
setTimeout(() => {
that.request(method,url,callback,postVar,true);
}, that.retryDelay*1000);
}
}
xhr.open(method, url, true);
if (method !== "POST") {
postVar = null;
}
xhr.send(postVar);
}
}
//处理位于最前队列的请求
QueueHandler.prototype.adanceQueue = function(){
if (this.queue.length === 0) {
this.requestInprogress = false;
return;
}
var req = this.queue.shift();
this.request(req.method,req.url,req.callback,req.postVar,true);
};