# 六.设计模式

# 1.介绍一下单一职责原则和开放封闭原则

  • 单一职责原则:一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因
  • 开放封闭原则:核心的思想是软件实体(类、模块、函数等)是可扩展的、但不可修改的。也就是说,对扩展是开放的,而对修改时封闭的

# 2.单例模式

单例模式即一个类只能构造除唯一的实例,单例模式的意义在于共享、唯一,Redux、Vuex中的 store、JQ 的$或者业务场景中的购物车、登录框都是单例模式的应用

class SingletonLongin{
  constructor(name,password){
    this.name=name
    this.password=password
  }
  static.getInstance(name,password){
    if(!this.instance)this.instance = new SingletonLogin(name,password)
    return this.instance
  }
}
let obj1=SingletonLogin.getInstance('sss','111')
let obj2=SingletonLogin.getInstance('qqq','1111')
1
2
3
4
5
6
7
8
9
10
11
12

# 3.工厂模式

工厂模式即对创建对象逻辑的封装,或者可以理解为对 new 的封装,这种封装就像创建对象的工厂,故名工厂模式。工厂模式常见于大型项目,比如 JQ 的$对象,我们创建选择器对象时之所以没有new selector就是因为$()已经是一个工厂方法,其他例子如React.createElement()Vue.component()都是工厂模式的实现。工厂模式有多种:简单工厂模式,工厂方法模式,抽象工厂模式,这里只以简单工厂模式为例

class User {
  constructor(name, auth) {
    this.name = name
    this.auth = auth
  }
}
class UserFactory {
  static createUser(name, auth) {
    if (auth === "admin") new User(name, 1)
    if (auth === "user") new User(name, 2)
  }
}
const admin = UserFactory.createUser("asdf", "1212")
const user = UserFactory.createUser("asdfas", "23423")
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 4.观察者模式

观察者模式概念很简单:观察者监听被观察者的变化,被观察者发生改变时,通知所有的观察者。观察者模式被广泛用于监听事件的实现

class Observer {
  constructor(fn) {
    this.update = fn
  }
}
class Subject {
  constructor() {
    this.observers = []
  }
  addObserver(observer) {
    this.observers.push(observer)
  }
  notify() {
    this.observers.forEach(observer => observer.update())
  }
}
var subject = new Subject()
cosnt update = ()=>{console.log('通知')}
var obj1 = new Observer(update)
var obj2 = new Observer(update)
subject.addObserver(obj1)
subject.addObserver(obj2)
subject.notify()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 5.装饰器模式

装饰器模式,可以理解为对类的一个包装,动态的拓展类的功能,ES7装饰器语法以及 React 中的高阶组件(HoC)都是这一模式的实现。react-redux 的 connect()也运用了装饰器模式,这里以 ES7 装饰器为例:

function info(target){
  target.prototype.name='展示'
  target.prototype.age =10
}
@inifo
class Man()
let man = new Man()
man.name
1
2
3
4
5
6
7
8

# 6.适配器模式

适配器模式,将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作

class Adaptee {
  test() {
    return "旧接口"
  }
}
class Target {
  constructor() {
    this.adaptee = new Adaptee()
  }
  test() {
    let info = this.adaptee.test()
    return `适配${info}`
  }
}
let target = new Target()
console.log(target.test())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 7.代理模式

代理模式,为一个对象找一个替代对象,以便对原对象进行访问。

