Table of Contents
Singleton pattern
Factory mode
装饰模式
Composite(组合)
Home Web Front-end JS Tutorial 5 TypeScript design patterns you need to know

5 TypeScript design patterns you need to know

Nov 20, 2020 pm 05:36 PM
javascript typescript Design Patterns

This article introduces 5 TypeScript design patterns to you. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

5 TypeScript design patterns you need to know

Design patterns are templates that help developers solve problems. There are too many patterns covered in this book, and they often target different needs. However, they can be divided into three different groups:

  • Structural Patterns Deal with the relationships between different components (or classes) and form new structures to provide New features. Examples of structural patterns are Composite, Adapter, and Decorator.
  • Behavior patternAbstract the common behavior between components into an independent entity. Examples of behavioral patterns are commands, strategies, and my personal favorite: Observer Pattern.
  • Creation mode focuses on the instantiation of classes, making it easier for us to create new entities. I'm talking about factory methods, singletons and abstract factories.

Singleton pattern

The singleton pattern is probably one of the most famous design patterns. It is a creation pattern because it ensures that no matter how many times we try to instantiate a class, we only have one instance available.

Handling database connections and the like can be done in singleton mode, because we want to process only one at a time without having to reconnect on each user request.

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())
})
Copy after login

Now, although the class cannot be instantiated directly, using the getInstance method can ensure that there will not be multiple instances. In the example above, you can see how a pseudo-class that wraps a database connection benefits from this pattern.

This example shows that no matter how many times we call the getInstance method, the connection is always the same.

The above running results:

0.4047087250990713
0.4047087250990713
0.4047087250990713
0.4047087250990713
0.4047087250990713
Copy after login

Factory mode

##Factory mode is a creation mode, just like Single case mode Same. However, this pattern does not work directly on the object we care about, but only manages its creation.

Explain: Suppose we write code to simulate a moving vehicle. There are many types of vehicles, such as cars, bicycles and airplanes. The mobile code should be encapsulated in each

vehicle class, but calling The code of their move methods can be generic.

The question here is how to handle object creation? There can be a single

creator class with 3 methods, or a method that takes parameters. In either case, extending that logic to support the creation of more vehices requires continually growing the same class.

However, if you decide to use the factory method pattern, you can do the following: <p></p>

5 TypeScript design patterns you need to know

Now, create the new object required The code is encapsulated into new classes, one for each vehicle type. This ensures that if you need to add a vehicle in the future, you only need to add a new class without modifying anything that already exists. <p></p>Let’s see how we can achieve this using

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()
Copy after login
The above is a lot of code, but we can use the diagram above to understand it. Essentially in the end, what we care about are custom handlers, here we call them handlers, rather than creators, because they don't just create the objects, they also have the logic to use them (the moveVehicle method). <p></p>The beauty of this pattern is that if you want to add a new

vehicle type, all you have to do is add its vehicle class and its handler program class without increasing the LOC of any other class.

Observer Pattern

Among all the patterns, my favorite is

Observer Pattern because of the type behavior we can implement it.

How does it work? Essentially, the pattern states that you have a set of observer objects that will react to changes in the state of the observed entity. To achieve this, once a change is received on the observed side, it is responsible for notifying its observers by calling one of its methods. <p></p>In practice, the implementation of this pattern is relatively simple, let's take a quick look at the code and then review <p></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()
Copy after login
As you can see, with two abstract classes, we can define

Observer, which will represent an object that reacts to changes on the Observable entity. In the above example, we assume to have an InputElement entity that is clicked (similar to how you have HTML input fields on the front end), and a ConsoleLogger that logs to the console Everything that happened.

The beauty of this pattern is that it allows us to understand and react to the internal state of an

Observable without having to mess with its internal code. We can continue to add observers that perform other actions, even observers that react to specific events, and let their code decide what to do with each notification.

装饰模式

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

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

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

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

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()
Copy after login

注意几个细节:

  • 实际上,SuperDecorator类扩展了Animal类,与Dog类扩展了相同的类。 这是因为装饰器需要提供与其尝试装饰的类相同的公共接口。
  • SuperDecorator类是abstract ,这意味着并没有使用它,只是使用它来定义构造函数,该构造函数会将原始对象的副本保留在受保护的属性中。 公共接口的覆盖是在自定义装饰器内部完成的。
  • SuperAnimalSwimmingAnimal是实际的装饰器,它们是添加额外行为的装饰器。

进行此设置的好处是,由于所有装饰器也间接扩展了Animal类,因此如果你要将两种行为混合在一起,则可以执行以下操作:

const superSwimmingDog =  new SwimmingAnimal(superDog)

superSwimmingDog.move()
Copy after login

Composite(组合)

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

比如编写过前端的页面,肯定使用过<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())
Copy after login

