javascript 设计模式简述

214 阅读4分钟

工厂模式 ☆

  • 将new 操作单独封装
  • 遇到new时,就要考虑是否使用工厂模式了 商店封装做汉堡的工作,消费者直接购买汉堡,不用知道具体的生产过程。 示例:
class Product {
    constructor(name){
    	this.name = name
    }
    init(){}
    fn1(){}
}

class Creator {
    create(name){
    	return new Product(name)
    }
}
// 测试 根本不用知道Product 
let creator = new Create()
let p1 = creator.create('p1')
p1.init

// demo2 React.createElement 
class Vnode(tag, attrs, children){
	// ...
}
React.createElement = function(tag, attrs, children){
	return new Vnode(tag, attrs, children)
}

构造函数和创建者分离,符合开发封闭原则。

单例模式

  • 系统中被唯一使用
  • 一个类只有一个实例 (obj1 === ojb2) 像登录框、购物车,自执行函数的一种应用
class SingleObject {
    login() {
    	console.log('login ...')
    }
    xx(){}
}
SingleObject.getInstance = (function(){
    let instance
    return function(){
    	if(!instance){
        	instance = new SingleObject()
        }
        return instance
    }
})()
// test
s1 = SingleObject.getInstance()
s2 = SingleObject.getInstance()

符合单一职责原则,只实例化唯一的对象

适配器模式

  • 旧接口格式与使用者不兼容
  • 中间加一个适配转换接口,即转换、适配思想
let $ = {
    ajax: function(opt){
    	return ajax(opt)
    }
}
$.ajax({}) 就与之前jq的适配了

装饰器模式 es7 装饰器 ☆

  • 为对象添加新功能
  • 不改变其原有的结构和功能
class Circle {
    draw() {}
}
class Decorator {
    constructor(circle){
    	this.circle = circle
    }
    draw(){
    	this.circle.draw()
        // 装饰
        this.addRed(this.circle)
    }
    addRed(){}
}

ES7 装饰器Demo

@testDec
class Demo {
	// ...
}
function testDec(target){
	target.isDec = true
}
console.log(Demo.isDec) // true
//2、 也可带参数的装饰器
function testDec(isDec){
	return function (target){
    	target.isDec = isDec
    }
}

@testDec(false)
class Demo {
}
console.log(Demo.isDec)

// 3、 装饰类 -- mixin 示例
function mixins(...list){
	return function(target){
    	Object.assign(target.prototype, ...list)
    }
}

const Foo = {
	foo(){
    	console.log('foo')
    }
}

@mixins(Foo)
class MyClass {}

let obj = new MyClass()
obj.foo()
// 4、 案例
function log(target, name, descriptor){
    let oldValue = descriptor.value
    descriptor.value = function(){
    	console.log(`callingxxx`)
        return oldValue.apply(this, arguments)
    }
    return descriptor
}

class Math {
    @log
    add(a, b){
    	return a + b
    }
}

let math = new Math()
const result = math.add(2,3)

装饰器原理

@decorator
class A {}

// 等同于
class A {}
A = decorator(A) || A

core-decorators 装饰器类库,封装了常用的来类库。

import { readonly } from 'core-decorators'
class Person {
    @readonly
    name() {
    	return 'zhang'
    }
}

let p = new Person()
p.name = xxx // 会报错,装饰了readonly.

利用deprecate装饰器给控制台提示信息

import { deprecate } from 'core-decorators'
class Person {
    @deprecate('即将弃用')
    name() {
    	return 'xxx'
    }
}
将现有对象和装饰器分离。

www.jianshu.com/p/1471ec511…

代理模式

  • 使用者无权访问目标对象,中间加代理,通过代理做授权和控制 案例:
class ReadImg {
    constructor(fileName){
    	this.fileName = fileName
    }
    display(){}
    loadImg(){}
}
class ProxyImg {
    constructor(fileName){
    	this.realImg = new ReadImg(fileName)
    }
    display(){
    	this.realImg.display()
    }
}

明星&经纪人案例

let star = {
    name: '张xx',
    age: 25,
    phone: 123111111
}

let agent = new Proxy(star, {
    get: function(target, key){
    	if(key === 'phone'){
        	return 'xxx'
        }
        if(key === 'price'){
        	return 12000
        }
        return target[key]
    },
    set: function(target, key, value){
    	if(key === 'customPrice'){
        	if(val < 10000){
            	throw new Error('价格太低')
            } else {
            	target[key] = val
                return true
            }
        }
    }
	
})

