最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 『面试的底气』—— 设计模式之开放封闭原则|8月更文挑战

    正文概述 掘金(红尘炼心)   2021-08-03   339

    前言

    在面试高级前端时,往往会遇到一些关于设计模式的问题,每次都回答不太理想。恰逢8月更文挑战的活动,准备用一个月时间好好理一下关于设计模式方面的知识点,给自己增加点面试的底气。

    在学习设计模式之前,首先要认识到设计模式是个编程思想,对任何编程语言都适用。其次要从设计模式的原则开始学习,故本文将详细介绍设计模式的原则之一开放封闭原则

    官方定义

    开放-封闭原则是说软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。

    自己的理解

    在开发任何系统时,不要指望系统一开始时需求确定,就再也不会发生变化,这是不切实际的想法,既然需求是一定会发生变化的,那么如何设计才能面对需求的改变,不至于修改大部分的代码导致系统不稳定。

    既然修改会导致系统不稳定,那么就少修改,不改变代码的主题,使用扩展的方式添加新需求的代码。这就是开放-封闭,是对扩展是开放的,对修改是封闭的。

    举一个职场中很常见的现象来解释开放-封闭原则。弹性打卡制度,大家都很熟悉吧,这个制度就是一个很好的开放-封闭原则的应用。

    在一家小公司,8点上班,但是有几个骨干员工经常迟到,老板看眼里,心里想这种现象非常不好,于是叫来人事主管提起这个现象,说往后迟到要扣钱,人事主管听了跟老板建议到:“我从考勤记录得知那几个骨干晚上都加班比较晚,加上我们又没有给加班费,这么做,难免会让人心生不满导致人员流失,建议改成弹性上班,比如早上8点到10点弹性,晚上6点到8点弹性下班”。老板听了,想到还是一天工作8个小时没变,于是说到:“先按这样执行一段时间,看看效果”。

    在以上的案例中,老板说往后迟到要扣钱,就是修改原本的考勤逻辑代码,可能会导致员工(系统)离职(不稳定)。而人事主管改成弹性上班的建议,只是原本的考勤逻辑代码中扩展出一种计算考勤的方法,其考勤时间还是8个小时不变的,不会导致员工(系统)离职(不稳定)。

    实现

    1、动态装饰函数的方式

    Function的原型链上添加一个extend方法来对函数进行扩展,在extend中利用_this.apply(this , arguments)执行要扩展的函数,并将直接结果result返回。然后执行fun.apply(this , arguments),其中fun就是调用函数extend时传入的要扩展的函数。这样不去修改函数的原有代码,也能往函数中添加新的逻辑,实现了开放-封闭。

    Function.prototype.extend = function(fun){
      var _this = this;
      return function(){
         const result = _this.apply(this , arguments);
         fun.apply(this , arguments);
         return result
      }
    }
    const a = () =>{
        //旧的逻辑代码
    }
    const b = a.extend(() =>{
       //新增逻辑代码
    })
    

    2、利用多态的思想

    多态的含义:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。或者换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的 反馈。

    多态的思想是将“做什么”和“谁去做以及怎样去做”分离开来,也就是将“不变的事物”与“可能改变的事物”分离开来。正好符合开放-封闭原则。

    下面先提供一段不符合开放-封闭原则的代码,再利用多态的思想来将其改造成符合开放-封闭原则。

    class A {
      constructor() {}
      init() {
        console.log('初始化A');
      }
    }
    class B {
      constructor() {}
      init() {
        console.log('初始化B');
      }
    }
    
    const init = (type) => {
      if (type === 'A') {
        new A().init();
      } else if (type === 'B') {
        new B().init();
      }
    };
    
    init('A');
    init('B');
    

    init函数中通过判断传入type来分别初始化A类和B类,假若又来一个C类,要用init函数来初始化,要怎么办呢?直接修改init函数:

    class C {
      constructor() {}
      init() {
        console.log('初始化C');
      }
    }
    const init = (type) => {
      if (type === 'A') {
        new A().init();
      } else if (type === 'B') {
        new B().init();
      }else if(type === 'C'){
        new C().init();
      }
    };
    

    若是这样处理,往后每新增一个类要初始化,都要去改动init函数的内部实现,是违背了开放-封闭原则。

    利用多态的思想,把程序中不变的部分隔离出来(都会调用类的init方法进行初始化), 然后把可变的部分(类的实例化)封装起来,这样一来程序就具有了可扩展性。故可以这样改造init函数。

    const init = (obj) =>{
      if(obj.init instanceof Function){
        obj.init();
      }
    }
    init(new A());
    init(new B());
    init(new C());
    

    3、利用回调函数

    函数可以作为参数传递给另外一个函数,把这个函数称为回调函数。

    可以把一部分易于变化的逻辑封装在回调函数中,然后把回调函数当作参数传入一个稳定和封闭的函数中,该函数是封闭的,不能轻易修改的。

    当一个函数要扩展时,可以把扩展的逻辑写入回调函数,当回调函数被执行时,就相当函数被扩展了,从而实现了开放-封闭原则。

    Jq的ajax就是利用了回调函数进行扩展,每次请求回来的数据都用回调函数进行处理。

    var getUserInfo = function( callback ){
       $.ajax( 'http:// xxx.com/getUserInfo', callback );
    };
    getUserInfo( function( data ){
       console.log( data.userName );
    });
    getUserInfo( function( data ){
       console.log( data.userId );
    }); 
    

    4、利用钩子函数

    在函数中容易发生变化的地方放置钩子函数,当函数执行到该地方时就会触发钩子函数,钩子函数中写入扩展的逻辑,就相当函数被扩展了,从而实现了开放-封闭原则。

    难点

    遵循开放-封闭原则的开发过程中,最难的是要找到将要发生变化的地方。将变化的封装起来,可以把系统中稳定不变的部分和容易变化的部分隔离开来。在系统的演变过程中,我们只需要替换那些容易变化的部分,如果这些部分是已经被封装好的,那么替换起来也相对容易。而变化部分之外的就是稳定的部分。在系统的演变过程中,稳定的部分是不需要改变的。

    开发时一开始就尽量遵守开放-封闭原则,并不是一件很容易的事情。

    一方面,我们需要尽快知道程序在哪些地方会发生变化,这要求我们有一些未卜先知的能力。

    另一方面,留给程序员的需求排期并不是无限的,所以我们可以说服自己去接受不合理的代码带来的坑。

    在最初开发的时候,先假设变化永远不会发生,这有利于我们迅速完成需求。当变化发生并 且对我们接下来的工作造成影响的时候,可以再回过头来封装这些变化的地方。然后确保我们不 会掉进同一个坑里。


    起源地下载网 » 『面试的底气』—— 设计模式之开放封闭原则|8月更文挑战

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元