1024programmer Mongodb 5 TypeScript Design Patterns You Need to Know

5 TypeScript Design Patterns You Need to Know

This article introduces 5 TypeScript design patterns. There is a certain reference value, and friends in need can refer to it, and I hope it will be helpful to everyone.

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 distinct groups:

  • Structural patterns deal with relationships between different components (or classes) and form new structures, to provide new functionality. Examples of structural patterns are Composite, Adapter, and Decorator.
  • Behavioral patterns abstract the common behavior between components into an independent entity. Examples of behavioral patterns are commands, policies, and one of my personal favorites: the 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 creational pattern because it ensures that no matter how many times we try to instantiate a class, we only have one instance available.

Singleton patterns for handling things like database connections, since we want to handle 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 cOnconnections = [
   MyDBConn. getInstance(),
   MyDBConn. getInstance(),
   MyDBConn. getInstance(),
   MyDBConn. getInstance(),
   MyDBConn. getInstance()
 ]

 connections.forEach( c => {
     console. log(c. getID())
 })

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

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

The result of the above operation:

0.4047087250990713
 0.4047087250990713
 0.4047087250990713
 0.4047087250990713
 0.4047087250990713

Factory Mode

Factory Mode is a creation mode, just like Singleton Mode the same. However, this pattern doesn’t work directly on the object we care about, but only manages its creation.

Explain: Suppose we simulate moving vehicles by writing code. There are many types of vehicles, such as cars, bicycles and airplanes. The mobile code should be encapsulated in each vehicle class. But the code that calls their move methods can be generic.

The question here is how to handle object creation? There could be a single creator class with 3 methods, or one method that takes parameters. In either case, extending that logic to support the creation of more vehices requires growing the same class over time.

However, if you decide to use the factory method pattern, you can do the following:

clipboard.png

Now, the code needed to create new objects is encapsulated into a new class, one for each vehicle type. This ensures that if vehicles need to be added in the future, only a new class needs to be added without modifying anything that already exists.

Let’s see how we can use TypeScript to achieve this:

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 is "abstract" because no one will instantiate it
 // we're going to extend it and implement the abstract method
 abstract class VehicleHandler {

     // This is the method that the real handler needs to implement
     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 PlaneHandThe rator class is abstract, which means it is not used, but is used to define a constructor that will keep a copy of the original object in a protected property.  The overriding of the public interface is done inside the custom decorator.  
  • SuperAnimal and SwimmingAnimal are the actual decorators, which are decorators that add extra behavior.
  • The advantage of having this set up is that since all decorators also indirectly extend the Animal class, if you want to mix the two behaviors together, you can Do the following:

    const superSwimmingDog = new SwimmingAnimal(superDog)
    
     superSwimmingDog.move()

    Composite (combination)

    About the Composite mode, it is actually a combination mode, also known as a partial overall mode. This mode is in our It is also often used in life.

    For example, if you have written a front-end page, you must have used tags such as

    to define some formats, and then the formats are combined with each other and organized into corresponding ones in a recursive way Structure, this method is actually a combination, embedding part of the components into the whole.

    The interesting thing about this pattern is that it is not a simple group of objects, it can contain entities or groups of entities, and each group can contain more groups at the same time, this is what we call a tree.

    Look at an example:

    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[] = []
        
         constructor() {
             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())

    In the above example, we can put product into Box , you can also put Box inside other Box, which is a classic example of composition. Because what we want to achieve is to get the complete delivery price, so we need to add the price of each element (including the price of each small box) in the big box.

    The result of the above operation:

    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

    Therefore, consider using this pattern when dealing with multiple objects conforming to the same interface. By hiding the complexity within a single entity (the composition itself), you'll find it helps simplify how you interact with your group.

    That's all for today's sharing, thank you for watching, see you next time.

    Original address: https://blog.bitsrc.io/design-patterns-in-typescript-e9f84de40449

    Author: Fernando Doglio

    Translation address: https://segmentfault.com/a/1190000025184682

    For more programming knowledge, please visit: Programming courses! !

    The above are the details of the 5 design patterns of TypeScript that need to be understood. For more, please pay attention to other related articles on 1024programmer.com!

    This article is from the internet and does not represent1024programmerPosition, please indicate the source when reprinting:https://www.1024programmer.com/5-typescript-design-patterns-you-need-to-know-2/

    author: admin

    Previous article
    Next article

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    Contact Us

    Contact us

    181-3619-1160

    Online consultation: QQ交谈

    E-mail: [email protected]

    Working hours: Monday to Friday, 9:00-17:30, holidays off

    Follow wechat
    Scan wechat and follow us

    Scan wechat and follow us

    Follow Weibo
    Back to top
    首页
    微信
    电话
    搜索