在上面的示例中,我们可以将product 放入Box中,也可以将Box放入其他Box中,这是组合的经典示例。因为我们要实现的是获得完整的交付价格,因此需要在大box里添加每个元素的价格(包括每个小box的价格)。

上面运行的结果:

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
Copy after login

因此,在处理遵循同一接口的多个对象时,请考虑使用此模式。 通过将复杂性隐藏在单个实体(组合本身)中,您会发现它有助于简化与小组的互动方式。

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

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

作者:Fernando Doglio

译文地址:https://segmentfault.com/a/1190000025184682

更多编程相关知识,请访问:编程课程!!

The above is the detailed content of 5 TypeScript design patterns you need to know. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

The difference between design patterns and architectural patterns in Java framework The difference between design patterns and architectural patterns in Java framework Jun 02, 2024 pm 12:59 PM

In the Java framework, the difference between design patterns and architectural patterns is that design patterns define abstract solutions to common problems in software design, focusing on the interaction between classes and objects, such as factory patterns. Architectural patterns define the relationship between system structures and modules, focusing on the organization and interaction of system components, such as layered architecture.

PHP Design Patterns: Test Driven Development in Practice PHP Design Patterns: Test Driven Development in Practice Jun 03, 2024 pm 02:14 PM

TDD is used to write high-quality PHP code. The steps include: writing test cases, describing the expected functionality and making them fail. Write code so that only the test cases pass without excessive optimization or detailed design. After the test cases pass, optimize and refactor the code to improve readability, maintainability, and scalability.

Open Intents: Can ERC-7683 become a 'Walmart' supermarket with the intention of synergy between Ethereum chains? Open Intents: Can ERC-7683 become a 'Walmart' supermarket with the intention of synergy between Ethereum chains? Mar 04, 2025 pm 06:24 PM

Written by YBBCapital ResearcherAc-Core: Ethereum fragmentation problem and OpenIntents framework: ERC-7683's breakthrough method Source: @ethereumfndnL2 and the booming development of DeFi have led to the increasing fragmentation of Ethereum liquidity. Asset liquidity is scattered among L1 and many L2s, and there is a lack of effective interconnection between various platforms, like isolated "small pools", hindering the overall efficiency of Ethereum. In 2024, Ethereum added more than 100 new chains, which is like a large shopping mall with a wide range of products, but it requires settlement in different currencies. To solve this problem, the Ethereum Foundation released OpenIntentsF on February 20

What are the advantages and disadvantages of using design patterns in java framework? What are the advantages and disadvantages of using design patterns in java framework? Jun 01, 2024 pm 02:13 PM

The advantages of using design patterns in Java frameworks include: enhanced code readability, maintainability, and scalability. Disadvantages include complexity, performance overhead, and steep learning curve due to overuse. Practical case: Proxy mode is used to lazy load objects. Use design patterns wisely to take advantage of their advantages and minimize their disadvantages.

Application of design patterns in Guice framework Application of design patterns in Guice framework Jun 02, 2024 pm 10:49 PM

The Guice framework applies a number of design patterns, including: Singleton pattern: ensuring that a class has only one instance through the @Singleton annotation. Factory method pattern: Create a factory method through the @Provides annotation and obtain the object instance during dependency injection. Strategy mode: Encapsulate the algorithm into different strategy classes and specify the specific strategy through the @Named annotation.

Application of design patterns in Spring MVC framework Application of design patterns in Spring MVC framework Jun 02, 2024 am 10:35 AM

The SpringMVC framework uses the following design patterns: 1. Singleton mode: manages the Spring container; 2. Facade mode: coordinates controller, view and model interaction; 3. Strategy mode: selects a request handler based on the request; 4. Observer mode: publishes and listen for application events. These design patterns enhance the functionality and flexibility of SpringMVC, allowing developers to create efficient and maintainable applications.

PHP Design Patterns: Patterns used to solve specific software problems PHP Design Patterns: Patterns used to solve specific software problems Jun 01, 2024 am 11:07 AM

PHP design patterns provide known solutions to common problems in software development. Common pattern types include creational (such as factory method pattern), structural (such as decorator pattern) and behavioral (such as observer pattern). Design patterns are particularly useful when solving repetitive problems, improving maintainability, and promoting teamwork. In e-commerce systems, the observer pattern can realize automatic updates between shopping cart and order status. Overall, PHP design patterns are an important tool for creating robust, scalable, and maintainable applications.

How does the TypeScript interface accurately represent the DATETIME type of SQLite? How does the TypeScript interface accurately represent the DATETIME type of SQLite? Apr 04, 2025 pm 05:15 PM

The DATETIME type representing SQLite in the TypeScript interface When using TypeScript definition interface to map the DATETIME type in the SQLite database, select the appropriate class...

See all articles