您现在的位置是:首页 > WEB > JSJS

常用的javascript设计模式

阿龙2019-07-15【JS】人已围观

简介说说平时写代码过程中,自己有用过的几种设计模式。

js中的设计模式有很多,我只说一下自己有用到过的比如:
  • 工厂模式
  • 单例模式
  • 观察者模式(发布订阅模式)
  • 代理模式

工厂模式:

概念:

工厂模式的定义:提供创建对象的接口,意思就是根据领导(调用者)的指示(参数),生产相应的产品(对象)。

创建一个对象常常需要复杂的过程,所以不适合在一个复杂的对象中。

创建对象可能会导致大量的重复代码,也可能提供不了足够级别的抽象。

工厂就是把成员对象的创建工作转交给一个外部对象,好处在于消除对象之间的耦合(也就是相互影响)

分类:

简单工厂模式:使用一个类,通常为单体,来生成实例。

复杂工厂模式定义是:将其成员对象的实列化推到子类中,子类可以重写父类接口方法以便创建的时候指定自己的对象类型。

父类只对创建过程中的一般性问题进行处理,这些处理会被子类继承,子类之间是相互独立的,具体的业务逻辑会放在子类中进行编写。

代码实现:

简单工厂模式: 

var XMLHttpFactory =function(){};      //这是一个简单工厂模式
  XMLHttpFactory.createXMLHttp =function(){
    var XMLHttp = null;
    if (window.XMLHttpRequest){
      XMLHttp = new XMLHttpRequest()
    }else if (window.ActiveXObject){
      XMLHttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
  return XMLHttp;
  }
  //XMLHttpFactory.createXMLHttp()这个方法根据当前环境的具体情况返回一个XHR对象。
  var AjaxHander =function(){
    var XMLHttp = XMLHttpFactory.createXMLHttp();
    ...
  }

应用场景:

以下几种情景下工厂模式特别有用:

(1)对象的构建十分复杂

(2)需要依赖具体环境创建不同实例

(3)处理大量具有相同属性的小对象

优点:

可以实现一些相同的方法,这些相同的方法我们可以放在父类中编写代码,那么需要实现具体的业务逻辑,那么可以放在子类中重写该父类的方法,去实现自己的业务逻辑;

也就是说有两点:  

 1、弱化对象间的耦合,防止代码的重复。在一个方法中进行类的实例化,可以消除重复性的代码。

 2、重复性的代码可以放在父类去编写,子类继承于父类的所有成员属性和方法,子类只专注于实现自己的业务逻辑。

缺点:

当工厂增加到一定程度的时候,提升了代码的复杂度,可读性下降。而且没有解决对象的识别问题,即怎么知道一个对象的类型。
 

单例模式

概念:

单例模式定义了一个对象的创建过程,此对象只有一个单独的实例,并提供一个访问它的全局访问点。也可以说单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。

代码实现:

单例的实现有很多种,下面只介绍其中的一种,使用闭包方式来实现单例,代码如下:

var single = (function(){
  var unique;
  function getInstance(){
    // 如果该实例存在,则直接返回,否则就对其实例化
    if( unique === undefined ){
      unique = new Construct();
    }
    return unique;
  }
  function Construct(){
    // ... 生成单例的构造函数的代码
  }
  return {
    getInstance : getInstance
  }
})();

上面的代码中,unique便是返回对象的引用,而 getInstance便是静态方法获得实例。Construct 便是创建实例的构造函数。

可以通过 single.getInstance() 来获取到单例,并且每次调用均获取到同一个单例。这就是 单例模式 所实现的效果。

使用场景:

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如全局缓存、浏览器的window对象。在js开发中,单例模式的用途同样非常广泛。试想一下,当我们

单击登录按钮的时候,页面中会出现一个登录框,而这个浮窗是唯一的,无论单击多少次登录按钮,这个浮窗只会被创建一次。因此这个登录浮窗就适合用单例模式。
 

观察者模式(发布订阅模式)

概念:

定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新,也被称为是发布订阅模式。

它需要一种高级的抽象策略,以便订阅者能够彼此独立地发生改变,而发行方能够接受任何有消费意向的订阅者。

应用场景:  

这个模式要先说应用场景,比较好理解。

打一个离我们比较近的一个场景,博客园里面有一个订阅的按钮(貌似有bug),比如小A,小B,小C都订阅了我的博客,当我的博客一有更新时,就会统一发布邮件给他们这三个人,就会通知这些订阅者

发布订阅模式的流程如下:

  1. 确定谁是发布者(比如我的博客)。

  2. 然后给发布者添加一个缓存列表,用于存放回调函数来通知订阅者。

  3. 发布消息,发布者需要遍历这个缓存列表,依次触发里面存放的订阅者回调函数。

  4. 退订(比如不想再接收到这些订阅的信息了,就可以取消掉)

代码如下:

var pubsub = {};  // 定义发布者
(function (q) {
  var list = [], //回调函数存放的数组,也就是记录有多少人订阅了我们东西
    subUid = -1;
  // 发布消息,遍历订阅者
  q.publish = function (type, content) {
    // type 为文章类型,content为文章内容
    // 如果没有人订阅,直接返回
    if (!list[type]) {
      return false;
    }
    setTimeout(function () {
      var subscribers = list[type],
        len = subscribers ? subscribers.length : 0;
 
      while (len--) {
        // 将内容注入到订阅者那里
        subscribers[len].func(type, content);
      }
    }, 0);
    return true;
  };
  //订阅方法,由订阅者来执行
  q.subscribe = function (type, func) {
    // 如果之前没有订阅过
    if (!list[type]) {
      list[type] = [];
    }
    // token相当于订阅者的id,这样的话如果退订,我们就可以针对它来知道是谁退订了。
    var token = (++subUid).toString();
    // 每订阅一个,就把它存入到我们的数组中去
    list[type].push({
      token: token,
      func: func
    });
    return token;
  };
  //退订方法
  q.unsubscribe = function (token) {
    for (var m in list) {
      if (list[m]) {
        for (var i = 0, j = list[m].length; i < j; i++) {
          if (list[m][i].token === token) {
            list[m].splice(i, 1);
            return token;
          }
        }
      }
    }
    return false;
  };
} (pubsub));
//将订阅赋值给一个变量,以便退订
var girlA = pubsub.subscribe('js类的文章', function (type, content) {
  console.log('girlA订阅的'+type + ": 内容内容为:" + content);
});
var girlB = pubsub.subscribe('js类的文章', function (type, content) {
  console.log('girlB订阅的'+type + ": 内容内容为:" + content);
});
var girlC = pubsub.subscribe('js类的文章', function (type, content) {
  console.log('girlC订阅的'+type + ": 内容内容为:" + content);
});
//发布通知
pubsub.publish('js类的文章', '关于js的内容'); 
// 输出:
// girlC订阅的js类的文章: 内容内容为:关于js的内容
// test3.html:78 girlB订阅的js类的文章: 内容内容为:关于js的内容
// test3.html:75 girlA订阅的js类的文章: 内容内容为:关于js的内容
//girlA退订了关于js类的文章 
setTimeout(function () {
  pubsub.unsubscribe(girlA);
}, 0);
//再发布一次,验证一下是否还能够输出信息
pubsub.publish('js类的文章', "关于js的第二篇文章");
// 输出:
// girlB订阅的js类的文章: 内容内容为:关于js的第二篇文章
// girlC订阅的js类的文章: 内容内容为:关于js的第二篇文章

代码可以自己运行一遍,这样比较好理解

优缺点:

优点:当我们需要维护相关对象的一致性的时候,使用观察者模式,,就可以避免对象之间的紧密耦合。例如,一个对象可以通知另外一个对象,而不需要知道这个对象的信息。

缺点:在发布/订阅模式中,如果我们需要将发布者同订阅者上解耦,将会在一些情况下,导致很难确保我们应用中的特定部分按照我们预期的那样正常工作。也就是说它的优点也可能是它的缺点
 

代理模式

概念:

代理模式的中文含义就是帮别人做事,javascript的解释为:把对一个对象的访问, 交给另一个代理对象来操作.

代码实现:

比如我们公司的补打卡是最后是要交给大boss来审批的,但是公司那么多人,每天都那么多补打卡,那大boss岂不是被这些琐事累死。所以大boss下会有一个助理,来帮

忙做这个审批,最后再将每个月的补打卡统一交给大boss看看就行。

// 补打卡事件
var fillOut = function (lateDate) {
  this.lateDate = lateDate;
};
// 这是bigBoss
var bigBoss = function (fillOut) {
  this.state = function (isSuccess) {
    console.log("忘记打卡的日期为:" + fillOut.lateDate + ", 补打卡状态:" + isSuccess);
  }
};
// 助理代理大boss 完成补打卡审批
var proxyAssis = function (fillOut) {
  this.state = function (isSuccess) {
    (new bigBoss(fillOut)).state(isSuccess); // 替bigBoss审批
  }
};
// 调用方法:
var proxyAssis = new proxyAssis(new fillOut("2016-9-11"));
proxyAssis.state("补打卡成功");
// 忘记打卡的日期为:2016-9-11, 补打卡状态:补打卡成功

应用场景:

比如图片的懒加载,我们就可以运用这种技术。在图片未加载完成之前,给个loading图片,加载完成后再替换成实体路径。

以上代码整理于“咸鱼老弟”,地址:https://www.jb51.net/article/102687.htm

Tags:javascript   设计模式

支持一下! ()

文章评论

    共有条评论大侠,来闹两句...

    请输入昵称:

    填入验证码:

打赏本站

  • 如果您觉得站长文章不错,可以通过扫码支付打赏一下哦!
  • 微信扫码:您说多少就多少~
  • 支付宝扫码:您说多少就多少~