设计模式有哪些

  1. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。

  2. 工厂模式(Factory Pattern):通过工厂方法创建对象,而不是直接使用 new 关键字。可以根据不同的条件创建不同类型的对象。

  3. 观察者模式(Observer Pattern):定义了一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。

  4. 发布-订阅模式(Pub-Sub Pattern):类似于观察者模式,但发布者和订阅者之间没有直接依赖关系。发布者将消息发布到通道,订阅者从通道订阅感兴趣的消息。

  5. 代理模式(Proxy Pattern):为一个对象提供一个代理,以控制对该对象的访问。可以用于实现缓存、延迟加载、权限控制等功能。

  6. 适配器模式(Adapter Pattern):将一个接口转换为客户端所期望的另一个接口,以解决接口不兼容的问题。

  7. 装饰器模式(Decorator Pattern):动态地给对象添加额外的行为或责任,而不需要修改原始对象的结构。

  8. 策略模式(Strategy Pattern):定义一系列算法,并将每个算法封装成独立的对象,使得它们可以相互替换。客户端可以灵活地选择不同的策略对象。

  9. MVC 模式(Model-View-Controller Pattern):将应用程序划分为模型(数据)、视图(展示)和控制器(逻辑)三个部分,以实现分离关注点和提高代码的可维护性。

  10. MVVM 模式(Model-View-ViewModel Pattern):在 MVC 模式的基础上引入视图模型(ViewModel),通过数据绑定实现视图和数据的双向绑定。

以上列举的设计模式只是一部分,在前端开发中还有其他许多设计模式可以应用。选择合适的设计模式有助于提高代码的可读性、可维护性和可扩展性,同时促进团队合作和代码重用。

 

demo

 单例模式

下面是一个在 JavaScript 中实现单例模式的代码示例:

const Singleton = (function() {
  let instance; // 私有变量,用于存储单例实例

  function createInstance() {
    // 创建单例实例的逻辑
    const object = new Object('I am the Singleton instance');
    return object;
  }

  return {
    getInstance: function() {
      // 如果实例不存在,则创建实例;如果实例已存在,则直接返回
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// 使用单例模式创建实例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // 输出:true,表示两个实例是同一个实例

在上述示例中,通过使用立即执行函数创建一个自执行的匿名函数,将单例实例和创建实例的逻辑封装在其中。instance 变量用于存储单例实例。

getInstance 方法是对外暴露的接口,用于获取单例实例。当第一次调用 getInstance 方法时,如果实例不存在,则调用 createInstance 函数创建实例,并将其赋值给 instance 变量。如果实例已存在,则直接返回现有的实例。

通过单例模式,我们可以确保在整个应用程序中只有一个实例存在,并提供了全局访问点来获取该实例。这在需要共享资源、避免重复创建对象或确保一致性的场景下非常有用。

工厂模式

下面是一个在 JavaScript 中实现工厂模式的代码示例:

// 定义一个工厂函数
function createProduct(type) {
  if (type === 'A') {
    return new ProductA();
  } else if (type === 'B') {
    return new ProductB();
  } else {
    throw new Error('Invalid product type.');
  }
}

// 定义产品类
function ProductA() {
  this.name = 'Product A';
  this.price = 100;
}

ProductA.prototype.getInfo = function() {
  console.log('Name: ' + this.name + ', Price: ' + this.price);
};

function ProductB() {
  this.name = 'Product B';
  this.price = 200;
}

ProductB.prototype.getInfo = function() {
  console.log('Name: ' + this.name + ', Price: ' + this.price);
};

// 使用工厂模式创建对象
const product1 = createProduct('A');
const product2 = createProduct('B');

product1.getInfo();  // 输出:Name: Product A, Price: 100
product2.getInfo();  // 输出:Name: Product B, Price: 200

在上述示例中,createProduct 是一个工厂函数,根据传入的参数 type 创建不同类型的产品对象。在工厂函数内部,根据 type 的值使用条件语句进行判断,并实例化相应的产品对象。

ProductAProductB 是具体的产品类,它们都有相同的方法 getInfo,但具体的实现可能不同。

通过工厂模式,我们可以将对象的创建逻辑封装在工厂函数中,客户端只需调用工厂函数并传入相应的参数,即可获得所需的产品对象,而无需关心具体的实例化过程。

工厂模式可以使代码更具可维护性和可扩展性,特别是当需要创建多个相关对象时,可以通过工厂方法统一管理对象的创建过程。

观察者模式

下面是一个简单的示例代码,演示了如何使用观察者模式:

// 主题(被观察者)
class Subject {
  constructor() {
    this.observers = []; // 观察者列表
  }

  // 添加观察者
  addObserver(observer) {
    this.observers.push(observer);
  }

  // 移除观察者
  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
      this.observers.splice(index, 1);
    }
  }

  // 通知观察者
  notifyObservers(data) {
    this.observers.forEach(observer => {
      observer.update(data);
    });
  }
}

// 观察者
class Observer {
  update(data) {
    console.log('Received data:', data);
    // 执行相应的操作
  }
}

// 创建主题和观察者
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

// 将观察者添加到主题
subject.addObserver(observer1);
subject.addObserver(observer2);

// 主题状态变化时,通知观察者
subject.notifyObservers('Hello, observers!');

在上述示例中,Subject 是主题类,负责维护观察者列表并在状态变化时通知观察者。Observer 是观察者类,实现了 update 方法来响应主题的通知。

通过使用观察者模式,主题和观察者之间的耦合度降低,主题无需关心具体的观察者,而观察者只需注册到主题并等待通知。这种松散的耦合使得系统更加灵活和可扩展,方便添加新的观察者或处理复杂的交互逻辑。

观察者模式在前端开发中广泛应用,例如事件订阅/发布系统、响应式编程等,用于处理组件之间的通信、状态管理和数据更新等场景。

发布订阅模式

下面是一个使用发布-订阅模式的简单示例:

// 创建一个事件通道
const channel = {};

// 订阅者A
const subscriberA = {
  id: 'A',
  onMessage: function(message) {
    console.log(`Subscriber A received message: ${message}`);
  }
};

// 订阅者B
const subscriberB = {
  id: 'B',
  onMessage: function(message) {
    console.log(`Subscriber B received message: ${message}`);
  }
};

// 发布者
const publisher = {
  publish: function(message) {
    console.log(`Publisher sends message: ${message}`);
    // 遍历通道上的订阅者,并通知它们
    for (let subscriber in channel) {
      if (channel.hasOwnProperty(subscriber)) {
        channel[subscriber].onMessage(message);
      }
    }
  }
};

// 订阅者A订阅通道
channel[subscriberA.id] = subscriberA;
// 订阅者B订阅通道
channel[subscriberB.id] = subscriberB;

// 发布者发布消息到通道
publisher.publish('Hello, subscribers!');
​

在上述示例中,channel 是事件通道,订阅者可以通过将自身添加到通道上来订阅事件。publisher 是发布者,它将消息发布到通道上,并通过遍历通道上的订阅者来通知它们。

通过使用发布-订阅模式,发布者和订阅者之间的耦合度降低,它们不需要直接知道彼此的存在,而是通过通道进行交互。这样可以提高代码的可扩展性和灵活性,使得系统中的各个模块更加独立和可重用。

发布-订阅模式常用于事件驱动的系统、跨组件通信、解耦合的消息传递等场景,在前端开发中广泛应用于事件订阅/发布、消息总线、状态管理库等方面。