Commonly used design patterns and applications in front-end development

Preface

In front-end development, everyone can write code. Sometimes you may know to write it this way, but you don’t know why it is written this way and what the meaning of it is. Today there is a fishing incident, to supplement the knowledge points related to design patterns, so that I can understand the design patterns more deeply and record and share them, so that my development ideas can be clearer. In order to avoid the interviewer asking later: "Do you know design patterns? What design patterns have you used?", Me: "I can write but I can't speak out", the interviewer: "Go back and wait for the notification"


Classification of design patterns

Design pattern is a general method for solving common problems in software development. It can help us improve the readability, maintainability and scalability of code. There are many types of design patterns. According to different purposes and scenarios, they can be divided into three categories: creative, structural and behavioral.

Creative

  • Singleton pattern

    The creational pattern mainly focuses on how objects are created. When you need to ensure that a class has only one instance and provide a global access point, you can use the singleton pattern. For example, if you need to manage a global status object, a global configuration object, or a global event bus object, you can use the singleton pattern to achieve this.

    // 定义一个单例类
    class Singleton {
          
          
      constructor(name) {
          
          
        this.name = name;
      }
      // 定义一个静态方法获取实例
      static getInstance(name) {
          
          
        // 如果实例不存在,则创建一个新的实例
        if (!this.instance) {
          
          
          this.instance = new Singleton(name);
        }
        // 返回实例
        return this.instance;
      }
    }
    
    // 测试
    const a = Singleton.getInstance('a');
    const b = Singleton.getInstance('b');
    console.log(a === b); // true
    console.log(a.name); // a
    console.log(b.name); // a
    
  • Factory pattern

// 定义一个工厂类
class Factory {
    
    
  // 定义一个静态方法创建对象
  static create(type) {
    
    
    // 根据不同类型返回不同对象
    switch (type) {
    
    
      case 'A':
        return new A();
      case 'B':
        return new B();
      default:
        return null;
    }
  }
}

// 定义两个不同类型的类
class A {
    
    
  constructor() {
    
    
    this.name = 'A';
  }
}

class B {
    
    
  constructor() {
    
    
    this.name = 'B';
  }
}

// 测试
const a = Factory.create('A');
const b = Factory.create('B');
console.log(a instanceof A); // true
console.log(b instanceof B); // true
console.log(a.name); // A
console.log(b.name); // B
  • builder pattern

Builder pattern is a design pattern that separates the construction process and presentation process of a complex object so that the same construction process can create different representations. In front-end development, we often encounter scenarios where we need to create complex objects, such as creating a complex form component or creating a complex chart component. Using the builder pattern, you can encapsulate the construction process of complex objects in a class, provide some methods to set different properties and configurations, and then return the final object. This avoids the direct use of constructors or object literals to create objects, improving the readability and maintainability of the code. Of course, I strongly recommend using tsx to write this way! It can be achieved using react or vue3+tsx.

// 定义一个表单组件类
class Form {
  constructor() {
    this.fields = []; // 表单字段列表
    this.title = ''; // 表单标题
    this.submitText = ''; // 提交按钮文本
  }
  // 定义一个渲染方法
  render() {
    // 返回一个vue组件对象
    return {
      template: `
        <div>
          <h1>{
   
   {title}}</h1>
          <div v-for="field in fields">
            <label>{
   
   {field.label}}</label>
            <input :type="field.type" :name="field.name" />
          </div>
          <button>{
   
   {submitText}}</button>
        </div>
      `,
      data() {
        return {
          title: this.title,
          fields: this.fields,
          submitText: this.submitText,
        };
      },
    };
  }
}

// 定义一个表单组件建造者类
class FormBuilder {
  constructor() {
    this.form = new Form(); // 创建一个新的表单组件对象
  }
  // 定义一个添加字段的方法
  addField(field) {
    this.form.fields.push(field); // 将字段添加到表单字段列表中
    return this; // 返回当前建造者对象,实现链式调用
  }
  // 定义一个设置标题的方法
  setTitle(title) {
    this.form.title = title; // 设置表单标题
    return this; // 返回当前建造者对象,实现链式调用
  }
  // 定义一个设置提交按钮文本的方法
  setSubmitText(text) {
    this.form.submitText = text; // 设置提交按钮文本
    return this; // 返回当前建造者对象,实现链式调用
  }
  // 定义一个获取最终表单组件对象的方法
  build() {
    return this.form.render(); // 返回最终的表单组件对象
  }
}

// 测试
const formBuilder = new FormBuilder();
const form = formBuilder.setTitle('注册表单')
                        .addField({ label: '用户名', type: 'text', name: 'username' })
                        .addField({ label: '密码', type: 'password', name: 'password' })
                        .addField({ label: '邮箱', type: 'email', name: 'email' })
                        .setSubmitText('注册')
                        .build();
new Vue({
  el: '#app',
  components: {
    form,
  },
});

structural type

  • adapter mode

