JavaScript設(shè)計(jì)模式手寫示例講解
想分享的幾種設(shè)計(jì)模式
目前模式:工廠模式,單例模式,適配器模式,裝飾者模式,建造者模式
建造者模式
簡介:建造者模式(builder pattern)比較簡單,它屬于創(chuàng)建型模式的一種。
白話:4個(gè)部分:有個(gè)產(chǎn)品,有個(gè)工廠可以造產(chǎn)品,有個(gè)設(shè)計(jì)師指揮造多少,有個(gè)人想買產(chǎn)品。
買產(chǎn)品的用戶不介意產(chǎn)品制造流程,只需要產(chǎn)品!
function Cola() {
this.sugar = '50g',
this.water = '100g'
}
function Packing() { // 第一種打包方式
this.createPkg = function(){
console.log('創(chuàng)建可樂外皮')
}
this.pushCola = function() {
console.log('可樂倒進(jìn)瓶子')
}
this.complete = function() {
var cola = new Cola()
cola.complete = true
return cola
}
this.init = function() {
this.createPkg() // 創(chuàng)建外皮
this.pushCola() // 倒進(jìn)瓶子
//還可以增加其他步驟
return this.complete() // 制作完成
}
}
function greenPacking() { //綠皮可樂打包方式
this.createPkg = function(){
console.log('創(chuàng)建green可樂外皮')
}
this.pushCola = function() {
console.log('可樂倒進(jìn)green瓶子')
}
this.complete = function() {
var cola = new Cola()
cola.complete = true
return cola
}
this.init = function() {
this.createPkg() // 創(chuàng)建外皮
this.pushCola() // 倒進(jìn)瓶子
//還可以增加其他步驟
return this.complete() // 制作完成
}
}
function Boss() {
this.createCola = function(packType) {
const pack = new window[packType]
this.product = pack.init() //完整產(chǎn)品產(chǎn)出
}
this.getCola = function(packType) {
this.createCola(packType);
return this.product
}
}
const boss = new Boss()
var UserCola = boss.getCola('greenPacking') // UserCola.complete === true
其他東西都不要,只要最后生產(chǎn)好的Cola,有sugar,有water。
關(guān)鍵在于Boss 函數(shù)中,擔(dān)任一個(gè)整合的職責(zé)
同樣的Boss函數(shù),我可以通過更換Packing函數(shù),打包方式,獲得不同樣式的Cola。
通過給getCola函數(shù)傳入不同想要的參數(shù),獲得不同的最終產(chǎn)品。實(shí)現(xiàn)了可插拔的函數(shù)結(jié)構(gòu)。
裝飾者模式
裝飾者提供比繼承更有彈性的替代方案。 裝飾者用用于包裝同接口的對(duì)象,不僅允許你向方法添加行為,而且還可以將方法設(shè)置成原始對(duì)象調(diào)用(例如裝飾者的構(gòu)造函數(shù))。
裝飾者用于通過重載方法的形式添加新功能,該模式可以在被裝飾者前面或者后面加上自己的行為以達(dá)到特定的目的。
好處:
裝飾者是一種實(shí)現(xiàn)繼承的替代方案。當(dāng)腳本運(yùn)行時(shí),在子類中增加行為會(huì)影響原有類所有的實(shí)例,而裝飾者卻不然。取而代之的是它能給不同對(duì)象各自添加新行為。參考前端手寫面試題詳細(xì)解答
function iwatch () {
this.battery = 100;
this.getBattery = function() {
console.log(this.battery)
}
}
iwatch.prototype.getNewPart = function(part) {
this[part].prototype = this; //把this對(duì)象上的屬性 指向 新對(duì)象的prototype
return new this[part]; //返回一個(gè)新對(duì)象,不修改原對(duì)象,新增了新對(duì)象的屬性
}
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;
工廠模式
一個(gè)工廠能生產(chǎn)好多不同的產(chǎn)品,最常見的工廠函數(shù)就是jQ的$()函數(shù),每一個(gè)函數(shù)的結(jié)果都是一個(gè)需要的產(chǎn)品。
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,將一個(gè)類(對(duì)象)的接口(方法或者屬性)轉(zhuǎn)化為另一個(gè)接口,以滿足用戶需求,使類(對(duì)象)之間接口的不兼容問題通過適配器得以解決
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')
}
//現(xiàn)在希望Dog類也可以學(xué)會(huì)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
適配器不只是函數(shù)接口,還有數(shù)據(jù)格式的適配
在前后端數(shù)據(jù)傳遞時(shí),常用到適配器模式,也就是通俗易懂的格式化數(shù)據(jù),format函數(shù)等等
vue的computed計(jì)算屬性也是適配器模式的一種實(shí)現(xiàn)
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 的數(shù)據(jù)不滿足當(dāng)前的要求,通過適配器,把數(shù)據(jù)格式化成想要的格式,對(duì)原始數(shù)據(jù)沒有改變
單例模式
function Simple (name) {
this.name = name
}
Simple.prototype.go = function() {
this.name = 'go'
console.log(this.name)
}
//static靜態(tài)方法
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()構(gòu)造函數(shù),不相等。
通過閉包只創(chuàng)建一次Simple實(shí)例,大家公用一個(gè)。
惰性單例模式
惰性和懶加載lazyload相似,延遲加載,或者說需要時(shí)再加載,不然一次加載過多,頻繁進(jìn)行操作dom影響性能
盡管上述代碼有Simple.getInstance方法,可以在需要時(shí)再進(jìn)行實(shí)例化,但仍然不是一個(gè)好的實(shí)現(xiàn)方式。
可以將惰性加載的部分提取出來。
e.g:
var simple = function(fn) {
var instance;
return function() {
return instance || (instance = fn.apply(this, arguments));
}
};
// 創(chuàng)建遮罩層
var createMask = function(){
// 創(chuàng)建div元素
var mask = document.createElement('div');
// 設(shè)置樣式
mask.style.position = 'fixed';
mask.style.top = '0';
...
...
document.body.appendChild(mask);
// 單擊隱藏遮罩層
mask.onclick = function(){
this.style.display = 'none';
}
return mask;
};
// 創(chuàng)建登陸窗口
var createLogin = function() {
// 創(chuàng)建div元素
var login = document.createElement('div');
// 設(shè)置樣式
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';
}
總結(jié)
對(duì)五種常見常用的設(shè)計(jì)模式進(jìn)行了學(xué)習(xí),這幾種很多時(shí)候都會(huì)用到,接下來還會(huì)繼續(xù)學(xué)習(xí)其他的18種設(shè)計(jì)模式,可能有的設(shè)計(jì)模式不一定在實(shí)際敲碼中使用,學(xué)了沒壞處,總能用得上嗷!
網(wǎng)上對(duì)于設(shè)計(jì)模式的文章,書籍層出不盡,但看得再多,不如自己理解,并且實(shí)際使用。很多時(shí)候是幾種設(shè)計(jì)模式融合在一起使用,如果不是自己去寫一遍,理解一遍,可能常見的設(shè)計(jì)模式都理解不了。這樣就太可惜了,發(fā)現(xiàn)干凈整潔的代碼,都說不出哪里好,就是看著舒服,順眼,運(yùn)行速度快…
到此這篇關(guān)于JavaScript設(shè)計(jì)模式手寫示例講解的文章就介紹到這了,更多相關(guān)JS設(shè)計(jì)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
動(dòng)態(tài)生成js類的實(shí)現(xiàn)方法
動(dòng)態(tài)生成js類的實(shí)現(xiàn)方法...2007-03-03
Bootstrap在線電子商務(wù)網(wǎng)站實(shí)戰(zhàn)項(xiàng)目5
這篇文章主要為大家分享了Bootstrap在線電子商務(wù)網(wǎng)站實(shí)戰(zhàn)項(xiàng)目,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
動(dòng)態(tài)的綁定事件addEventListener方法的使用
本文為大家介紹下動(dòng)態(tài)的綁定事件的方法addEventListener的使用示例,不了解的朋友可以參考下2014-01-01
解決一個(gè)微信號(hào)同時(shí)支持多個(gè)環(huán)境網(wǎng)頁授權(quán)問題
由于微信限制一個(gè)服務(wù)號(hào)只能配置一個(gè)網(wǎng)頁授權(quán)域名, 又不可能給每個(gè)環(huán)境單獨(dú)配一個(gè)服務(wù)號(hào),這樣不僅需要成本而且很浪費(fèi)資源,下面小編給大家?guī)砹私鉀Q一個(gè)微信號(hào)同時(shí)支持多個(gè)環(huán)境網(wǎng)頁授權(quán)問題,感興趣的朋友一起看看吧2019-08-08
wangEditor富文本編譯器插件學(xué)習(xí)系列之工具欄配置
這篇文章主要給大家介紹了關(guān)于wangEditor富文本編譯器插件學(xué)習(xí)系列之工具欄配置的相關(guān)資料,wangEditor是一款基于原生JavaScript封裝,開源免費(fèi)的富文本編輯器,支持常規(guī)的文字排版操作、插入圖片、插入視頻、插入代碼等功能,需要的朋友可以參考下2023-12-12
TypeError: Cannot set properties of 
這篇文章主要介紹了TypeError: Cannot set properties of undefined (setting ‘xx‘)的問題,本文給大家分享完美解決方案,需要的朋友可以參考下2023-09-09
網(wǎng)站導(dǎo)致瀏覽器崩潰的原因總結(jié)(多款瀏覽器) 推薦
對(duì)于訪客,如果登錄您網(wǎng)站,瀏覽器就立刻崩潰,我想這對(duì)誰都是無法容忍的,對(duì)此總結(jié)了網(wǎng)站導(dǎo)致瀏覽器崩潰的原因2010-04-04

