分享 10 个最受 JavaScript 开发者喜爱的设计模式

1. 构造模式

在经典的面向对象语言中,构造函数是一种特殊的方法,用于在为新创建的对象分配内存之后初始化它。在 JavaScript 万物皆对象,我们最感兴趣就是对象的构造函数了。由于对象构造器用来创建特定类型的对象,就像这样,当对象被第一次创建,它就可以使用准备对象和接受参数来设置成员属性和方法的值。

如我们所见,JavaScript 不支持类这个概念,所以在构造函数中,关键字 this 引用了正在创建的新对象重访问对象创建,基本构造函数可能如下所示:
(译者注:ES6 Class 已经作为标准了)

function Car(model, year, miles) {
  this.model = model;
  this.year = year;
  this.miles = miles;
}

// 使用方法:
var bmw = new Car('M4', '2019', '1000');

2. 模块模式

模块是任何健壮的应用程序体系结构中不可或缺的一部分,通常有助于将项目的代码单元干净地分离和组织起来
几个实现模块的选项,包括:

  • 字面量对象
  • 模块模式
  • AMD 模块
  • CommonJS 模块
  • ECMAScript Harmony 模块

字面量对象:

var newObject = {
  variableKey: variableValue,
  functionKey: function() {
    //…
  }
};

模块模式:

让我们通过创建一个自包含的模块来查看模块模式的实现。

var testModule = (function() {
  var counter = 0;
  return {
    incrementCounter: function() {
      return ++counter;
    },
    resetCounter: function() {
      counter = 0;
    }
  };
})();

// 使用方法:
testModule.incrementCounter();
testModule.resetCounter();

3. 显示模块模式

显示模块可以做的一件事是,当我们要从另一个对象调用一个公共方法或访问公共变量时,避免重复主对象的名称。

var myRevealingModule = (function() {
  var privateVariable = 'not okay',
    publicVariable = 'okay';
  function privateFun() {
    return privateVariable;
  }

  function publicSetName(strName) {
    privateVariable = strName;
  }

  function publicGetName() {
    privateFun();
  }

  return {
    setName: publicSetName,
    message: publicVariable,
    getName: publicGetName
  };
})();

// 使用方法:

myRevealingModule.setName('Marvin King');

4. 单例模式

单例模式众所周知,它时将类的实例化约束为同一个对象。单例对象不同于静态对象,它可以延迟初始化。通常因为他们需要一些信息,而这些在初始化阶段不可用。对于不知道先前对它们的引用的代码,它们不提供便于检索的方法。让我们看看单例的结构:

var singletonPattern = (function() {
  var instance;
  function init() {
    // 单例
    function privateMethod() {
      console.log('privateMethod');
    }
    var privateVariable = 'this is private variable';
    var privateRandomNumber = Math.random();
    return {
      publicMethod: function() {
        console.log('publicMethod');
      },
      publicProperty: 'this is public property',
      getRandomNumber: function() {
        return privateRandomNumber;
      }
    };
  }

  return {
    // 获取单例实例(如果存在)
    // 不存在就创建一个
    getInstance: function() {
      if (!instance) {
        instance = init();
      }
      return instance;
    }
  };
})();

// 使用方法
var single = singletonPattern.getInstance();

5. 观察者模式

观察者是这种设计模式,一个被观察者对象维护着观察者的对象列表,这些对象依赖于被观察者,被观察者自动将自身的状态的任何变化通知给观察者。

  • 被观察者
    • 维护着观察者列表、添加或删除观察者的设备
  • 观察者
    • 提供被观察者的更新接口,需要在被观察者状态更改时通知该对象
  • 具体的被观察者
    • 在状态变化时向观察者广播,存储具体的观察者信息
  • 具体的观察者
    • 存储具体的被观察者引用,为观察者实现一个更新接口,以确保状态与被观察者一致
function ObserverList() {
  this.observerList = [];
}

ObserverList.prototype.Add = function(obj) {
  return this.observerList.push(obj);
};

ObserverList.prototype.Empty = function() {
  this.observerList = [];
};

ObserverList.prototype.Count = function() {
  return this.observerList.length;
};