The adapter pattern is a design pattern that converts the interface of one class or object into another interface so that originally incompatible classes or objects can work together. In front-end development, we often encounter scenarios that require connecting to different interfaces or data formats, such as calling APIs from different sources or processing data in different formats. Using the adapter pattern can avoid modifying the original class or object, but implements interface or data conversion through an intermediate layer, improving the reusability and scalability of the code.

// 定义一个适配器类
class Adapter {
    
    
  constructor(adaptee) {
    
    
    this.adaptee = adaptee;
  }
  // 定义一个适配方法
  getData() {
    
    
    // 将适配对象的数据转换成目标格式
    const data = this.adaptee.data.map(item => ({
    
    
      id: item._id,
      name: item._name,
      value: item._value,
    }));
    // 返回目标对象
    return data
  }
}

// 定义一个适配对象
const adaptee = {
    
    
  data: [
    {
    
     _id: '1', _name: 'a', _value: '10' },
    {
    
     _id: '2', _name: 'b', _value: '20' },
    {
    
     _id: '3', _name: 'c', _value: '30' },
  ],
};

// 测试
const adapter = new Adapter(adaptee);
console.log(adapter.getData()); // [{ id: '1', name: 'a', value: '10' }, { id: '2', name: 'b', value: '20' }, { id: '3', name: 'c', value: '30' }]
  • Decorator pattern

Decoration pattern is a design pattern that dynamically adds some responsibilities to an object, that is, adds additional functionality. It allows us to create a decorative class to wrap the original object without modifying the original object, thereby extending or modifying the functionality of the original object. The advantage is that the function extension or modification of the original object can be achieved without modifying the original object.

// 定义一个抽象组件类
class Component {
    
    
  // 定义一个抽象方法
  operation() {
    
    
    throw new Error('Abstract method');
  }
}

// 定义一个具体组件类
class ConcreteComponent extends Component {
    
    
  // 实现抽象方法
  operation() {
    
    
    console.log('具体组件的操作');
  }
}

// 定义一个抽象装饰类
class Decorator extends Component {
    
    
  constructor(component) {
    
    
    super();
    // 持有一个组件对象的引用
    this.component = component;
  }
  // 实现抽象方法
  operation() {
    
    
    // 调用组件对象的方法
    this.component.operation();
  }
}

// 定义一个具体装饰类A
class ConcreteDecoratorA extends Decorator {
    
    
  // 实现抽象方法
  operation() {
    
    
    // 调用父类的方法
    super.operation();
    // 执行装饰器自己的操作
    console.log('装饰器A的操作');
  }
}

// 定义一个具体装饰类B
class ConcreteDecoratorB extends Decorator {
    
    
  // 实现抽象方法
  operation() {
    
    
    // 调用父类的方法
    super.operation();
    // 执行装饰器自己的操作
    console.log('装饰器B的操作');
  }
}

// 测试代码
const c = new ConcreteComponent();
const d1 = new ConcreteDecoratorA(c);
const d2 = new ConcreteDecoratorB(d1);
d2.operation();

behavioral

  • Observer pattern

The Observer pattern is a design pattern that defines a one-to-many dependency relationship. When the state of an object (observer) changes, all objects (observers) that depend on it will be notified and automatically updated. In front-end development, we often encounter scenarios that require event-driven or data binding, such as implementing a custom event system or implementing a simple MVVM framework. Using the observer pattern can achieve loose coupling between objects and improve the scalability and testability of the code. Two-way binding in Vue is an observer mode. First use the vmodel command on the dom. When changes occur, notify the parent component to modify the binding value.

// 定义一个被观察者类
class Subject {
    
    
  constructor() {
    
    
    this.state = null; // 被观察者的状态
    this.observers = []; // 观察者列表
  }
  // 添加观察者方法
  attach(observer) {
    
    
    this.observers.push(observer);
  }
  // 移除观察者方法
  detach(observer) {
    
    
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
    
    
      this.observers.splice(index, 1);
    }
  }
  // 更新状态方法
  setState(state) {
    
    
    this.state = state;
    this.notify();
  }
  // 通知观察者方法
  notify() {
    
    
    for (let observer of this.observers) {
    
    
      observer.update(this.state);
    }
  }
}

// 定义一个观察者类
class Observer {
    
    
  constructor(name) {
    
    
    this.name = name;
  }
  // 更新方法
  update(state) {
    
    
    console.log(`${
      
      this.name} received ${
      
      state}`);
  }
}

// 测试
const subject = new Subject();
const observer1 = new Observer('observer1');
const observer2 = new Observer('observer2');
subject.attach(observer1);
subject.attach(observer2);
subject.setState('hello');
subject.detach(observer1);
subject.setState('world');

Summarize

Reasonable use of design patterns can improve the readability of our code and make our development ideas clearer. Therefore, it is of great benefit to ourselves to fully understand these design patterns.

Guess you like

Origin blog.csdn.net/wz9608/article/details/131894685
Recommended