美文网首页
重新组织函数-Extract Method(提炼函数)

重新组织函数-Extract Method(提炼函数)

作者: 瑾然有昫 | 来源:发表于2019-12-18 12:06 被阅读0次

将这段代码放进一个独立函数中,并合理命名该函数名称
示例:
修改前:

public function printOwing($amount) {
  $this->printBanner();
  print("name: {$this->name}");
  print("amount:{$amount}");
}

修改后:

public function printOwing ($amount) {
  $this->printBanner();
  $this->printDetail($amount);
}

public function printDetail ($amount) {
  print("name: {$this->name}");
  print("amount:{$amount}");
}
  • 动机
  1. 函数粒度小,提升被复用几率
  2. 顶层函数读起来像一系列的注释
  3. 函数的复写更容易些
  • 做法
  1. 创建一个新函数,根据其做什么而不是以它怎么做来命名
  2. 从源函数复制提炼出的代码 到新建的目标函数中
  3. 检查是否有仅用于被提炼代码段的临时变量,如果有的话需要在目标函数中声明为临时变量
  4. 检查被提炼代码段,看看是否有任何局部变量被其改变.如果一个临时变量的值被修改了,看看是否可以将被提炼代码段处理为一个查询,并将结果赋值给相关变量.如果很难这样做或者被修改的变量不止一个,则你就不仅仅需要将这段代码原封不动的提炼出来.你可能需要使用Split Temporary Variavle(分离临时变量),然后在尝试提炼.也可以使用Replace Temp With Query(查询代替临时变量)将临时变量消灭掉
  5. 将被提炼代码段中需要读取的局部变量,当做参数传给目标函数
  6. 在源函数中, 将被提炼代码段替换为对目标函数的调用

实例1:含有简单的变量

局部变量最简单的情况:被提炼的代码段只是读取这些变量的值,并不修改他们.这种情况下我们可以简单的将它们当做参数传给新建的函数

修改前:

    /**
     * 打印欠款
     * @param $orders
     */
    public function printOwing() {
        $outStanding = 0.0;

        // print banner
        print_r("**************************");
        echo "<br>";
        print_r("******Customer Owes*******");
        echo "<br>";
        print_r("**************************");

        foreach ($this->orders as $order) {
            $outStanding += $order->getAmount();
        }

        // printDetail
        print("name: {$this->name}");
        echo "<br>";
        print("amount: {$outStanding}");
    }

修改后

   /**
     * 打印欠款
     * @param $orders
     */
    public function printOwing() {
        $outStanding = 0.0;
        $this->printBanner();
        foreach ($this->orders as $order) {
            $outStanding += $order->getAmount();
        }
        $this->printDetail($outStanding);
    }

    /**
     * 打印banner
     */
    public function printBanner() {
        print_r("**************************");
        echo "<br>";
        print_r("******Customer Owes*******");
        echo "<br>";
        print_r("**************************");
    }

    /**
     * 打印详情
     * @param $outStanding
     */
    public function printDetail($outStanding) {
        print("name: {$this->name}");
        echo "<br>";
        print("amount: {$outStanding}");
    }

实例2:对局部变量再赋值

如果被提炼代码段对局部变量赋值了,问题就变得复杂了.这里只讨论临时变量的问题.如果你发现源函数的参数被赋值,应该马上使用Remove Assignments to Parameters.
被赋值的临时变量分为两种情况:

  1. 这个变量只在被提炼代码中使用,可以将这个临时变量的声明移到被提炼代码中.然后一起提炼出去.
  2. 被提炼代码之外的代码也使用了这个变量,这又分为两种情况:
    • 如果这个变量在被提炼代码段之后未被使用, 直接在目标函数中修改它就可以了.
    • 如果被提炼代码段之后的代码还使用了这个变量, 需要让目标函数返回改变量改变后的值

在上次代码的基础上将计算代码提炼出来:

     /**
     * 打印欠款
     * @param $orders
     */
    public function printOwing() {
        $this->printBanner();
        $outStanding = $this->getOutStanding();
        $this->printDetail($outStanding);
    }

    /**
     * 打印banner
     */
    public function printBanner() {
        print_r("**************************");
        echo "<br>";
        print_r("******Customer Owes*******");
        echo "<br>";
        print_r("**************************");
    }

    /**
     * 打印详情
     * @param $outStanding
     */
    public function printDetail($outStanding) {
        print("name: {$this->name}");
        echo "<br>";
        print("amount: {$outStanding}");
    }

     /**
     * 计算
     * @param $orders
     * @return float
     */
    public function getOutStanding() {
        $result = 0.0;
        foreach ($this->orders as $order) {
            $result += $order->getAmount();
        }
        return $result;
    }

本例中$result只在被提炼代码中被初始化为明确初值,所以只在新函数中对它初始化,如果代码还对这个变量做了其他处理.就必须将它的值作为参数传给目标函数,对于这种变化,最初的代码可能是这样的

    /**
     * 打印欠款
     * @param $orders
     */
    public function printOwing($perviousAmount) {
        $outStanding = $perviousAmount * 1.5;
        $this->printBanner();
        foreach ($this->orders as $order) {
            $outStanding += $order->getAmount();
        }
        $this->printDetail($outStanding);
    }

被提炼后的代码可能是这样的:

    /**
     * 打印欠款
     * @param $orders
     */
    public function printOwing($previousAmount) {
        $this->printBanner();
        $outStanding = $this->getOutStanding($perviousAmount * 1.5);
        $this->printDetail($outStanding);
    }

     /**
     * 计算
     * @param $orders
     * @return float
     */
    public function getOutStanding($outStanding ) {
        $result = $outStanding;
        foreach ($this->orders as $order) {
            $result += $order->getAmount();
        }
        return $result;
    }

这时候, 你可能会问: "如果需要返回的变量不止一个怎么办?", 最通常的选择是挑选另一块代码来提炼.如果你的语言支持多值返回,可以使用他们带回多个回传值

相关文章

网友评论

      本文标题:重新组织函数-Extract Method(提炼函数)

      本文链接:https://www.haomeiwen.com/subject/fnmynctx.html