Maison > interface Web > js tutoriel > le corps du texte

Une plongée approfondie dans 5 modèles de conception dans TypeScript

青灯夜游
Libérer: 2021-06-03 10:53:31
avant
1605 Les gens l'ont consulté
<p>Cet article vous donnera une compréhension approfondie de 5 modèles de conception TypeScript. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.

<p>Une plongée approfondie dans 5 modèles de conception dans TypeScript

<p>Les modèles de conception sont des modèles qui aident les développeurs à résoudre des problèmes. Il y a trop de modèles abordés dans ce livre, et ils ciblent souvent des besoins différents. Cependant, ils peuvent être divisés en trois groupes différents :

  • Les modèles structurels traitent des relations entre différents composants (ou classes) et forment de nouvelles structures pour fournir de nouvelles fonctionnalités. Des exemples de modèles structurels sont Composite, Adapter et Decorator.
  • Le modèle de comportement résume le comportement commun entre les composants en une entité indépendante. Des exemples de modèles de comportement sont les commandes, les stratégies et mon préféré : 观察者模式.
  • Le mode Création se concentre sur l'instanciation des classes, ce qui nous permet de créer plus facilement de nouvelles entités. Je parle de méthodes d'usine, de singletons et d'usines abstraites.

Modèle Singleton

<p>Le modèle Singleton est probablement l'un des modèles de conception les plus célèbres. Il s'agit d'un modèle de création car il garantit que peu importe le nombre de fois que nous essayons d'instancier une classe, nous n'avons qu'une seule instance disponible.

<p>La gestion d'éléments tels que les connexions à la base de données peut être effectuée en mode singleton car nous souhaitons n'en gérer qu'une à la fois sans avoir à nous reconnecter à chaque demande de l'utilisateur.

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())
})
Copier après la connexion
<p>Maintenant, bien que la classe ne puisse pas être instanciée directement, l'utilisation de la méthode getInstance garantit qu'il n'y aura pas plusieurs instances. Dans l'exemple ci-dessus, vous pouvez voir comment une pseudo-classe qui encapsule une connexion à une base de données bénéficie de ce modèle.

<p>Cet exemple montre que peu importe le nombre de fois que nous appelons la méthode getInstance, la connexion est toujours la même.

<p>Le résultat ci-dessus :

0.4047087250990713
0.4047087250990713
0.4047087250990713
0.4047087250990713
0.4047087250990713
Copier après la connexion

Le mode usine

<p>工厂模式 est un mode de création, tout comme 单例模式. Cependant, ce patron ne travaille pas directement sur l'objet qui nous tient à cœur, mais gère uniquement sa création.

<p>Expliquez : Supposons que nous écrivions du code pour simuler des véhicules en mouvement. Il existe de nombreux types de véhicules, tels que les voitures, les vélos et les avions, le code mobile doit être encapsulé dans chaque vehicle classe, mais le <🎜 cela. les appelle > Le code de la méthode peut être générique. move

La question ici est de savoir comment gérer la création d'objets ? Il peut y avoir une seule <p> classe avec 3 méthodes, ou une méthode qui prend des paramètres. Dans les deux cas, étendre cette logique pour prendre en charge la création de plus de creator nécessite de développer la même classe. vehices

Cependant, si vous décidez d'utiliser le modèle de méthode d'usine, vous pouvez procéder comme suit : <p>

<p>Une plongée approfondie dans 5 modèles de conception dans TypeScript

Maintenant, le code requis pour créer le nouvel objet est encapsulé dans un nouveau Parmi les classes, chaque classe correspond à un type de véhicule. Cela garantit que si vous devez ajouter un véhicule à l'avenir, il vous suffira d'ajouter une nouvelle classe sans rien modifier de ce qui existe déjà. <p>

Ensuite, voyons comment nous pouvons utiliser <p> pour y parvenir : 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()
Copier après la connexion

Ce qui précède représente beaucoup de code, mais nous pouvons utiliser le diagramme ci-dessus pour le comprendre. En fin de compte, ce qui nous intéresse, ce sont les gestionnaires personnalisés, nous les appelons ici gestionnaires, plutôt que créateurs, car ils ne se contentent pas de créer les objets, ils ont également la logique pour les utiliser (la méthode moveVehicle). <p>

La beauté de ce modèle est que si vous souhaitez ajouter un nouveau type <p>, tout ce que vous avez à faire est d'ajouter sa classe vehicle et sa classe de gestionnaire sans rien ajouter d'autre Classe LOC. vehicle

Modèle d'observateur

De tous les modèles, mon préféré est <p> en raison du comportement typé que nous pouvons implémenter. 观察者模式

Comment ça marche ? Essentiellement, le modèle dit que vous disposez d'un ensemble d'objets observateurs qui réagiront aux changements dans l'état de l'entité observée. Pour y parvenir, une fois un changement reçu du côté observé, il se charge de notifier ses observateurs en appelant une de ses méthodes. <p>

En pratique, l'implémentation de ce pattern est relativement simple, jetons un coup d'oeil rapide au code et révisons <p>
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()
Copier après la connexion