ObserverList.prototype.Get = function(index) {
  if (index > -1 && index < this.observerList.length) {
    return this.observerList[index];
  }
};

//...

当一个被观察者需要通知一些有信息给观察者,他会发送广播给观察者们(包含与通知主题相关的数据)

当我们不再希望某些观察者收到被观察者的变化通知,可以在被观察者的观察者列表中移除就好。以后,我会更多的讨论观察者在 JavaScript 领域的应用。

6. 中介者模式

如果系统中出现了太多组件之间的直接关系。现在可能需要一个控制的中心点,组件通过它进行通信。中介模式通过确保组件之间不是显式地相互引用,从而促进了松耦合。

var mediator = (function() {
  var topics = {};
  var subscribe = function(topic, fn) {
    if (!topics[topic]) {
      topics[topic] = [];
    }
    topics[topic].push({ context: this, callback: fn });
    return this;
  };

  // 向应用的其他部分发布/广播事件
  var publish = function(topic) {
    var args;
    if (!topics[topic]) {
      return false;
    }
    args = Array.prototype.slice.call(arguments, 1);
    for (var i = 0, l = topics[topic].length; i < l; i++) {
      var subscription = topics[topic][i];
      subscription.callback.apply(subscription.content, args);
    }
    return this;
  };
  return {
    publish: publish,
    subscribe: subscribe,
    installTo: function(obj) {
      obj.subscribe = subscribe;
      obj.publish = publish;
    }
  };
})();

7. 原型模式

使用原型模式的好处之一就是,我们使用 JavaScript 已经提供的原型优势,而不是试图模仿其他语言的特性。让我们看一下模式示例。

var myCar = {
  name: 'bmw',
  drive: function() {
    console.log('I am driving!');
  },
  panic: function() {
    console.log('wait, how do you stop this thing?');
  }
};

//用法:

var yourCar = Object.create(myCar);

console.log(yourCar.name); //'bmw'

8. 工厂模式

工厂可以提供一个通用的接口来创建对象,我们可以在其中指定希望创建的工厂对象的类型。请参见下图。

function Car(options) {
  this.doors = options.doors || 4;
  this.state = options.state || 'brand new';
  this.color = options.color || 'silver';
}

9. Mixin 模式

Mixin 类是提供功能的类,这些类可以被子类或子类组轻松继承,以实现功能重用。

var Person = function(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.gender = 'male';
};

var clark = new Person('Clark', 'kent');

var Superhero = function(firstName, lastName, powers) {
  Person.call(this.firstName, this.lastName);
  this.powers = powers;
};

SuperHero.prototype = Object.create(Person.prototype);
var superman = new Superhero('Clark', 'Kent', ['flight', 'heat-vision']);

console.log(superman); //输出个人的属性和能力

在这种情况下,超级英雄能够覆盖任何继承值与值的具体对象。

10. 装饰模式

装饰器是一种结构设计模式,旨在促进代码重用。与 Mixins 相似,它们可以被认为是对象子类化的另一种可行选择。传统上,装饰器提供了在系统中动态添加行为到现有类的能力。这个想法是装饰本身而并不是类的基本功能所必需的。让我们来看看装饰器是如何在 JavaScript 中工作的。

function MacBook() {
  this.cost = function() {
    return 997;
  };
  this.screenSize = function() {
    return 11.6;
  };
}

// 装饰器 1

function Memory(macbook) {
  var v = macbook.cost();
  macbook.cost = function() {
    return v + 75;
  };
}

// 装饰器 2

function Engraving(macbook) {
  var v = macbook.cost();
  macbook.cost = function() {
    return v + 200;
  };
}

// 装饰器 3

function Insurance(macbook) {
  var v = macbook.cost();
  macbook.cost = function() {
    return v + 250;
  };
}

var mb = new MacBook();

Memory(mb);
Engraving(mb);
Insurance(mb);

mb.cost(); // 1522

所有模式都可能不适用于一个项目,并且一些项目可能会受益于观察者模式提供的解耦的好处。也就是说,一旦我们牢牢掌握了设计模式及其最适合解决的具体问题,集成到我们的应用程序体系结构将变得更加容易。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://dev.to/shijiezhou/top-10-javascr...

译文地址:https://learnku.com/f2e/t/38857

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!