js设计模式

119 阅读3分钟

构造器模式

JS 中,ES6之前是不支持类这个概念的,所以一般用函数来表示一个构造器,使用方法是在构造器函数前使用 new 关键字。

  • say方法挂载在this上,可见有弊端,每次new一个新的对象都有自己独立的say方法,想想,都是做一样的事,是否可以共同一个呢?请看原型模式~~~
/**
* 构造函数  ---》以下方式存在弊端
* @deprecated 在JS 中,ES6之前是不支持类这个概念的,所以一般用函数来表示一个构造器,使用方法是在构造器函数前使用 new 关键字。
* @param name 姓名
* @param age 年龄
* @constructor
*/
function Person(name, age) {
  this.name = name
  this.age = age
  // 每个人身上都有say方法(这样不是我们想要的,造成每new出来一个新的对象,就有一个say方法),方法挂载到原型上,使之共享
  this.say = function () {
    console.log('你好,我是' + this.name)
  }
}
// new 会在内存中开辟一块新的空间且地址不同
const person1 = new Person('张三', 20) 
const person2 = new Person('李四', 19) 
person2.name = '王五'
console.log(person1) // {name: '张三', age: 20, say:function()}
console.log(person2) // {name: '王五', age: 19, say:function()}
person1.say() // 你好,我是张三
person2.say() // 你好,我是王五
console.log(person1.say === person2.say) // false

原型模式

  • 此时我们将say方法直接挂载到Person原型对象上,这样就可以达到共享一个方法,可以看出person1.say === person2.say是为true的。
/**
* @param name 姓名
* @param age 年龄
* @constructor
*/
function Person(name, age) {
  this.name = name
  this.age = age
}
// 原型属性上 加上say方法
Person.prototype.say = function () {
  console.log('你好,我是' + this.name)
}
// new 会在内存中开辟一块新的空间且地址不同
const person1 = new Person('张三', 20) 
const person2 = new Person('李四', 19) 
person2.name = '王五'
console.log(person1) // {name: '张三', age: 20} 此时say在原型对象Prototype里面
console.log(person2) // {name: '王五', age: 19} 此时say在原型对象Prototype里面
person1.say() // 你好,我是张三
person2.say() // 你好,我是王五
console.log(person1.say === person2.say) // true

我们用ES6当中的类模式实现

  • 类模式包含了构造器模式原型模式~ 代码能更好的复用,话不多说~直接上代码
/**
* ES6类模式
*/
class Person {
  // constructor里面可以写属性
  constructor(name,age) {
    this.name = name
    this.age = age
  }
  // 共用的方法都可以写这里,直接会挂载到原型对象上
  // say方法是存在原型对象身上的
  say() {
   console.log('我是'+this.name)
  }
}
const zs = new Person('李四',22)
const ls = new Person('张三',23)
console.log(zs)
ls.say() // 我是张三

image.png

工厂模式

简单工厂模式

简单工厂模式又叫静态工厂模式,由一个工厂对象决定创建某一种产品对象类的实例

  • ES5写法
 /**
   *
   * @param role 用户
   * @param authority 权限
   * @constructor
   */
function UserFactory(role) {
 function User(role, authority) {
   this.role = role
   this.authority = authority
 }
 switch (role) {
   case 'admin':
     return new User('admin', ['add', 'delete', 'update', 'get'])
   case 'user1':
     return new User('user1', ['add', 'get'])
   case 'user2':
     return new User('user2', ['get'])
   default:
    throw new Error('参数错误')
  }
}
const user1 = new UserFactory('user1')
const user2 = new UserFactory('user2')
console.log(user1)
console.log(user2)

image.png ES6写法
使用static关键字将简单工厂封装到User类的静态方法中

class User {
    constructor(role, authority) {
      this.role= role
      this.authority= authority
    }
    static UserFactory(role) {
      switch (role) {
        case 'admin':
          return new User('admin', ['add', 'delete', 'update', 'get'])
        case 'user1':
          return new User('user1', ['add', 'get'])
        case 'user2':
          return new User('user2', ['get'])
        default:
          throw new Error('参数错误')
      }
    }
  }
  const admin = User.UserFactory('admin')
  const user1 = User.UserFactory('user1')
  const user2 = User.UserFactory('user2')
  console.log(admin)
  console.log(user1)
  console.log(user2)

image.png

User就是一个简单工厂,在该函数中有3个实例中分别对应不同的权限的用户。当我们调用工厂函数时,只需要传递admin, user1, user2这三个可选参数中的一个获取对应的实例对象。

简单工厂的优点在于你只需要一个正确的参数,就可以获取到你所需要的对象,而无需知道其创建的具体细节。但是在函数内包含了所有对象的创建逻辑(构造函数)和判断逻辑的代码,每增加新的构造函数还需要修改判断逻辑代码。当我们的对象不是上面的3个而是30个或更多时,这个函数会成为一个庞大的超级函数,便得难以维护。所以,简单工厂只能作用于创建的对象数量较少,对象的创建逻辑不复杂时使用