Comme vous pouvez le voir, avec deux classes abstraites, on peut définir <p>, cet observateur représentera un objet qui réagit aux changements sur l'entité Observer. Dans l'exemple ci-dessus, nous supposons que nous avons une entité Observable sur laquelle on clique (de la même manière que vous avez des champs de saisie HTML sur le front-end) et un InputElement qui enregistre tout ce qui arrive à la console. La beauté de ce modèle pour ConsoleLogger

est qu'il nous permet de comprendre et de réagir à l'état interne de <p> sans avoir à jouer avec son code interne. Nous pouvons continuer à ajouter des observateurs qui effectuent d'autres actions, même des observateurs qui réagissent à des événements spécifiques, et laisser leur code décider quoi faire de chaque notification. Observable

装饰模式

<p>装饰模式试图在运行时向现有对象添加行为。 从某种意义上说,我们可以将其视为动态继承,因为即使没有创建新类来添加行为,我们也正在创建具有扩展功能的新对象。

<p>这样考虑:假设我们拥有一个带有move方法的Dog类,现在您想扩展其行为,因为我们想要一只超级狗和一只可以游泳的狗。

<p>通常,我们需要在 Dog 类中添加move 行为,然后以两种方式扩展该类,即SuperDogSwimmingDog类。 但是,如果我们想将两者混合在一起,则必须再次创建一个新类来扩展它们的行为,但是,有更好的方法。

<p>组合让我们可以将自定义行为封装在不同的类中,然后使用该模式通过将原始对象传递给它们的构造函数来创建这些类的新实例。 让我们看一下代码:

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&#39;s go swimming --- ")
const swimmingDog =  new SwimmingAnimal(dog)
swimmingDog.move()
Copier après la connexion
<p>注意几个细节:

  • 实际上,SuperDecorator类扩展了Animal类,与Dog类扩展了相同的类。 这是因为装饰器需要提供与其尝试装饰的类相同的公共接口。
  • SuperDecorator类是abstract ,这意味着并没有使用它,只是使用它来定义构造函数,该构造函数会将原始对象的副本保留在受保护的属性中。 公共接口的覆盖是在自定义装饰器内部完成的。
  • SuperAnimalSwimmingAnimal是实际的装饰器,它们是添加额外行为的装饰器。
<p>进行此设置的好处是,由于所有装饰器也间接扩展了Animal类,因此如果你要将两种行为混合在一起,则可以执行以下操作:

const superSwimmingDog =  new SwimmingAnimal(superDog)

superSwimmingDog.move()
Copier après la connexion

Composite(组合)

<p>关于Composite模式,其实就是组合模式,又叫部分整体模式,这个模式在我们的生活中也经常使用。

<p>比如编写过前端的页面,肯定使用过<p>等标签定义一些格式,然后格式之间互相组合,通过一种递归的方式组织成相应的结构,这种方式其实就是组合,将部分的组件镶嵌到整体之中。

<p>关于此模式的有趣之处在于,它不是一个简单的对象组,它可以包含实体或实体组,每个组可以同时包含更多组,这就是我们所说的树。

<p>看一个例子:

interface IProduct {
  getName(): string
  getPrice(): number
}

class Product implements IProduct {
  private price:number
  private name:string

  constructor(name:string, price:number) {
    this.name = name
    this.price = price
  }

  public getPrice():number {
    return this.price
  }

  public getName(): string {
    return this.name
  }
}

class Box implements IProduct {

    private products: IProduct[] = []
    
    contructor() {
        this.products = []
    }
    
    public getName(): string {
        return "A box with " + this.products.length + " products"
    } 
    
    add(p: IProduct):void {
        console.log("Adding a ", p.getName(), "to the box")
        this.products.push(p)
    }

    getPrice(): number {
        return this.products.reduce( (curr: number, b: IProduct) => (curr + b.getPrice()),  0)
    }
}

//Using the code...
const box1 = new Box()
box1.add(new Product("Bubble gum", 0.5))
box1.add(new Product("Samsung Note 20", 1005))

const box2 = new Box()
box2.add( new Product("Samsung TV 20in", 300))
box2.add( new Product("Samsung TV 50in", 800))

box1.add(box2)

console.log("Total price: ", box1.getPrice())
Copier après la connexion
<p>在上面的示例中,我们可以将product 放入Box中,也可以将Box放入其他Box中,这是组合的经典示例。因为我们要实现的是获得完整的交付价格,因此需要在大box里添加每个元素的价格(包括每个小box的价格)。

<p>上面运行的结果:

Adding a  Bubble gum to the box
Adding a  Samsung Note 20 to the box
Adding a  Samsung TV 20in to the box
Adding a  Samsung TV 50in to the box
Adding a  A box with 2 products to the box
Total price:  2105.5
Copier après la connexion
<p>因此,在处理遵循同一接口的多个对象时,请考虑使用此模式。 通过将复杂性隐藏在单个实体(组合本身)中,您会发现它有助于简化与小组的互动方式。

<p>今天的分享就到这里了,感谢大家的观看,我们下期再见。

<p>英文原文地址:https://blog.bitsrc.io/design-patterns-in-typescript-e9f84de40449

<p>作者:Fernando Doglio

<p>译者:前端小智

<p>更多编程相关知识,请访问:编程视频!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!