创建时间: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...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。