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

    正文概述 掘金(红尘炼心)   2021-08-27   431

    这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战

    前言

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

    定义

    模板方法模式是一种只需使用继承就可以实现的非常简单的模式。

    模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。

    在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。

    子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。

    使用场景

    在一些平行的子类中,各子类之间有很多相同的行为,但是之间也有不同的行为,相同和不同的行为都混合在各个子类中实现。可以用模板方法模式来优化一下,把子类实现中的相同部分移到父类中,而将不同的部分留待子类来实现。

    头疼的抽象类

    首先要说明的是,模板方法模式是一种严重依赖抽象类的设计模式。JavaScript 在语言层面并没有提供对抽象类的支持,我们也很难模拟抽象类的实现。我们要在没有抽象类时所做出的让步和变通。

    抽象类的作用

    抽象类是在 Java 中的概念,在 Java 中,类分为两种,一种为具体类,另一种为抽象类。具体类可以被实例化,抽象类不能被实例化。由于抽象类不能被实例化,如果写了一个抽象类,那么这个抽象类一定是用来被某些具体类继承的。

    用一个生活的场景来理解。比如我们去便利店想买一瓶饮料,我们不能直接跟老板说:“来一瓶饮料。”如果我们这样说了,那么老板接下来肯定会问:“要什么饮料?”饮料只是一个抽象类,只有当我们真正明确了的饮料类型之后,才能得到一瓶咖啡、绿茶、红茶、可乐等等。

    抽像方法和具体方法

    抽象方法被声明在抽象类中,抽象方法并没有具体的实现过程,是一些“哑”方法。当子类继承了这个抽象类时,必须重写父类的抽象方法。除了抽象方法之外,如果每个子类中都有一些同样的具体实现方法,那这些方法也可以选择放在抽象类中,这可以节省代码以达到复用的效果,这些方法叫作具体方法。当代码需要改变时,我们只需要改动抽象类里的具体方法就可以了。

    解决 JavaScript 对抽像类的不支持

    JavaScript 并没有从语法层面提供对抽象类的支持。抽象类的第一个作用是隐藏对象的具体类型,由于 JavaScript 是一门“类型模糊”的语言,隐藏对象的类型在 JavaScript 中并不重要。

    所以当我们在 JavaScript 中使用原型继承来模拟 Java 的类式继承时,并没有编译器帮助我们进行任何形式的检查,我们也没有办法保证子类会重写父类中的“抽象方法”。

    有一个非常有用的办法。那就是在抽像类的方法中抛出一个错误。

    class Extraction{
      constructor(){
      }
      a(){
        throw new Error( '子类必须重写 a 方法' ); 
      }
    } 
    

    虽然在编写代码时不会报错,但是在运行代码时会报错,只是这个报错有点晚而已。

    实现一个简单的模板方法模式

    用一个最经典的例子来介绍。咖啡和茶。

    先用程序来实现冲咖啡的过程:

    class Coffee{
      boilWater(){
        console.log( '把水煮沸' );
      }
      brewCoffeeGriends(){
        console.log( '用沸水冲泡咖啡' );
      }
      pourInCup(){
        console.log( '把咖啡倒进杯子' );
      }
      addSugarAndMilk(){
        console.log( '加糖和牛奶' );
      }
      init(){
        this.boilWater();
        this.brewCoffeeGriends();
        this.pourInCup();
        this.addSugarAndMilk();
      }
    }
    const coffee = new Coffee();
    coffee.init(); 
    

    再用程序来实现一下泡茶的过程。

    class Tea{
      boilWater(){
        console.log( '把水煮沸' );
      }
      steepTeaBag(){
        console.log( '用沸水浸泡茶' );
      }
      pourInCup(){
        console.log( '把茶水倒进杯子' );
      }
      addLemon(){
        console.log( '加柠檬' );
      }
      init(){
        this.boilWater();
        this.steepTeaBag();
        this.pourInCup();
        this.addLemon();
      }
    }
    const tea = new Tea();
    tea.init();
    

    比较这两段程序,会发现泡茶和冲咖啡的步骤其实差不多,Coffee类和Tea类中有相同的行为,但是具体上还是有些差异,可以利用模板方法模式,构造一个抽像类Beverage,把Coffee类和Tea类中的行为进行分离出共同点(抽像)后移到抽像类Beverage中,并将其作为他们的父类。

    泡茶冲咖啡抽像处理
    把水煮沸把水煮沸把水煮沸用沸水冲泡咖啡用沸水浸泡茶叶用沸水浸泡原料把咖啡倒进杯子把茶水倒进杯子把饮料倒进杯子加糖和牛奶加柠檬加配料

    我们先进行抽像,对比一下煮茶和煮咖啡过程

    泡茶冲咖啡
    把水煮沸把水煮沸用沸水冲泡咖啡用沸水浸泡茶叶把咖啡倒进杯子把茶水倒进杯子加糖和牛奶加柠檬

    可以发现

    • 原料不同。一个是咖啡,一个是茶,但我们可以把它们都抽象为“饮料”。
    • 泡的方式不同。咖啡是冲泡,而茶叶是浸泡,我们可以把它们都抽象为“泡”。
    • 加入的调料不同。一个是糖和牛奶,一个是柠檬,但我们可以把它们都抽象为“配料”。

    经过抽象之后,不管是冲咖啡还是泡茶,我们都能整理为下面四步:

    • 把水煮沸
    • 用沸水冲泡饮料
    • 把饮料倒进杯子
    • 加配料

    接下来创建一个泡一杯饮料的抽像类Beverage

    class Beverage{
      constructor(){}
      boilWater(){
        console.log( '把水煮沸' );
      }
      brew(){// 用沸水冲泡饮料,空方法,应该由子类重写
        throw new Error( '子类必须重写 brew 方法' ); 
      }
      pourInCup(){// 把饮料倒进杯子,空方法,应该由子类重写
        throw new Error( '子类必须重写 pourInCup 方法' ); 
      }
      addCondiments(){// 加配料,空方法,应该由子类重写
        throw new Error( '子类必须重写 addCondiments 方法' ); 
      }
      init(){
        this.boilWater();
        this.brew();
        this.pourInCup();
        this.addCondiments();
      }
    }
    

    后面冲咖啡和泡茶的过程就可以继承抽像类Beverage来实现。

    class Coffee extends Beverage{
      constructor(){
        super();
      }
      boilWater(){
        console.log( '把水煮沸' );
      }
      brew(){
        console.log( '用沸水冲泡咖啡' );
      }
      pourInCup(){
        console.log( '把咖啡倒进杯子' );
      }
      addCondiments(){
        console.log( '加糖和牛奶' );
      }
    }
    const coffee = new Coffee();
    coffee.init(); 
    

    以上就实现了一个最简单的模板方式模式,其关键还是将子类中的方法进行抽像。


    起源地下载网 » 『面试的底气』—— 设计模式之模板方法模式|8月更文挑战

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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