前端常见设计模式

2024-01-08 15:32:57

前端常见设计模式

前端设计模式是在前端开发中常用的一些设计思想或者编程范式,它们旨在解决特定的问题,并提供了一种可复用的解决方案。设计模式可以使代码更加可维护、可扩展,并促使开发者编写更清晰、更高效的代码。

1.外观模式(Facade Pattern)

  • 概念: 外观模式提供了一个高层次的接口,使得子系统更容易使用。它为复杂的子系统提供了一个简化的界面,客户端可以通过这个界面访问子系统的功能。
  • 举例: 在前端开发中,外观模式可以用于隐藏复杂的 API 调用或底层实现,提供一个简单的接口供开发者使用。
// 外观模式的简单示例
class SubsystemA {
  operationA() {
    console.log('Subsystem A: Operation A');
  }
}

class SubsystemB {
  operationB() {
    console.log('Subsystem B: Operation B');
  }
}

class SubsystemC {
  operationC() {
    console.log('Subsystem C: Operation C');
  }
}

class Facade {
  constructor() {
    this.subsystemA = new SubsystemA();
    this.subsystemB = new SubsystemB();
    this.subsystemC = new SubsystemC();
  }

  operate() {
    this.subsystemA.operationA();
    this.subsystemB.operationB();
    this.subsystemC.operationC();
  }
}

// 使用外观模式
const facade = new Facade();
facade.operate();

2.观察者模式(Observer Pattern)

  • 概念: 观察者模式定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
  • 举例: Element UI 中的事件系统就使用了观察者模式。比如,可以监听一个组件的事件,当组件状态发生变化时,触发相应的事件。
// Element UI 的事件监听
this.$refs.myComponent.$on('customEvent', () => {
  // 处理事件的逻辑
});

3.访问者模式(Visitor Pattern)

  • 概念: 访问者模式表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
  • 举例: 在处理复杂数据结构时,访问者模式可用于对数据结构进行不同类型的操作,而不修改数据结构本身。
// 访问者模式的简单示例
class Element {
  accept(visitor) {
    visitor.visit(this);
  }
}

class ConcreteElementA extends Element {}

class ConcreteElementB extends Element {}

class Visitor {
  visit(element) {
    // 执行访问操作
  }
}

class ConcreteVisitor extends Visitor {
  visit(element) {
    // 具体访问操作
  }
}

// 使用访问者模式
const elementA = new ConcreteElementA();
const elementB = new ConcreteElementB();
const visitor = new ConcreteVisitor();

elementA.accept(visitor);
elementB.accept(visitor);

4.中介者模式(Mediator Pattern)

  • 概念: 中介者模式用一个中介对象来封装一系列对象的交互。中介者使对象之间不再直接相互引用,而是通过中介者对象进行交互。
  • 举例: 在前端应用中,中介者模式可用于管理多个组件之间的通信,通过中介者对象处理组件之间的消息传递。
   // 中介者模式的简单示例
   class Mediator {
     constructor() {
       this.colleagueA = new ColleagueA(this);
       this.colleagueB = new ColleagueB(this);
     }

     notify(sender, message) {
       if (sender === this.colleagueA) {
         this.colleagueB.receive(message);
       } else if (sender === this.colleagueB) {
         this.colleagueA.receive(message);
       }
     }
   }

   class ColleagueA {
     constructor(mediator) {
       this.mediator = mediator;
     }

     send(message) {
       this.mediator.notify(this, message);
     }

     receive(message) {
       // 处理收到的消息
     }
   }

   class ColleagueB {
     constructor(mediator) {
       this.mediator = mediator;
     }

     send(message) {
       this.mediator.notify(this, message);
     }

     receive(message) {
       // 处理收到的消息
     }
   }

5.装饰者模式(Decorator Pattern)

  • 概念: 装饰者模式动态地给一个对象添加一些额外的职责,就扩展功能而言,装饰者模式比生成子类更为灵活。
  • 举例: Element UI 的 Input 组件的 prefix-iconsuffix-icon 属性就可以理解为装饰者模式的应用。它们允许你在输入框的前后添加额外的图标。
<!-- Element UI Input 组件的装饰者模式 -->
<el-input
  v-model="inputValue"
  placeholder="请输入内容"
  prefix-icon="el-icon-search"
  suffix-icon="el-icon-edit"
></el-input>

6.工厂模式(Factory Pattern)

  • 概念: 工厂模式提供一个接口用于创建对象,但决定要实例化的类是由子类决定的。工厂方法允许一个类的实例化延迟到其子类。
  • 举例: 在 Vue.js 中,通过组件工厂函数创建全局组件是工厂模式的一种应用。