const idol = {
  name: "1212",
  phone: 1000,
  price: 100000,
}
const agent = new Proxy(idol, {
  get: function (target) {
    return "经纪人电话1000"
  },
  set: function (target, key, value) {
    if (key === "price") {
      if (value < target.price) throw new Error("报价过低")
      target.price = value
    }
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 7. 什么是原型链

  • 对于 object 来说,可以通过proto找到一个原型对象,在该对象中定义了很多函数让我们来使用
  • 原型链是一种机制,指的是 javascript 每个对象包括原型对象都有一个内置proto属性指向创建它的函数对象的原型对象,即 prototype 属性
  • 函数的原型链对象 constructor 默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针proto;该指针是指向上一层的原型对象,而上一层的原型对象的结构依然类似;因此可以利用proto一直指向 object 的原型对象上,而 object 原型对象用 object.prototype=null 表示原型链顶端。如此形成了 js 的原型链继承。同时所有的 js 对象都有 object 的基本方法。

# 8. 类的创建和继承

  • 1.原型链继承
  • 2.构造函数继承
  • 3.组合继承
  • 4.原型式继承
  • 5.寄生式继承
  • 6.寄生组合继承
  • 7.混合继承
  • 8.es6 继承

# 1·原型链继承

function Parent() {
  this.parentName = "parent"
}
Parent.portotype.getParentName = function () {
  return this.parentName + 1
}
function Child() {
  this.name = "child"
}
Child.prototype = new Parent()
Child.prototype.getChildName = function () {
  return this.name + 1
}
var child = new Child()
console.log(child.getParentName())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2.构造函数继承

function Parent() {
  this.parentName = "parent"
}
Parent.prototype.getParentName = function () {
  return this.parentName + 1
}
function Child() {
  this.name = "child"
  Parent.call(this)
}
Child.prototype.getChildName = function () {
  return this.name + 1
}
var child = new Child()
console.log(child.parentName)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.组合继承

function Parent() {
  this.parentName = "parent"
}
Parent.prototype.getParentName = function () {
  return this.parentName + 1
}
function Child() {
  this.name = "child"
  Parent.call(this)
}
Child.prototype = new Parent()
Child.prototype.getChildName = function () {
  return this.name + 1
}
var child = new Child()
console.log(child.getParentName())
console.log(child.parentName)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 4.原型式继承

function Parent() {
  this.parentName = "parent"
}
Parent.prototype.getParentName = function () {
  return this.parentName + 1
}
function object(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
var child = object(new Parent())
child.childName = "child"
child.getChildName = function () {
  this.childName + 1
}
console.log(child.getChildName())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.寄生式继承

function Parent() {
  this.parentName = "parent"
}
Parent.portotype.getParentName = function () {
  return this.parentName + 1
}
function createAnother(original) {
  var clone = Object(original)
  clone.childName = "child"
  clone.getChildName = function () {
    return this.childName + 1
  }
  return clone
}
var child = createAnother(new Parent())
child.prototype = new Parent()
console.log(child.parentName)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6.寄生组合继承

function inheritPrototype(c, p) {
  var prototype = Object.create(p.ptototype)
  prototype.constructor = c
  c.prototype = prototype
}
function Parent() {
  this.parentName = "parent"
}
Parent.prototype.getParentName = function () {
  return this.parentName + 1
}
function Child() {
  this.childName = "child"
  Parent.call(this)
}
inheritPrototype(Child, Parent)
Child.prototype.getChildName = function () {
  return this.childName + 1
}
var child = new Child()
console.log(child.parentName)
console.log(child.getParentName())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 7.混合式继承

function Parent() {
  this.parentName = "parent"
}
Parent.portotype.getParentName = function () {
  return this.parentName + 1
}
function Child() {
  this.name = "child"
}
Child.prototype.getChildName = function () {
  return this.name + 1
}
function MyClass() {
  Parent.call(this)
  Child.call(this)
}
MyClass.prototype = Object.create(Parent.prototype)
Object.assign(MyClass.prototype, Child.prototype)
MyClass.prototype.constructor = MyClass
var child = new MyClass()
console.log(child.getParentName())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 8.es6 中继承

class Parent {
  constructor() {
    this.parentName = "parent"
  }
  getParentName() {
    return this.parentName + 1
  }
}
class Child extends Parent {
  constructor() {
    super()
    this.childName = "child"
  }
  getChildName() {
    return this.childName + 1
  }
}
var child = new Child()
console.log(child.getChildName())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 1.模拟实现 new

function _new(fn, args) {
  var obj = Object.create(fn.prototype)
  var result = obj.apply(fn, args)
  return typeof result === "object" && result !== null ? result : object
}
1
2
3
4
5

# 2.es5 如何实现继承

  • 原型链继承
  • 构造函数继承
  • 组合式继承
  • 寄生组合继承

# 1. 观察者模式

  • 在软件开发设计找那个是一个对象(subject),维护一系列依赖他的对象(observer),当任何状态发生改变自动通知他们。强依赖关系
  • 简答理解:数据发生改变是,对应的处理函数酒瓯会自动执行。一个 subjet,用来维护 observers,为某些 event 来通知(notify)观察者

# 2.发布-订阅者和观察者模式的区别

  • 它定义了一种一对多的关系,可以使多个观察者对象对一个主体对象进行监听,当这个主题对象发生改变时,依赖的所有对象都会被通知到

  • 两者的区别:

    • 1.观察者模式中,观察者知道 subject,两者是相关联的,而发布订阅者只有通过信息代理进行通信
    • 2.在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反
    • 3.观察者大部分是同步的,比如事件的触发,subject 就会调用观察者的方法,而发布订阅者大多数是异步的
    • 4.观察者模式需要在单个应用程序地址空间中实现,而发布订阅者更像交叉应用模式

# 常见的设计模式

  • 工厂模式
  • 单例模式
  • 适配器模式
  • 装饰器
  • 代理模式
  • 发布-订阅模式
  • 外观模式
上次更新: 2022/6/29 上午12:09:44