Javascript 设计模式系统讲解与应用学习总结

面向对象

概念

  • 三要素:继承 封装 多态
// 类,即模板
class People {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    eat() {
        alert(`${this.name} eat something`)
    }
    speak() {
        alert(`My name is ${this.name}, age ${this.age}`)
    }
}

//对象(实例)
let zhang = new People('zhang', 20)
zhang.eat()
zhang.speak()

let wang = new People('wang', 21)
wang.eat()
wang.speak()
  • 继承,子类继承父类
// 父类
class People {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    eat() {
        alert(`${this.name} eat something`)
    }
    speak() {
        alert(`My name is ${this.name}, age ${this.age}`)
    }
}
// 子类继承父类
class Student extends People {
    constructor(name, age, number) {
        super(name, age)
        this.number = number
    }
    study() {
        alert(`${this.name} study`)
    }
}
// 实例
let xiaoming = new Student('xiaoming', 10, 'A1')
xiaoming.study()
console.log(xiaoming.number)
let xiaohong = new Student('xiaohong', 11, 'A2')
xiaohong.study()

1.people是父类,公共的,不仅仅服务于student
2.继承可将公共方法抽离出来,提高复用,减少冗余

  • 封装,数据的权限和保密
    1.public 完全开放
    2.protected 对子类开放
    3.private 对自己开放
class Student extends People {
    number
    private girlfriend
    constructor(name, age, number) {
        super(name, age)
        this.number = number
        this.girlfriend = 'xiaoli'
    }
    study() {
        alert(`${this.name} study`)
    }
}

1.减少耦合,不该露的不外露
2.利于数据,接口的权限管理
3.es6目前不支持,需要typescript支持,目前一般认为_开头的方法为私有

  • 多态,统一接口不同实现
    1.保持子类的开放性和灵活性,面向接口编程,js应用极少
    2.需要结合java等语言的接口、重写、重载等功能

js的应用举例

// jquery模拟
class jQuery {
    constructor(selector) {
        let slice = Array.prototype.slice
        let dom = slice.call(document.querySelectorAll(selector))
        let len = dom ? dom.length : 0
        for (let i = 0; i < len; i++) {
            this[i] = dom[i]
        }
        this.length = len
        this.selector = selector || ''
    }
    append(node) {

    }
    addClass(name) {

    }
    html(data) {

    }
    // 此处省略若干 API
}
window.$ = function (selector) {
    return new jQuery(selector)
}

面向对象的意义

1.程序执行:顺序、判断、循环---结构化
2.面向对象 ---数据结构化
3.对于计算机,结构化的才是最简单的
4.编程应该 简单&抽象

设计原则

描述

  • 即按照哪一种思路或者标准来实现功能
  • 功能相同,可以有不同设计方案来实现
  • 随着需求的增加,设计的作用才能体现出来

UNIX/LINUX设计哲学

  • 准则1:小即是美
  • 准则2:让每个程序只做好一件事
  • 准则3:快速建立原型
  • 准则4:舍弃高效率而取可移植性
  • 准则5:采用纯文本来储存数据
  • 准则6:充分利用软件的杠杆效应(软件复用)
  • 准则7:使用shell脚本来提高杠杆效应和可移植性
  • 准则8:避免强制性的用户界面
  • 准则9:让每个程序都称为过滤器
  • 小准则:允许用户定制环境
  • 小准则:尽量使操作系统内核小而轻量化
  • 小准则:使用小写字母并尽量简短
  • 小准则:沉默是金
  • 小准则:各部分之和大于整体
  • 小准则:寻求90%的解决方案

S O L I D 五大设计原则

  • S - 单一职责原则
    1.一个程序只做好一件事
    2.如果功能过于复杂就拆分开,每个部分保持独立
  • O - 开放封闭原则
    1.对扩展开放,对修改封闭
    2.增加需求时,扩展新代码,而非修改已有代码
    3.这是软件设计的终极目标
  • L - 李氏置换原则
    1.子类能覆盖父类
    2.父类能出现的地方子类就能出现
    3.js中使用较少(弱类型&继承使用较少)
  • I - 接口独立原则
    1.保持接口的单一独立,避免出现“胖接口”
    2.js中没有接口(typescript例外),使用较少
    3.类似于单一职责原则,这里更关注接口
  • D - 依赖导致原则
    1.面向接口编程,依赖于抽象而不依赖于具体
    2.使用方只关注接口而不关注具体类的实现
    3.js中使用较少(没有接口&弱类型)

23种设计模式介绍

创建型

  • 工厂模式(工厂方法模式,抽象工厂模式,建造者模式)
  • 单例模式
  • 原型模式

结构型

  • 适配器模式
  • 装饰器模式
  • 代理模式
  • 外观模式
  • 桥接模式
  • 组合模式
  • 享元模式

行为型

  • 策略模式
  • 迭代器模式
  • 模板方法模式
  • 职责链模式
  • 观察者模式
  • 命令模式
  • 备忘录模式
  • 中介者模式
  • 状态模式
  • 解释器模式
  • 访问者模式

设计模式详解

工厂模式

  • 将new操作单独封装
  • 遇到new时,就要考虑是否使用工厂模式

示例

  • 你去购买汉堡,直接点餐、取餐,不会自己亲手做
  • 商店要“封装”做汉堡的工作,做好直接给买者
class Product {
  constructor (name) {
    this.name = name
  }
  init() {
    alert("init")
  }
  fun1() {
    alert("fun1")
  }
  fun2() {
    alert("fun1")
  }
}

class Creator {
  create (name) {
    return new Product(name)
  }
}

// 测试
let creator = new Creator()
let p = creator.create('p1')
p.init()
p.fun1()

单例模式

  • 系统中被唯一使用
  • 一个类只有一个实例

