TS中使用getter和setter做类的私有属性保护及时实现单例模式

1,489 阅读5分钟

一、getter和setter

有些时候,我们需要对类的某些属性做一个保护,所以我们不希望这个属性直接暴露出来,而是通过加密或者其他方式处理之后再展示出来,这个时候就要用到类的新的语法getter和setter来实现这个功能了,话不多说,先上代码;

class Person {
  constructor(private name: string) {}
}

let person = new Person('Dabin')

console.log(person.name); // 报错,name是私有属性,只能在内部访问

上面代码我们声明了一个Person类,并声明了一个私有属性name,然后我们声明了他的实例person,你会看到,当我们想访问name属性并打他的时候报错了,显示内部属性无法在外部访问;

这个时候,我们就需要用到gettersetter了,我们更改代码,往下看;

class Person {
  constructor(private name: string) {}
  get getName() {
    return this.name 
  }
}

let person = new Person('Dabin')

console.log(person.getName);

这个时候,我们查看控制台,发现能正常打印name了;这是因为我们通过get在类的内部访问了name属性,所以他不会报错,细心的人会发现,为什么我们访问getName方法不会在后面加括号,这是因为我们虽然访问的getName方法,但实际上我们访问的是类的get属性,所以不需要加括号;

但是这样看起来,跟直接访问name属性没什么区别啊,还不如直接访问来的简单,别着急,请听我往下讲,虽然目前我们还是直接返回的name属性,但是如果我们对getName方法做一些修改呢?比如我们在后面再拼接上一些内容;

class Person {
  constructor(private name: string) {}
  get getName() {
    return this.name + ' Lee'
  }
}

let person = new Person('Dabin')

console.log(person.getName); //Dabin Lee

这个时候你再看,我们在this.name 后面拼接上Lee,返回的就不是实际的name值了,而是Dabin Lee,然后我们在修改一些代码,将私有属性用标记,并修改方法名;

class Person {
  constructor(private _name: string) {}
  get name() {
    return this._name + ' Lee'
  }
}

let person = new Person('Dabin')

console.log(person.name); //Dabin Lee

这个时候你再看,是不是有点那个味道了,你以为你获取的是我的私有属性name,其实那也只是你以为,这里的get方法其实就是最私有属性的一个加密,用来保护我们的私有属性;那如果我想修改这个name值呢?这个时候就需要我们的setter属性出马了;看代码:

class Person {
  constructor(private _name: string) {}
  get name() {
    return this._name + ' Lee'
  }
  set name(name: string) {
    this._name = name.split(' ')[0]
  }
}

let person = new Person('Dabin')
console.log(person.name); //Dabin Lee
person.name = 'Dabin lee'
console.log(person.name); //Dabin Lee

同样的,在给name属性赋值的时候,我们也需要做一些加密处理,然后在真正赋值时只截取我们需要的那部分就可以了,以上就是如何用gettersetter对类的私有属性进行保护的方法了,这只是很简单的例子,在实际的开发中可能会复杂的多,但是基本原理就是这样的,也是比较简单的;

二、单例模式

接下来,我们来了解一下在TS中如何实现我们开发常用的单例模式;那什么是单例模式呢?顾名思义,单例模式就是声明一个类,然后只允许用它来创建一个实例,具体如何实现呢?看代码:

class Demo {
  private constructor(name: string) {}
}

let demo1 = new Demo() // 报错

要实现单例模式,首先我们希望内部的constructor只能被调用一次,我们我们给constructor添加了private标记,这样,你在外部试图通过new关键字来穿创建实例的时候就会报错;这样我们就排除了在外部构建实例的情况,那问题来了,我们怎么去实现那唯一一次的实例构建呢?那肯定只能在类内部实现了;

这里我们要用到类的静态属性static,我们知道通过static标记的属性和方法是挂载到类本身上的而不是实例上的,这样我们就可以声明一个静态方法,暴露给外部调用;

class Demo {
  private constructor(name: string) {}

  static getInstance() {
    return new Demo('Dabin')
  }
}

let demo1 = Demo.getInstance()

我们通过static声名了一个getInstance方法供外部调用,同时这个方法也返回了Demo实例,但是,很明显,这压根没实现只能创建一个实例这个要求,别急,我们在声明一个类的静态属性instance,然后将其私有化;然后在修改getInstance方法;

class Demo {
  private static instance: Demo
  private constructor(name: string) {}

  static getInstance() {
    if (!this.instance) {
      this.instance = new Demo('Dabin')
    }
    return this.instance
  }
}

let demo1 = Demo.getInstance()
let demo2 = Demo.getInstance()

上面代码,我们声明了一个静态属性instance,将其设置为Demo类型,并且将其私有化,这样外部就不能直接访问这个属性了,然后我们看getInstance方法,每次调用的时候,我们会判断Demo实例是否存在,如果不存在,就会创建一个实例并挂载到instance上,如果已经实例化过了,那就直接返回这个实例;这样,我们的单例就实现了; 对代码做简单的修改,我们验证一下;

class Demo {
  private static instance: Demo
  private constructor(public name: string) {}

  static getInstance(name: string) {
    if (!this.instance) {
      this.instance = new Demo(name)
    }
    return this.instance
  }
}

let demo1 = Demo.getInstance('Dabin')
let demo2 = Demo.getInstance('Dashegn')

console.log(demo1.name); // Dabin
console.log(demo2.name); // Dabin

执行后发现,打印的结果都是Dabin,这是因为只有第一次调用getInstance方法的时候才是创建Demo实例,后面生成demo2的时候就是直接返回刚刚创建的实例,所以demo1demo2其实是两个完全相等的实例;以上,就是一个简单的单例模式的实现了;

通过这篇文章,我们简单的了解了如何使用类的gettersetter属性对类的静态属性进行加密保护,同时简单的实现了TypeScript中的单例模式,在过程中也对类的static属性有一些很好的理解,希望对你有用;