// Vue.js 中的工厂模式
Vue.component('my-component', {
  // 组件定义
});

7.单例模式(Singleton Pattern)

  • 概念: 单例模式确保一个类只有一个实例,并提供一个全局访问点。
  • 举例: Element UI 中的 MessageBox 组件就是一个单例模式的应用。只有一个全局的 MessageBox 实例,可以通过调用 this.$alertthis.$confirm 等方法来获取并使用。
// Element UI 中的 MessageBox 单例模式
this.$alert('Hello, World!', '提示', {
  confirmButtonText: '确定',
  callback: action => {
    // 处理用户点击确认的逻辑
  }
});

8.策略模式(Strategy Pattern)

  • 概念: 策略模式定义了一系列的算法,将每个算法都封装起来,并使它们可以互相替换,使得算法的变化不会影响到使用算法的客户。
  • 举例: Element UI 的表单验证规则就是策略模式的应用。你可以为一个表单项定义不同的验证规则,使得验证逻辑可以根据具体的需求而变化。
// Element UI 表单验证规则(策略模式)
rules: {
  username: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    // 其他验证规则...
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    // 其他验证规则...
  ],
}

9.迭代器模式(Iterator Pattern)

  • 概念: 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示。
  • 举例: 在处理集合数据时,可以使用迭代器模式遍历集合,而不必关心集合的具体实现。
// 迭代器模式的简单示例
class Iterator {
  constructor(collection) {
    this.collection = collection;
    this.index = 0;
  }

  hasNext() {
    return this.index < this.collection.length;
  }

  next() {
    return this.collection[this.index++];
  }
}

// 使用迭代器遍历数组
const array = [1, 2, 3, 4, 5];
const iterator = new Iterator(array);

while (iterator.hasNext()) {
  console.log(iterator.next());
}

10.适配器模式(Adapter Pattern)

  • 概念: 适配器模式允许将一个接口转换成客户希望的另一个接口。它主要用于解决接口不兼容的问题。
  • 举例: 在使用不同的数据源时,可以通过适配器模式统一数据的接口,以便在应用中统一处理。
// 适配器模式的简单示例
class OldDataSource {
  getData() {
    // 获取数据的逻辑
  }
}

class NewDataSourceAdapter {
  constructor(newDataSource) {
    this.newDataSource = newDataSource;
  }

  getData() {
    // 适配逻辑,将新数据源的接口适配成旧数据源的接口
    return this.newDataSource.fetchData();
  }
}

11.订阅-发布模式(Publish-Subscribe Pattern)

  • 概念: 订阅-发布模式定义了对象间一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并被自动更新。
  • 举例: Vue.js 中的事件总线(Event Bus)是订阅-发布模式的一种应用,通过 $on$emit 方法进行事件的订阅和发布。
// 订阅-发布模式的简单示例(使用 Vue.js 事件总线)
// 创建事件总线
const eventBus = new Vue();

// 组件A 订阅事件
eventBus.$on('customEvent', (data) => {
  // 处理事件的逻辑
});

// 组件B 发布事件
eventBus.$emit('customEvent', eventData);

12.代理模式(Proxy Pattern)

  • 概念: 代理模式为一个对象提供一个代理,以控制对该对象的访问。代理通常充当一个中介,用于控制对真实对象的访问,以便在访问时添加一些额外的逻辑。
  • 举例: 在前端开发中,代理模式常用于处理图片加载、网络请求、权限控制等场景,通过代理对象控制对真实对象的访问。ImageProxy充当了代理的角色,负责控制对真实图片对象RealImage` 的访问。如果图片尚未加载,代理会负责加载图片;如果图片已加载,代理直接显示已加载的图片,而无需再次加载。代理模式通过这种方式提供了更灵活、可控的访问方式。
// 代理模式的简单示例 - 图片加载
class RealImage {
  constructor(filename) {
    this.filename = filename;
    this.loadImage();
  }

  loadImage() {
    console.log(`Loading image: ${this.filename}`);
  }

  display() {
    console.log(`Displaying image: ${this.filename}`);
  }
}

class ImageProxy {
  constructor(filename) {
    this.filename = filename;
    this.image = null;
  }

  display() {
    if (!this.image) {
      this.image = new RealImage(this.filename);
    }
    this.image.display();
  }
}

// 使用代理模式加载图片
const proxyImage = new ImageProxy('example.jpg');
proxyImage.display(); // 图片被加载并显示
proxyImage.display(); // 图片已加载,直接显示

`

文章来源:https://blog.csdn.net/Robinwang1128/article/details/135456535
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。