JavaScript 常用设计模式详解:单例、工厂、适配与外观

作者:拾光时间:2026-10-21 21:47:27浏览:458

本文详细介绍 JavaScript 中四种常见的设计模式:单例模式通过闭包实现资源懒加载;工厂模式利用构造函数动态创建对象;适配器模式解决接口兼容性问题;外观模式封装复杂子系统以简化调用。结合具体代码示例,帮助开发者理解并应用这些模式优化前端架构。

JavaScript 作为一种面向对象语言,虽然出现时间较晚,但目前已是最流行的脚本语言之一。随着微信商城等页面的兴起,JavaScript 在前端开发中的地位愈发重要,程序员和互联网从业者都应关注其发展趋势。

若希望在前端领域深入发展,掌握设计模式是必经之路。本文将介绍几种常见的设计模式及其应用场景。

单例模式

一、单例模式

单例模式(也称单子模式或单体模式)是软件设计中简单且常用的一种模式。在 JavaScript 中,实现单例的方式多样,最简单的方式是使用对象字面量,其中可包含大量属性和方法:


var mySingleton = {
property1: "something",
property2: "something else",
method1: function () {
  console.log('hello world');
}};

若需扩展该对象,可添加私有成员和方法,并通过闭包封装这些变量和函数声明。仅暴露所需的公共成员和方法,示例代码如下:


 var mySingleton = function () {
  /* 这里声明私有变量和方法 */
  var privateVariable = 'something private';
  function showPrivate() {
    console.log(privateVariable);
  }
  /* 公有变量和方法(可以访问私有变量和方法) */
  return {
    publicMethod: function () {
      showPrivate();
    },
    publicVar: 'the public can see this!'
  };
};
var single = mySingleton();
single.publicMethod(); // 输出 'something private'
console.log(single.publicVar); // 输出 'the public can see this!'

上述代码已具备良好结构,但若希望实现延迟初始化以节约资源,可在另一个构造函数中初始化代码,如下所示:


var Singleton = (function () {
  var instantiated;
  function init() {
    /*这里定义单例代码*/
    return {
      publicMethod: function () {
        console.log('hello world');
      },
      publicProperty: 'test'
    };
  }
  return {
    getInstance: function () {
      if (!instantiated) {
        instantiated = init();
      }
      return instantiated;
    }
  };
})();
/*调用公有的方法来获取实例:*/
Singleton.getInstance().publicMethod();

工厂模式

二、工厂模式

工厂模式通过一个方法决定创建哪个类的实例,这些实例通常拥有相同的接口。该模式适用于实例类型在编译期无法确定、而在执行期决定的场景。通俗而言,如同公司茶水间的饮料机,选择咖啡或牛奶取决于按下的按钮。

实例:


function A( name ){
       this.name = name;
    }
    function ObjectFactory(){
       var obj = {},
           Constructor = Array.prototype.shift.call( arguments );
obj.__proto__ = typeof Constructor .prototype === 'number' ? Object.prototype
: Constructor .prototype;
       var ret = Constructor.apply( obj, arguments );
       return typeof ret === 'object' ? ret : obj;
    }
    var a = ObjectFactory( A, 'svenzeng' );
    alert ( a.name ); //svenzeng

这段代码源自 ES5 中 new 和构造器的相关说明。可以看出,new 操作本质上是对象的复制和改写过程,具体生成什么由调用 ObjectFactory 时传入的参数决定。

适配模式

三、适配模式

适配模式主要解决接口不兼容问题。借助适配器,可在不修改原有不兼容接口的情况下,为使用者提供统一的包装接口。虽然表面与门面模式相似,均是对其他对象或接口进行包装,但适配器模式侧重于解决兼容性问题,而门面模式侧重于方便性。

例如,一个简单的学生查询学科成绩的方法:


  function selectScore( name, id, course_id ){
  // arguments 姓名 学号 课程id
  ...
}

若需获取班级某门学科的整体成绩列表,而手头仅有每个学生的如下数据:


[
  { name: 'lily', studentID: '0911' },
  { name: 'suny', studentID: '0912' },
  ...
]

假设需查询英语课程(ID 为 101)的成绩,使用适配器方式处理参数兼容性是恰当的选择。


function selectEnglishScore( stutentObj ){
  selectScore( stutentObj.name, stutentObj.studentID , 101);
}

这是最简单的适配器处理参数兼容的形式。简言之,适配器模式的核心在于适配,即解决兼容问题。

示例二:若需将 jQuery 中的 $ 选择器改为 $id 以适配项目,可通过编写方法将 $ 转换为 $id,如下所示:


$id = function( id ){
 return jQuery( '#' + id )[0];
}

外观模式

四、外观模式

外观模式(又称门面模式)是一种简单且无处不在的模式。它提供一个高层接口,使客户端或子系统调用更加便捷。用一段简单的代码表示:


var getName = function(){
 return ''svenzeng"
}
var getSex = function(){
  return 'man'
}

若需分别调用 getName 和 getSex 函数,可使用更高层的接口 getUserInfo 进行调用:


var getUserInfo = function(){
 var info = a() + b();
 return info;
}

或许有人会问,为何不一开始就将 getName 和 getSex 的代码合并,例如:


var getNameAndSex = function(){
 return 'svenzeng" + "man";
}

答案显而易见:正如食堂炒菜师傅不会因预定烧鸭和白菜就将两者炒在一锅中,而是提供烧鸭饭套餐。在程序设计中,需保证函数或对象处于合理粒度,因为并非所有用户都同时需要相同功能。外观模式的优势在于隐藏实现细节,用户只需关注高层接口。例如在烧鸭饭套餐故事中,用户不关心师傅先做烧鸭还是炒白菜,也不关心鸭子来源。

最后,提供一个常见的外观模式示例:


var stopEvent = function( e ){  //同时阻止事件默认行为和冒泡
 e.stopPropagation();
 e.preventDefault();
}

本文介绍的设计模式暂告一段落。若需了解更多设计模式,可参考汤姆大叔的博客。此外,许多设计模式实质是将解决问题的方法细化,如查看 prototype 或 jQuery 源码,会发现其中大量应用了设计模式。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持本站!

作者最新文章