代理类和目录类分离

外观模式

  • 为子系统中的一组接口提供一个高层接口
  • 使用者使用这个高层接口

观察者模式 ☆

  • 发布 & 订阅
  • 一对多
class Subject {
    constructor(){
    	this.state = 0
        this.observers = []
    }
    getState(){
    	return this.state
    }
    setState(state){
    	this.state = state
        // 通知所有观察者
        this.notifyAllObservers()
    }
    notifyAllObservers(){
    	this.observers.forEach( observer => {
        	observer.update()
        })
    }
    attach(observer){
    	this.observer.push(observer)
    }
}

// 观察者
class Observer {
    constructor(name, subject){
    	this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update(){
    	console.log(`xxxxx`)
    }
}

// 测试
let s = new Subject()
// 2个观察者
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)

// demo  nodejs  自定义事件
const EventEmitter = require('events').EventEmitter
const emitter1 = new EvevntEmitter()

emitter1.on('some', ()=> {})
emitter1.on('some', ()=> {})
emitter1.emit('some')
// demo2 任何构造函数都可以继承 EventEmitter 的方法 on emit
const EventEmitter = require('events').EventEmitter
class Dog extends EventEmitter {
    constructor(name){
    	super()
        this.name = name
    }
}
let simon = new Dog('simon')
simon.on('methodsxx', ()=>{
})
simon.emit('methodsxx')

// vue react 生命周期也类似

迭代器模式

  • 顺序访问一个集合
  • 使用者无需知道集合的内部结构(封装)
class Iterator {
    constructor(container){
    	this.list = container.list
        this.index = 0
    }
    next(){
    	if(this.hasNext()){
        	return this.list[this.index++]
        }
        return null
    }
    hasNext(){
    	if(this.index >= this.list.length){
        	return false
        }
        return true
    }
}

class Container {
    constructor(list){
    	this.list = list
    }
    // 生成遍历器
    getIterator(){
    	return new Iterator(this)
    }
}

let arr = [1,2,3,4,5]
let container = new Container(arr)
let iterator = container.getIterator()
while(iterator.hasNext()){
	// xxxx
}

ES6 Iterator 为何存在? es中,有序集合的数据类型有很多。 object 不是有序集合,可以用Map 代替 for(let item of data){} // 遍历迭代器

function each(data){
    let iterator = data[Symbol.iterator]()
    iterator.next() // {value: 1, done: false}
    iterator.next() // done  {value: undefined, done: true}
    let item = {done: false}
    while(!item.done){
    	item = iterator.next()
        if(!item.done){
        	// xxx
        }
    }
}

Es6 iterator 与Generator

function* helloworld(){
    yield 'xx';
    yield 'xxx'
    return 'ending'
}

状态模式

  • 一个对象有状态变化
  • 每次状态变化都会触发一个逻辑

class State {
    constructor(color){
    	this.color = color
    }
    handle(context){
    	context.setState(this)
    }
}
// 主体
class Context {
    constructor(){
    	this.state = null
    }
    getState(){
    	return this.state
    }
    setState(state){
    	this.state = state
    }
}

// 测试
let context = new Context()
let green = new State('green')
// 绿灯亮了
green.handle(context)

Javascript State Machine 库状态管理

var fsm = new StateMachine({
  init: 'solid',
  transitions: [
    { name: 'melt',     from: 'solid',  to: 'liquid' },
    { name: 'freeze',   from: 'liquid', to: 'solid'  },
    { name: 'vaporize', from: 'liquid', to: 'gas'    },
    { name: 'condense', from: 'gas',    to: 'liquid' }
  ],
  methods: {
    onMelt:     function() { console.log('I melted')    },
    onFreeze:   function() { console.log('I froze')     },
    onVaporize: function() { console.log('I vaporized') },
    onCondense: function() { console.log('I condensed') }
  }
});

单一原则、开放封闭

设计模式案例:

  • 单例更多的用在,像弹窗、广告下载组件,保证只new 一次
  • 适配器模式, 像对以前的$.ajax 进行适配 let $= {ajax{return aa()}}、 axios 请求参数适配器,对请求的工程参数进行适配
let adaptor = null
if(weex){
	adaptor = weexAdaptor
}else if(wechat){
	adaptor = wechatAdaptor
}
export default adaptor
  • 装饰器模式,原有方法上再挂载其他方法来满足现有需求。像log\readonly 属性

juejin.cn/post/684490…