示例

  • 登录框
  • 购物车
class SingleObject {
    login() {
        console.log('login...')
    }
}
SingleObject.getInstance = (function () {
    let instance
    return function () {
        if (!instance) {
            instance = new SingleObject();
        }
        return instance
    }
})()

// 测试
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()
console.log(obj1 === obj2)
class LoginForm {
    constructor() {
        this.state = 'hide'
    }
    show() {
        if (this.state === 'show') {
            alert('已经显示')
            return
        }
        this.state = 'show'
        console.log('登录框已显示')
    }
    hide() {
        if (this.state === 'hide') {
            alert('已经隐藏')
            return
        }
        this.state = 'hide'
        console.log('登录框已隐藏')
    }
}
LoginForm.getInstance = (function () {
    let instance
    return function () {
        if (!instance) {
            instance = new LoginForm();
        }
        return instance
    }
})()

// 一个页面中调用登录框
let login1 = LoginForm.getInstance()
login1.show()
// login1.hide()

// 另一个页面中调用登录框
let login2 = LoginForm.getInstance()
login2.show()

// 两者是否相等
console.log('login1 === login2', login1 === login2)

设计原则验证

  • 符合单一职责原则,只实例化唯一的对象
  • 没法具体开放封闭原则,但是绝对不违反开发封闭原则

适配器模式

介绍

  • 旧接口格式和使用者不兼容
  • 中间加一个适配器转换接口

实例

image.png
class Adaptee {
  specificRequest() {
    return '德国标准的插头'
  }
}
class Target {
  constructor () {
    this.adaptee = new Adaptee()
  }
  request() {
    let info = this.adaptee.specificRequest()
    return `${info} -> 转换器 -> 中国标准的插头`
  }
}

// 测试
let target = new Target()
target.request()

场景

  • 封装旧接口
  • vue computed

设计原则验证

  • 将旧接口和使用者进行分离
  • 符合开发封闭原则

装饰器模式

介绍

  • 为对象添加新功能
  • 不改变其原因的结构和功能

示例

image.png

场景

  • es7装饰器
  • core-decorators

代码示例

// 装饰类
//一个简单的demo
@testable
class MyTestableClass {
  // ...
}

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

alert(MyTestableClass.isTestable) // true
// 装饰类 mixin 示例
function mixins(...list) {
  return function (target) {
    Object.assign(target.prototype, ...list)
  }
}

const Foo = {
  foo() { alert('foo') }
}

@mixins(Foo)
class MyClass {}

let obj = new MyClass();
obj.foo() // 'foo'
// 示例 只读装饰器
import { readonly } from 'core-decorators'

class Person {
    @readonly
    name() {
        return 'zhang'
    }
}

let p = new Person()
alert(p.name())
// p.name = function () { /*...*/ }  // 此处会报错
// 打印日志装饰器
function log(target, name, descriptor) {
  var oldValue = descriptor.value;

  descriptor.value = function() {
    console.log(`Calling ${name} with`, arguments);
    return oldValue.apply(this, arguments);
  };

  return descriptor;
}

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

const math = new Math();
const result = math.add(2, 4);
console.log('result', result);

core-decorators

  • 第三方开源lib
  • 提供常用的装饰器
import { deprecate } from 'core-decorators';

class Person {
  @deprecate
  facepalm() {}

  @deprecate('We stopped facepalming')
  facepalmHard() {}

  @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
  facepalmHarder() {}
}

let person = new Person();

person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.

person.facepalmHard();
// DEPRECATION Person#facepalmHard: We stopped facepalming

person.facepalmHarder();
// DEPRECATION Person#facepalmHarder: We stopped facepalming
//
//     See http://knowyourmeme.com/memes/facepalm for more details.

设计原则验证

  • 将现有对象和装饰器进行分离,两者独立存在
  • 符合开发封闭原则

代理模式

介绍

  • 使用者无权访问目标对象
  • 中间加代理,通过代理做授权和控制

示例

  • 科学上网,访问github.com
  • 明星经纪人
// 明星
let star = {
    name: '张XX',
    age: 25,
    phone: '13910733521'
}

// 经纪人
let agent = new Proxy(star, {
    get: function (target, key) {
        if (key === 'phone') {
            // 返回经纪人自己的手机号
            return '18611112222'
        }
        if (key === 'price') {
            // 明星不报价,经纪人报价
            return 120000
        }
        return target[key]
    },
    set: function (target, key, val) {
        if (key === 'customPrice') {
            if (val < 100000) {
                // 最低 10w
                throw new Error('价格太低')
            } else {
                target[key] = val
                return true
            }
        }
    }
})

// 主办方
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)

// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000
// agent.customPrice = 90000  // 报错:价格太低
console.log('customPrice', agent.customPrice)

观察者模式

介绍

  • 发布&订阅
  • 一对多

示例

  • 点咖啡,点好之后坐等被叫
// 主题,接收状态变化,触发每个观察者
class Subject {
    constructor() {
        this.state = 0
        this.observers = []
    }
    getState() {
        return this.state
    }
    setState(state) {
        this.state = state
        this.notifyAllObservers()
    }
    attach(observer) {
        this.observers.push(observer)
    }
    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }
}

// 观察者,等待被触发
class Observer {
    constructor(name, subject) {
        this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`)
    }
}

// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)

s.setState(1)
s.setState(2)
s.setState(3)


场景

  • 网页事件绑定
  • promise
  • jquery callbacks
  • nodejs 自定义事件

$('#btn1').click(function () {
    console.log(1);
})
$('#btn1').click(function () {
    console.log(2);
})
$('#btn1').click(function () {
    console.log(3);
})

你可能感兴趣的:(Javascript 设计模式系统讲解与应用学习总结)