关于javascript:手写JavaScript常见5种设计模式

31次阅读

共计 5653 个字符,预计需要花费 15 分钟才能阅读完成。

想分享的几种设计模式

目前模式:工厂模式,单例模式,适配器模式,装璜者模式,建造者模式

建造者模式

简介:建造者模式(builder pattern)比较简单,它属于创立型模式的一种。

文言:4 个局部:有个产品,有个工厂能够造产品,有个设计师指挥造多少,有集体想买产品。

买产品的用户不介意产品制作流程,只须要产品!

function Cola() {
    this.sugar = '50g',
    this.water = '100g'
}
function Packing() { // 第一种打包形式
    this.createPkg = function(){console.log('创立可乐外皮')
    }
    this.pushCola = function() {console.log('可乐倒进瓶子')
    }
    this.complete = function() {var cola = new Cola()
        cola.complete = true
        return cola
    }
    this.init = function() {this.createPkg() // 创立外皮
        this.pushCola() // 倒进瓶子
        // 还能够减少其余步骤
        return this.complete() // 制作实现}
}
function greenPacking() { // 绿皮可乐打包形式
    this.createPkg = function(){console.log('创立 green 可乐外皮')
    }
    this.pushCola = function() {console.log('可乐倒进 green 瓶子')
    }
    this.complete = function() {var cola = new Cola()
        cola.complete = true
        return cola
    }
    this.init = function() {this.createPkg() // 创立外皮
        this.pushCola() // 倒进瓶子
        // 还能够减少其余步骤
        return this.complete() // 制作实现}
}
function Boss() {this.createCola = function(packType) {const pack = new window[packType]
        this.product = pack.init() // 残缺产品产出}
    this.getCola = function(packType) {this.createCola(packType);
        return this.product
    }
}
const boss = new Boss()
var UserCola = boss.getCola('greenPacking') // UserCola.complete === true

其余货色都不要,只有最初生产好的 Cola,有 sugar,有 water。

关键在于 Boss 函数中,负责一个整合的职责

同样的 Boss 函数,我能够通过更换 Packing 函数,打包形式,取得不同款式的 Cola。

通过给 getCola 函数传入不同想要的参数,取得不同的最终产品。实现了可插拔的函数构造。

装璜者模式

装璜者提供比继承更有弹性的代替计划。装璜者用用于包装同接口的对象,不仅容许你向办法增加行为,而且还能够将办法设置成原始对象调用(例如装璜者的构造函数)。

装璜者用于通过重载办法的模式增加新性能,该模式能够在被装璜者后面或者前面加上本人的行为以达到特定的目标。

益处:

装璜者是一种实现继承的代替计划。当脚本运行时, 在子类中减少行为会影响原有类所有的实例,而装璜者却不然。取而代之的是它能给不同对象各自增加新行为 。参考 前端手写面试题具体解答

function iwatch () {
    this.battery = 100;
    this.getBattery = function() {console.log(this.battery)
    }
}

iwatch.prototype.getNewPart = function(part) {this[part].prototype = this; // 把 this 对象上的属性 指向 新对象的 prototype
    return new this[part]; // 返回一个新对象,不批改原对象,新增了新对象的属性
}

iwatch.prototype.addNetwork = function() {this.network = function() {console.log('network')
    }
}

iwatch.prototype.addSwim = function() {this.swim = function() {console.log('swim')
    }
}

var watch = new iwatch();
watch.getBattery(); // 100

watch = watch.getNewPart('addNetwork'); // 增加新行为,network()
watch = watch.getNewPart('addSwim'); // 既有 network 办法,也有 swim 办法 

在 ES7 中引入了 @decorator 润饰器的提案,参考阮一峰的文章。

@testable
class MyTestableClass {// ...}

function testable(target) {target.isTestable = true;}

MyTestableClass.isTestable // true

间接能够应用,装璜器行为

@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;

工厂模式

一个工厂能生产好多不同的产品,最常见的工厂函数就是 jQ 的 $() 函数,每一个函数的后果都是一个须要的产品。

function Product(name) {this.name = name;}
Product.prototype.init = function () {console.log('init');
}
Product.prototype.go = function () {console.log('go');
}

function Factory () {}
Factory.prototype.add = function(name) {return new Product(name);
}

//use
let f = new Factory();
let a = f.add('a');

console.log(a.name);
a.init();
a.go();

适配器模式

Adapter,将一个类(对象)的接口(办法或者属性)转化为另一个接口,以满足用户需要,使类(对象)之间接口的不兼容问题通过适配器得以解决

function Person () {}
Person.prototype.Say = function() {throw new Error("该办法必须被重写!")
}
Person.prototype.Walk = function() {throw new Error("该办法必须被重写!")
}

function Dog () {}
Dog.prototype.Walk = function() {throw new Error("该办法必须被重写!")
}
Dog.prototype.shout = function() {throw new Error("该办法必须被重写!")
}

function PersonA () {Person.apply(this)
}
PersonA.prototype = new Person()
PersonA.prototype.Say = function() {console.log('Person say')
}
PersonA.prototype.Walk = function() {console.log('Person Walk')
}

function DogBlack () {Dog.apply(this)
}
DogBlack.prototype = new Dog()
DogBlack.prototype.Walk = function() {console.log('Dog Walk')
}
DogBlack.prototype.shout = function() {console.log('Dog Shout')
}

// 当初心愿 Dog 类也能够学会 Say, 并且多走几步

function DogSayAdapter (DogClass) {Dog.apply(this)
  this.DogClass = DogClass
}
DogSayAdapter.prototype = new Dog()
DogSayAdapter.prototype.Say = function() {this.DogClass.shout()
}
DogSayAdapter.prototype.Walk = function() {this.DogClass.Walk()
  this.DogClass.Walk()}

var personA = new PersonA()
var dogBlack = new DogBlack()
var dogSay = new DogSayAdapter(dogBlack)

personA.Say()
personA.Walk()
dogBlack.Walk()
dogBlack.shout()

dogSay.Say()
dogSay.Walk()//walk * 2    

适配器不只是函数接口,还有数据格式的适配

在前后端数据传递时,罕用到适配器模式,也就是通俗易懂的格式化数据,format 函数等等

vue 的 computed 计算属性也是适配器模式的一种实现

const originData = [
    {
        title: 'title',
        age: 18,
        content: ['123',321],
        callback: function(){console.log(this)
        }
    },
  {
        title: 'title2',
        age: 1,
        content: ['1',3],
        callback: function(){console.log('title2')
        }
    }
]

function dataAdapter(data) {
  return data.map(item => {
    return {
      title: item.title,
      content: item.content.join(','),
      init: item.callback
    }
  })
}

var formatData = dataAdapter(originData)

e.g: 原始 data 的数据不满足以后的要求,通过适配器,把数据格式化成想要的格局,对原始数据没有扭转

单例模式

function Simple (name) {this.name = name}
Simple.prototype.go = function() {
  this.name = 'go'
  console.log(this.name)
}

//static 静态方法
Simple.getInstance = (function() {
  var ins
  return function(name){if (!ins) {ins = new Simple(name)
    }
    return ins
  }
})()

let a = Simple.getInstance('a') // name: a
let b = Simple.getInstance('b') // name: a

b===a//true

非单例模式下,雷同的 new Simple() 构造函数,不相等。

通过闭包只创立一次 Simple 实例,大家专用一个。

惰性单例模式

惰性和懒加载 lazyload 类似,提早加载,或者说须要时再加载,不然一次加载过多,频繁进行操作 dom 影响性能

只管上述代码有 Simple.getInstance 办法,能够在须要时再进行实例化,但依然不是一个好的实现形式。

能够将惰性加载的局部提取进去。

e.g:

var simple = function(fn) {
    var instance;
    return function() {return instance || (instance = fn.apply(this, arguments));
    }
};
// 创立遮罩层
var createMask = function(){
    // 创立 div 元素
    var mask = document.createElement('div');
    // 设置款式
    mask.style.position = 'fixed';
    mask.style.top = '0';
      ...
    ...
    document.body.appendChild(mask);
    // 单击暗藏遮罩层
    mask.onclick = function(){this.style.display = 'none';}
    return mask;
};

// 创立登陆窗口
var createLogin = function() {
    // 创立 div 元素
    var login = document.createElement('div');
    // 设置款式
    login.style.position = 'fixed';
    login.style.top = '50%';
      ...
    ...
    login.innerHTML = 'login it';
    document.body.appendChild(login);

    return login;
};

document.getElementById('btn').onclick = function() {var oMask = simple(createMask)();
    oMask.style.display = 'block';
    var oLogin = simple(createLogin)();
    oLogin.style.display = 'block';
}

总结

对五种常见罕用的设计模式进行了学习,这几种很多时候都会用到,接下来还会持续学习其余的 18 种设计模式,可能有的设计模式不肯定在理论敲码中应用,学了没害处,总能用得上嗷!

网上对于设计模式的文章,书籍层出不尽,但看得再多,不如本人了解,并且理论应用。很多时候是几种设计模式交融在一起应用,如果不是本人去写一遍,了解一遍,可能常见的设计模式都了解不了。这样就太惋惜了,发现洁净整洁的代码,都说不出哪里好,就是看着难受,悦目,运行速度快 …

正文完
 0