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

    正文概述 掘金(红尘炼心)   2021-08-25   437

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

    前言

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

    什么是命令模式

    用一个生活例子来介绍。假如你是一家餐厅的服务员,那么你的工作应该是这样的:

    当某位客人点餐后,你要根据客人点的菜在电脑上创建一条订单,创建成功后,这条订单进入订单列表中,厨房会收到新订单提醒开始做菜,客人不用关心是那位厨师帮他炒菜,只要在桌子上等菜就行。

    当某位客人打电话订餐,要求一个小时后开始炒他的菜,你要根据客人点的菜在电脑上创建一条订单,并注明一个小时后开始炒,厨房会在一个小时后收到新订单提醒开始做菜。假如过了半个小时,客人有事来不了,打电话过来取消了,你要在订单列表找到这个客人的订单,取消订单即可,如果超过一个小时,就不能取消订单了。

    如果有太多的客人点餐,厨房可以按照订单列表中的订单顺序排队炒菜。

    上面就是一种命令模式,客人到餐厅吃饭,本质上是客人向厨师发起请求,厨师接收到请求后开始炒菜,但是客人不认识厨师,怎么办呢?餐厅就靠订单列表把客人和厨师关联起来,通过订单列表,客人就可以命令厨师开始炒菜,这些记录着订餐信息的订单列表,便是命令模式中的命令对象。

    命令模式的用途

    命令模式中的命令(command)指的是一个执行某些特定事情的指令。其最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。

    拿订餐来说,客人需要向厨师发送请求,但是客人完全不知道这些厨师的名字和联系方式。命令模式把客人订餐的请求封装成command对象,也就是订餐中的订单列表对象。这个对象可以在程序中被四处传递,就像订单列表可以从服务员手中传到厨师的手中。这样一来,客人就不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系。

    另外,相对于过程化的请求调用,command对象拥有更长的生命周期。对象的生命周期是跟初始请求无关的,因为这个请求已经被封装在了command对象的方法中,成为了这个对象的行为。我们可以在程序运行的任意时刻去调用这个方法,就像厨师可以在客人预定一个小时之后才帮他炒菜,相当于程序在一个小时之后才开始执行command对象的方法。除此之外,命令模式还支持撤销、排队等操作。

    实践命令模式

    假设正在开放一个餐厅订餐系统的界面,该界面有非常多个 Button 按钮,且这些按钮都用权限来控制。因为权限控制比较复杂,所以决定让一个程序员专门负责绘制这些按钮,而另外一个程序员则负责编写点击按钮后的具体行为,且这些行为都将被封装在对象里。

    对于绘制按钮的程序员来说,他完全不知道某个按钮未来将用来做什么,可能用来刷新订单列表,也可能用来增加订单,他只知道点击这个按钮会发生某些事情。那么当完成这个按钮的绘制之后,应该如何给它绑定 onclick 事件呢?或许你很快就给出解决方案了。

    <body>
      <button id="button1">点击按钮 1</button>
      <button id="button2">点击按钮 2</button>
      <button id="button3">点击按钮 3</button>
    </body>
    <script>
      const button1 = document.getElementById( 'button1' ),
      const button2 = document.getElementById( 'button2' ),
      const button3 = document.getElementById( 'button3' );
    </script>
    const bindClick = (button,func) =>{
      button.onclick = func;
    };
    const OrderList = {
      refresh(){
        console.log( '刷新订单列表' );
      },
    };
    const Order = {
      add(){
        console.log( '增加订单' );
      },
      del(){
        console.log( '删除订单' );
      }
    };
    bindClick( button1, OrderList.refresh); 
    bindClick( button2, Order.add);
    bindClick( button3, Order.del);
    

    上面的代码的确可以解决上述的需求,但是发送请求者bindClick( button1, Order.refresh)和请求接收者Order耦合在一起了,只要修改了Order对象的方法名,发送请求者也得跟着修改。

    回顾一下上文介绍的命令模式的用途,我们可以使用命令模式来实现上述需求,就可以消除请求发送者和请求接收者之间的耦合关系

    构建命令对象

    如何构建命令对象command是实现命令模式的关键。设计模式的主题总是把不变的事物和变化的事物分离开来,命令模式也不例外。所以在上述需求中,点击按钮后,会固定执行命令对象command的一个方法execute,这是不变的事物,而变化的事物是execute方法中执行接收者receiver中某个方法。

    const command = (receiver) =>{
      return {
        execute(){
          //执行接收者receiver中某个方法
        }
      }
    }
    

    接下来实现上面点击按钮2后会添加订单的功能。

    const OrderCommand = (receiver) =>{
      return {
        execute: function () {
          receiver.add();
        }
      }
    };
    const setCommand = (button, command) =>{
      button.onclick = () =>{
        command.execute();
      }
    };
    const orderCommand = OrderCommand(Order);
    setCommand(button2, orderCommand);
    

    上述代码中OrderCommand是用来创建一个命令对象的函数,setCommand是给按钮上安装命令对象command,点击按钮后就会执行命令对象command中的execute方法。

    执行const orderCommand = OrderCommand(Order)Order这个订单行为集合对象创建一个命令对象。

    此时点击按钮就会执行Order对象中的添加订单的方法add,假如点击按钮不执行添加订单,而是要执行删除订单,只要修改OrderCommand函数即可

    const OrderCommand = (receiver) =>{
      return {
        execute: function () {
          receiver.del();
        }
      }
    };
    

    而不要去同时修改发送请求者和接收请求者的代码,这就达到消除发送请求者和接收请求者之间的耦合关系。


    起源地下载网 » 『面试的底气』—— 设计模式之命令模式(一)|8月更文挑战

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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