创建时间:2019-12-18

对一些常见设计模式的理解与实现(主要为代码实现)

设计模式作用:常见问题可重用解决方案,编程模板;使代码更易理解,维护

1. 工厂模式

2. 单例模式

3. 模块模式

4. 代理模式

5. 发布订阅模式 (观察者模式)

 工厂模式

目的是为了创建对象,定义用于创建对象的接口

简单工厂模式:创建同一类对象,解决相似问题(创建的对象数量较少,对象的创建逻辑不复杂时使用)

```js

functionsimpleFactory({name:name='hew', score:score=123} = {}) {

const obj = {}

    obj.name = name

    obj.score = score

    obj.fn=function () {

console.log(`${this.name}:${this.score}`);

    }

return obj

}

console.log(simpleFactory().fn()) 

```

工厂方法模式 对象实例化推迟到子类中

```js

classFactory {

constructor({ name: name='hew', subject: subject='chinese' } = {}) {

this.name = name

this.subject = subject

if(new.target === Factory) {

thrownewError('抽象类不能实例化');

        }

    }

}

classChildextendsFactory {

constructor(params, score){

super(params)

this.score = score

    }

create(type) {

switch(type) {

case1: returnnewChild({name: 'hee'}, 333); break;

default: returnnewChild({name: 'trump'}, 444)

        }

    }

}

const child =newChild()

console.log(child.create(2))

```

抽象工厂模式 对象实例化推迟到子类中

```JS

classFactory {

constructor({ name: name='hew', subject: subject='chinese' } = {}) {

this.name = name

this.subject = subject

if(new.target === Factory) {

thrownewError('抽象类不能实例化');

        }

    }

}

classChildOneextendsFactory {

constructor(params, score){

super(params)

this.score = score

    }

execut() {

console.log('excute1');

    }

}

classChildTwoextendsFactory {

constructor(params, score){

super(params)

this.score = score

    }

execut() {

console.log('excute2');

    }

}

functionswitchFactory(type) {

switch(type) {

case1: returnnewChildOne({name: 'hee'}, 333); break;

default: returnnewChildTwo({name: 'trump'}, 444)

    }

}

console.log(switchFactory(2))

````

构造函数模式

```js

class Factory {

    constructor({ name: name = 'hew', subject: subject='chinese', score:score = 100 }) {

        this.name = name

        this.subject = subject

        this.score = score

    }

    add() {

        return  `${this.name} : ${this.subject} - ${this.score}`

    }

}

console.log(new Factory({name:'hew'}));

console.log(new Factory({name:'trump'}).add());

```

 单例模式

只需要一个的对象(如浏览器中的window等), 只有一个实例,全局访问

应用场景:管理模块;命名空间,减少全局变量数量

export default 也满足单例模式

利用类和闭包来实现

```js

classSingleConstruct {

constructor(name) {

this.name = name

    }

getName() {

returnthis.name

    }

}

const Single = (function() {

let once =null

returnfunction(name) {

if(!once) {

            once =newSingleConstruct(name)

        }

return once

    }          

})()

const a =newSingle('hew')

// 传入的参数 trump 无任何作用

const b =newSingle('trump')

console.log(a === b)  // true

```

弹窗实例(惰性单例实现)惰性单例:点击或需要使用时才创建

```html

 <buttonid="btn">打开弹窗</button>

```

```js

const createEle = (function() {

let once =null

returnfunction() {

if (!once) {

const div = document.createElement('div')

            div.innerHTML ='我是弹窗'

            div.addEventListener('click', function() {

this.setAttribute('style', 'display:none')

            })

            document.body.append(div)

            once = div

        }

return once

    }

})()

document.getElementById('btn').addEventListener('click', function() {

// 每次点击都是操作的同一个div

const div =createEle()

    div.setAttribute('style', 'display:block')

})

```

 模块模式

对象字面量方式

```js

const moduleObject = {

    name: 'modeule',

    config: {

        version: 'v0.0.0'

    },

getName: function() {

console.log('function getName');

    }

}

console.log(moduleObject.name);

console.log(moduleObject.getName());

```

匿名函数形式

```js

const modulePattern = (function() {

const privateCount =1122

constprivateFn=function() {

console.log('private funnction');

    }

return {

        variable: 'var',

method1: function(){

console.log(privateCount);

        },

method2: function() {

console.log('method2');

        }

    }

})()

console.log(modulePattern.privateCount); //undefined

console.log(modulePattern.method1()); // 1122

```

 代理模式

提供一个代理对象,可以访问某个对象中的方法

简单示例

```js

// 老板找人替自己板砖

classStaff{

constructor(name) {

this.staff = name

    }

}

classBoss{

constructor() {

this.boss ='Hew'

    }

liftingBrick(who) {

console.log(`${who.staff} help boss ${this.boss} lifting brick`);

    }

}

classProxyLiftingBrick{

liftingBrick(staff){

newBoss().liftingBrick(staff)

    }

}

const plb =newProxyLiftingBrick()

plb.liftingBrick(newStaff('Trump'))

```

// 图片加载

```js

// 创建img标签元素

const createImgEle = (function() {

const img = document.createElement('img')

    document.body.appendChild(img)

return {

setSrc: function(url) {

            img.src = url

        }

    }

})()

// 代理加载图片

const proxyLoadImg = (function() {

const imgObj =newImage()

    imgObj.onload=function() {

setTimeout(() => {

            createImgEle.setSrc(this.src)

        }, 2000);

    }

return {

setSrc: function(url) {

// 默认图

            createImgEle.setSrc('http://img2.imgtn.bdimg.com/i...')

            imgObj.src = url

        }

    }

})()        

proxyLoadImg.setSrc('http://pic.58pic.com/58pic/15..._1024.jpg')

```

 发布订阅模式

```js

classSubscribe{

constructor() {

this.subscribers = {}

    }

/** 添加订阅者 */

addSubscriber(key, subscriber) {

if(!this.subscribers[key]) {

this.subscribers[key] = []

        }

this.subscribers[key].push(subscriber)

    }

/** 删除订阅者 */

removeSubscriber(key) {

if(this.subscribers[key]) {

this.subscribers[key].splice(0,this.subscribers[key].length)

        } else {

console.error('删除:没有订阅');

        }

    }

/** 通知订阅者 */

informSubscriber= (key, msg) => {

if(this.subscribers[key] &&this.subscribers[key].length) {

this.subscribers[key].forEach(v=> {

v(msg)

            })

        } else {

console.error('通知:没有订阅');

        }

    }

/** 删除订阅者 */

}

const sub =newSubscribe();

sub.addSubscriber('s1', (msg) => {

console.log('s1 msg:', msg)

})

sub.addSubscriber('s1', (msg) => {

console.log('s1 msg 2:', msg)

})

sub.addSubscriber('s2', (msg) => {

console.log('s2 msg', msg)

})

sub.informSubscriber('s1', '来自s1的信息')

sub.removeSubscriber('s1')

sub.informSubscriber('s1', '来自s11的信息')

sub.informSubscriber('s2', '来自s2的信息')

```

优缺点:结构清晰,解耦较好;当有大量数据时,订阅过程比较消耗内存和时间

> 欢迎交流 [Github](https://github.com/WarrenHewi...


Warren
91 声望2 粉丝