参考:
https://juejin.cn/post/6844904125721772039#heading-33
GOF提出23种设计模式。
原型有一个样板实例,原型模式简单理解就是拷贝实例对象。类初始化需要消耗很多资源,通过原型模式进行拷贝对象急减少了消耗。
function Animal(name) {
console.log('0000'+name);
this.name = name || 'animal';
this.eat = function(food) {
console.log(`${this.name} 在吃${food}`)
}
}
Animal.prototype.sleep = function() {
console.log(this.name + '正在睡觉');
}
function Cat() {};//创建抽象类
Cat.prototype = new Animal();//继承Animal类
Cat.prototype.name = 'cat';
var cat = new Cat();
console.log(cat);
cat.eat('鱼');
cat.sleep();
console.log(cat instanceof Cat);
console.log(cat instanceof Animal);
单例模式的应用:windows的任务管理器。不能同事打开两个任务管理器。支付功能,一个订单只能支付一次。
优缺点:
let singleCase = function(name){
this.name = name;
};
// 获取实例对象
let getInstance = (function() {
var instance = null;
return function(name) {//返回的这个函数引用了instance。所以导致IIFE立即执行函数执行完被销毁之后,变量instance会被缓存起来,形成了闭包。所以当传入two参数再次执行时,不会重新声明一个变量instance而是去访问缓存的instance。
if(!instance) {//相当于一个一次性阀门,只能实例化一次
instance = new singleCase(name);
console.log(instance);
}
return instance;
}
})();//
// 测试单体模式的实例,所以one===two
let one = getInstance("one");
let two = getInstance("two");
简单工厂 :用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)
抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)
直接使用工厂方法就能创建对象,而不用使用new关键字。在创建对象的过程中,看不到构造函数实例化的过程。
实例化对象的最佳方式。通过使用一个共同的接口来指向新创建的对象。
var Factory=function(type,content){
if(this instanceof Factory){//判断是不是实例对象,是就返回相关属性。不是就new创建。
return new this[type](content);
}else{
return new Factory(type,content);
}
}
Factory.prototype={
Python:function(content){
console.log('Python值为',content);
}
}
Factory('Python','我是Python');
function playerFactory (username){
var user= new object ();
user .username = username;
return user ;
}
var xm = playerFactory( 'xiao ming ')
创建一个函数,通过接收参数来生成不同的对象。
提供一个[创建一系列相关或相互依赖对象的]接口。
// let useFactory = function(role) {
// function User(opt) {
// this.name = opt.name;
// this.age = opt.age;
// }
// switch(role) {
// case 'administrator':
// return new User(administrator);
// break;
// case 'admin':
// return new User(admin);
// break;
// default:
// console.log('不是管理员')
// }
// }
// let administrator = UserFactory('administrator');
// let admin = UserFactory('admin');
function UserFactory(role) {
function User(opt) {
this.name = opt.name;
this.age = opt.age;
console.log(this)
}
switch (role.name) {
case 'superAdmin':
return new User(role);
break;
case 'admin':
return new User(role);
break;
case 'user':
return new User(role);
break;
default:
console.log('000')
}
}
//调用
let superAdmin = UserFactory({name:'superAdmin',age:24});
let admin = UserFactory({name:'admin',age:28});
let normalUser = UserFactory({name:'user',age:18});
//子类继承父类,子类重写父类中的抽象方法。
应用于适配函数参数。
举个例子:存在3条数据,分别来自3个数据来源,是3种不同的数据结构的。而我们接收的数据格式是规定好的某一种。采用适配器模式,就可以实现兼容,将不同的数据结构都适配成我们所能接收的数据结构。
//鸭子
var Duck = function(){};
Duck.prototype.fly = function(){
throw new Error("该方法必须被重写!");
};
Duck.prototype.quack = function(){
throw new Error("该方法必须被重写!");
}
//火鸡
var Turkey = function(){};
Turkey.prototype.fly = function(){
throw new Error(" 该方法必须被重写 !");
};
Turkey.prototype.gobble = function(){
throw new Error(" 该方法必须被重写 !");
};
//然后再定义具体的鸭子和火鸡的构造函数,分别为:
//鸭子
var MallardDuck = function () {
Duck.apply(this);
};
MallardDuck.prototype = new Duck(); //原型是Duck
MallardDuck.prototype.fly = function () {
console.log("可以飞很长的距离!");
};
MallardDuck.prototype.quack = function () {
console.log("嘎嘎!嘎嘎!");
};
//火鸡
var WildTurkey = function () {
Turkey.apply(this);
};
WildTurkey.prototype = new Turkey(); //原型是Turkey
WildTurkey.prototype.fly = function () {
console.log("飞翔的距离貌似有点短!");
};
WildTurkey.prototype.gobble = function () {
console.log("咯咯!咯咯!");
};
//为了让火鸡也支持quack方法,我们创建了一个新的火鸡适配器TurkeyAdapter:
var TurkeyAdapter = function(oTurkey){
Duck.apply(this);
this.oTurkey = oTurkey;
};
TurkeyAdapter.prototype = new Duck();
TurkeyAdapter.prototype.quack = function(){
this.oTurkey.gobble();
};
TurkeyAdapter.prototype.fly = function(){
var nFly = 0;
var nLenFly = 5;
for(; nFly < nLenFly;){
this.oTurkey.fly();
nFly = nFly + 1;
}
};
let decorator=function(input,fn){
//获取事件源
let input=document.getElementById(input);
console.log(input.onclick)
//若事件源已经绑定事件
if(typeof input.onclick=='function'){
//缓存事件源原有的回调函数
let oldClickFn=input.onclick;
//为事件源定义新事件
input.onclick=function(){
//事件源原有回调函数
oldClickFn();
//执行事件源新增回调函数
fn();
}
}else{
//未绑定绑定
input.onclick=fn;
}
}
//测试用例
decorator('textInp',function(){
console.log('文本框执行啦');
})
decorator('btn',function(){
console.log('按钮执行啦');
})
//在形式上,外观模式在javascript中就像这样:
function a(x){
// do something
}
function b(y){
// do something
}
function ab( x, y ){
a(x);
b(y);
}
代理模式是通过代理来控制对对象的访问。实际功能还是对象本身去执行。代理只是控制是否去执行这个功能。
代理模式使用场景:
let myFather = function(){};//创建抽象类父类。在父类中封装子类的算法框架
myFather.ptototype.one = function() {
console.log('把水煮沸')
}
myFather.ptototype.two = function() {
throw new Error("子类必须重写方法");
}
myFather.ptototype.three = function() {
throw new Error("子类必须重写方法");
}
myFather.prototype.isdo = function() {//添加钩子方法给不一定执行的函数添加条件控制
return true;
}
myFather.prototype.init = function() {
this.one();
this.two();
if(this.isdo()) {//3是否执行要看isdo的返回值
this.three();
}
}
let mySon = function(){};//创建子类
mySon.prototype = new myFather();//继承抽象类
mySon.prototype.two = function() {
console.log('重写two方法')
}
mySon.prototype.isdo = function() {
return window.confirm("需要执行three方法吗");
}
mySon.prototype.three = function() {
console.log('重写three方法')
}
let mySon_duixiang = new mySon();
mySon_duixiang.init();
策略+组合:
算法可以自有切换,扩展性很好,避免了使用多重条件判断。
所有策略都需要对外暴露
let strategies = {
'a': function(val) {
return val * 4;
},
'b': function(val) {
return val * 3;
},
'c': function(val) {
return val * 2;
}
}
let calcu = function(level,val) {
return strategies[level](val);
}
calcu('a',777);
作用:解耦了各节点关系。各节点灵活拆分重组。
使用场景:
好处:减少事件数量,避免内存泄漏,有利于提高性能。
singleton:单例模式,用来减少重复创建对象。
factory:工厂模式,用来解耦。
iterator:迭代器模式,用来遍历对象。
observer:观察者模式,用来收发消息。
templete:模板模式,用来避免执行相同的操作。
strategy:策略模式,用来定义算法等。