你应该知道的 5 种 typescript设计模式_ts设计模式-爱代码爱编程
github 地址:https://github.com/qq449245884/vue-okr-tree
设计模式是可以帮助开发人员解决问题的模板。在本中涉及的模式太多了,而且它们往往针对不同的需求。但是,它们可以被分为三个不同的组:
-
结构模式处理不同组件(或类)之间的关系,并形成新的结构,以提供新的功能。结构模式的例子有
Composite
、Adapter
和Decorator
。 -
行为模式将组件之间的公共行为抽象成一个独立的实体。行为模式的例子有命令、策略和我个人最喜欢的一个:
观察者模式
。 -
创建模式 专注于类的实例化,让我们更容易创建新的实体。我说的是工厂方法,单例和抽象工厂。
单例模式可能是最著名的设计模式之一。它是一种创建模式,因为它确保无论我们尝试实例化一个类多少次,我们都只有一个可用的实例。
处理数据库连接之类的可以单例模式,因为我们希望一次只处理一个,而不必在每个用户请求时重新连接。
class MyDBConn {
protected static instance: MyDBConn | null = null
private id:number = 0
constructor() {
this.id = Math.random()
}
public getID():number {
return this.id
}
public static getInstance():MyDBConn {
if (!MyDBConn.instance) {
MyDBConn.instance = new MyDBConn()
}
return MyDBConn.instance
}
}
const connections = [
MyDBConn.getInstance(),
MyDBConn.getInstance(),
MyDBConn.getInstance(),
MyDBConn.getInstance(),
MyDBConn.getInstance()
]
connections.forEach( c => {
console.log(c.getID())
})
现在,虽然不能直接实例化类,但是使用getInstance
方法,可以确保不会有多个实例。在上面的示例中,可以看到包装数据库连接的伪类如何从该模式中获益。
这个事例展示了无论我们调用getInstance
方法多少次,这个连接总是相同的。
上面的运行结果:
0.4047087250990713
0.4047087250990713
0.4047087250990713
0.4047087250990713
0.4047087250990713
工厂模式
是一种创建模式,就像单例模式
一样。但是,这个模式并不直接在我们关心的对象上工作,而是只负责管理它的创建。
解释一下:假设我们通过编写代码来模拟移动车辆,车有很多类型,例如汽车、自行车和飞机,移动代码应该封装在每个vehicle
类中,但是调用它们的move
方法的代码可以是通用的。
这里的问题是如何处理对象创建?可以有一个具有3个方法的单一creator
类,或者一个接收参数的方法。在任何一种情况下,扩展该逻辑以支持创建更多vehices
都需要不断增长相同的类。
但是,如果决定使用工厂方法模式,则可以执行以下操作:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YHK6n7XD-1605746535954)(/img/bVbZLFD)]
现在,创建新对象所需的代码被封装到一个新类中,每个类对应一个车辆类型。这确保了如果将来需要添加车辆,只需要添加一个新类,而不需要修改任何已经存在的东西。
接着来看看,我们如何使用TypeScript
来实现这一点:
interface Vehicle {
move(): void
}
class Car implements Vehicle {
public move(): void {
console.log(“Moving the car!”)
}
}
class Bicycle implements Vehicle {
public move(): void {
console.log(“Moving the bicycle!”)
}
}
class Plane implements Vehicle {
public move(): void {
console.log(“Flying the plane!”)
}
}
// VehicleHandler 是“抽象的”,因为没有人会实例化它instantiate it
// 我们要扩展它并实现抽象方法
abstract class VehicleHandler {
// 这是真正的处理程序需要实现的方法
public abstract createVehicle(): Vehicle
public moveVehicle(): void {
const myVehicle = this.createVehicle()
myVehicle.move()
}
}
class PlaneHandler extends VehicleHandler{
public createVehicle(): Vehicle {
return new Plane()
}
}
class CarHandler extends VehicleHandler{
public createVehicle(): Vehicle {
return new Car()
}
}
class BicycleHandler extends VehicleHandler{
public createVehicle(): Vehicle {
return new Bicycle()
}
}
/// User code…
const planes = new PlaneHandler()
const cars = new CarHandler()
planes.moveVehicle()
cars.moveVehicle()
上面的代码很多,但我们可以使用上面的图表来理解它。本质上最后,我们关心的是自定义处理程序,这里称它为处理程序,而不是创造者,因为他们不只是创建的对象,他们也有逻辑,使用它们(moveVehicle方法)。
这个模式的美妙之处在于,如果您你要添加一个新的vehicle
类型,所要做的就是添加它的vehicle
类和它的处理程序类,而不增加任何其他类的LOC。
在所有的模式,我最喜欢的是观察者模式
,因为类型的行为我们可以实现它。
它是如何工作的呢?本质上,该模式表明你拥有一组观察者对象,这些对象将对被观察实体状态的变化做出反应。为了实现这一点,一旦在被观察端接收到一个更改,它就负责通过调用它的一个方法来通知它的观察者。
在实践中,此模式的实现相对简单,让我们快速查看一下代码,然后回顾一下
type InternalState = {
event: String
}
abstract class Observer {
abstract update(state:InternalState): void
}
abstract class Observable {
protected observers: Observer[] = []
protected state:InternalState = { event: “”}
public addObserver(o: Observer):void {
this.observers.push(o)
}
protected notify () {
this.observers.forEach(o => o.update(this.state))
}
}
class ConsoleLogger extends Observer {
public update(newState: InternalState) {
console.log("New internal state update: ", newState)
}
}
class InputElement extends Observable {
public click():void {
this.state = { event: “click” }
this.notify()
}
}
const input = new InputElement()
input.addObserver(new ConsoleLogger())
input.click()
正如你所看到的,通过两个抽象类,我们可以定义Observer
,该观察者将表示对Observable
实体上的更改做出反应的对象。 在上面的示例中,我们假设具有一个被单击的InputElement
实体(类似于在前端具有HTML输入字段的方式),以及一个ConsoleLogger
,用于记录控制台发生的所有事情。
这种模式的优点在于,它使我们能够了解Observable
的内部状态并对其做出反应,而不必弄乱其内部代码。 我们可以继续添加执行其他操作的观察者,甚至包括对特定事件做出反应的观察者,然后让它们的代码决定对每个通知执行的操作。
装饰模式试图在运行时向现有对象添加行为。 从某种意义上说,我们可以将其视为动态继承,因为即使没有创建新类来添加行为,我们也正在创建具有扩展功能的新对象。
这样考虑:假设我们拥有一个带有move
方法的Dog
类,现在您想扩展其行为,因为我们想要一只超级狗和一只可以游泳的狗。
通常,我们需要在 Dog 类中添加move
行为,然后以两种方式扩展该类,即SuperDog
和SwimmingDog
类。 但是,如果我们想将两者混合在一起,则必须再次创建一个新类来扩展它们的行为,但是,有更好的方法。
组合让我们可以将自定义行为封装在不同的类中,然后使用该模式通过将原始对象传递给它们的构造函数来创建这些类的新实例。 让我们看一下代码:
abstract class Animal {
abstract move(): void
}
abstract class SuperDecorator extends Animal {
protected comp: Animal
constructor(decoratedAnimal: Animal) {
super()
this.comp = decoratedAnimal
}
abstract move(): void
}
class Dog extends Animal {
public move():void {
console.log(“Moving the dog…”)
}
}
class SuperAnimal extends SuperDecorator {
public move():void {
console.log(“Starts flying…”)
this.comp.move()
console.log(“Landing…”)
}
}
class SwimmingAnimal extends SuperDecorator {
public move():void {
console.log(“Jumps into the water…”)
this.comp.move()
}
}
const dog = new Dog()
console.log("— Non-decorated attempt: ")
dog.move()
console.log("— Flying decorator — ")
const superDog = new SuperAnimal(dog)
superDog.move()
console.log("— Now let’s go swimming — ")
const swimmingDog = new SwimmingAnimal(dog)
swimmingDog.move()
前端资料汇总
我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。
首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。
更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。
找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。
最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。