前端面试题目整理——设计模式

作用

JavaScript设计模式的作用 - 提高代码的重用性,可读性,使代码更容易的维护和扩展。

目录

  1. 单例模式
  2. 工厂模式
  3. 抽象工厂模式
  4. 策略模式
  5. 模板方法模式
  6. 职责链模式
  7. 发布订阅者模式
  8. 桥接模式
  9. 适配器模式
  10. 代理模式

正文

  • 单例模式

确保一个类仅有一个实例,并提供一个访问它的全局访问点。一般我们是这样实现单例的,用一个变量来标志当前的类已经创建过对象,如果下次获取当前类的实例时,直接返回之前创建的对象即可

单例模式下对象只会实例化一次,我们可以利用闭包,当该对象已经存在的时候,直接返回该对象,否则重新创建

var singleton = function( fn ){
    var result;
    return function(){
        return result || ( result = fn .apply( this, arguments ) );
    }
}
var createMask = singleton( function(){
return document.body.appendChild( document.createElement('div') );
 })

http://www.alloyteam.com/2012/10/common-javascript-design-patterns/

  • 工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
工厂就是把成员对象的创建工作转交给一个外部对象,好处在于消除对象之间的耦合(何为耦合?就是相互影响)。通过使用工厂方法而不是new关键字及具体类,可以把所有实例化的代码都集中在一个位置,有助于创建模块化的代码,这才是工厂模式的目的和优势。

能解决多个相似的问题,但不能知道对象识别的问题(对象的类型不知道)
使用工厂模式生成xhr

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

将其成员对象的实列化推迟到子类中,子类可以重写父类接口方法以便创建的时候指定自己的对象类型。 父类就变成了一个抽象类,但是父类可以执行子类中相同类似的方法,具体的业务逻辑需要放在子类中去实现。

定义函数实现子类继承父类,然后子类重写父类中的抽象方法。
工厂中定义多个抽象类,实现具体子类继承抽象类
实现方式—>https://segmentfault.com/a/1190000012422055

  • 策略模式

定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
使用策略模式重构代码,可以消除程序中大片的条件分支语句。在实际开发中,我们通常会把算法的含义扩散开来,使策略模式也可以用来封装一系列的“业务规则”。只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以使用策略模式来封装他们

普通模式

  var awardS = function (salary) {
    return salary * 4
  };

  var awardA = function (salary) {
    return salary * 3
  };

  var awardB = function (salary) {
    return salary * 2
  };

  var calculateBonus = function (level, salary) {
    if (level === 'S') {
      return awardS(salary);
    }
    if (level === 'A') {
      return awardA(salary);
    }
    if (level === 'B') {
      return awardB(salary);
    }
  };

  calculateBonus('A', 10000);

策略模式

  var strategies = {
    'S': function (salary) {
      return salary * 4;
    },
    'A': function (salary) {
      return salary * 3;
    },
    'B': function (salary) {
      return salary * 2;
    }
  }

  var calculateBonus = function (level, salary) {
    return strategies[level](salary);
  }

  calculateBonus('A', 10000);
  • 模板方法模式

模板方法模式使用了原型链的方法,封装性好,复用性差
模板方法模式由二部分组成,第一部分是抽象父类,第二部分是具体实现的子类,一般的情况下是抽象父类封装了子类的算法框架,包括实现一些公共方法及封装子类中所有方法的执行顺序,子类可以继承这个父类,并且可以在子类中重写父类的方法,从而实现自己的业务逻辑。

模板方法是基于继承的设计模式,可以很好的提高系统的扩展性。 java中的抽象父类、子类
模板方法有两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。

实现:父类定义方法,子类实现方法(抽象工厂模式封装了继承函数)。
示例---->https://blog.csdn.net/ligang2585116/article/details/50365276

  • 职责链模式

职责链,一系列可能处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇到一个可以处理它的对象,减少了很多重复代码。

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

https://div.io/topic/1800#1职责链模式的定义

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

发布订阅模式,顾名思义,就是一个发布消息,一个监听消息,当有消息接收时处理消息。

function Publisher(name) {
    this.name = '报纸' + name
    // 订阅了本出版社的读者列表
    this.subscribers = [];
}

// 添加一个迭代方法,遍历所有投递列表 
Publisher.prototype.deliver = function(data) {
    // 遍历当前出版社对象所有的订阅过的方法
    const context = this
    this.subscribers.forEach(function(fn) {
        //data用于传参数给内部方法
        fn.fire(context.name, data);
    });
    return this;
}


// 观察者
function Observe(callback) {
    this.fire = callback;
}

// 给予订阅者阅读的能力
Observe.prototype.subscribe = function(publisher) {

    var that = this;
    // some如果有一个返回值为true则为true
    var alreadyExists = publisher.subscribers.some(function(el){
        // 这里的el指的是函数对象
        return el.fire === that.fire // 查看是否已经订阅了,如果订阅了就不再订阅
    });

    // 如果存在这个函数对象则不进行添加
    if (!alreadyExists) {
        publisher.subscribers.push(this);
    }
    return this;
};

// 给予观察者退订的能力
Observe.prototype.unsubscribe = function(publisher) {

    var that = this;

    // 过滤,将返回值为true的重组成数组
    publisher.subscribers = publisher.subscribers.filter(function(el) {

        // 这里的el.fire指的是观察者传入的callback
        // that.fire就是当前对象对callback的引用
        return !(el.fire === that.fire) // 删除掉订阅
    })
    return this;
};

var publisher1 = new Publisher('xixi');

// 实例化的读者,这个需要改进
var observer1 = new Observe(function(publisher, text) {
        console.log('得到来自'+publisher +'的订阅消息:'+ text + ',哈哈哈')
});
var observer2 = new Observe(function(publisher, text) {
    console.log('得到来自'+publisher +'的订阅消息:'+ text + ',嘻嘻嘻')
});

// 读者订阅了一家报纸,在报社可以查询到该读者已经在订阅者列表了,
// publisher1.subscribers->[observer1]
observer1.subscribe(publisher1);
observer2.subscribe(publisher1)                                                     
// 分发报纸,执行所有内在方法
publisher1.deliver(13);// 输出123

// 退订
observer1.unsubscribe(publisher1);
publisher1.deliver(12388);
  • 桥接模式
    https://segmentfault.com/a/1190000012547750
  • 适配器模式

适配器模式(Adapter)是将一个类(对象)的接口(方法或属性)转化成客户希望的另外一个接口(方法或属性),适配器模式使得原本由于接口不兼容而不能一起工作的那些类(对象)可以一些工作。

https://segmentfault.com/a/1190000012436538

  • 代理模式

代理模式的定义是把对一个对象的访问, 交给另一个代理对象来操作.

保护代理、虚拟代理(图片预加载)、缓存代理
https://juejin.im/post/5a68491cf265da3e5661b342#heading-0

你可能感兴趣的:(javascript,面试)