17611538698
webmaster@21cto.com

软件开发之要义:DRY-——不要重复你自己

资讯 0 2558 2020-06-08 12:04:15

21CTO学院导读:不重复自己(Do not Repeat Yourself)是软件开发之要义,它的目标就是避免代码重复。


8-code-deck.jpg
 
不要重复自己,是软件开发的基本原则,它的目标是避免重复的代码发生。
 
每行代码在系统必须有单一,明确,权威的表现。
 
很多时间,你发现自己一遍又一遍编写同样的代码时,本文告诉你更实际好用的方法。
 
 
案例:不要重复自己
 
先看一个代码例子,来看它是否可以再改进,重构它以避免代码重复。
 
以下是一个Rport类,功能很简单,接收一些数据,通过控制台格式化打印一些信息。
 
代码如下:
class Report{



public function show(array $data){



echo "Report: " . ucwords(strtolower($data["name"])) . " ";

echo "Product: " . ucwords(strtolower($data["product"])) . " ";

echo "Start date: " . date("Y/m/d", $data["startDate"]) . " ";

echo "End date: " . date("Y/m/d", $data["endDate"]) . " ";

echo "Total: " . $data["total"] . " ";

echo "Average x day: " . floor($data["total"] / 365) . " ";

echo "Average x week: " . floor($data["total"] / 52) . " ";



}

}

 
可以改进此代码吗?稍等一下,有报表的新需求,把内容保存到文件里。这很容易,我们对它进行一些复制粘贴,做一些小更改,几分钟就可能搞定。
 
代码如下:
class Report {



public function show(array $data) {



echo "Report: " . ucwords(strtolower($data["name"])) . " ";

echo "Product: " . ucwords(strtolower($data["product"])) . " ";

echo "Start date: " . date("Y/m/d", $data["startDate"]) . " ";

echo "End date: " . date("Y/m/d", $data["endDate"]) . " ";

echo "Total: " . $data["total"] . " ";

echo "Average x day: " . floor($data["total"] / 365) . " ";

echo "Average x week: " . floor($data["total"] / 52) . " ";

echo "Average x month: " . floor($data["total"] / 12) . " ";



}



public function saveToFile(array $data) {



$report = ';

$report .= "Report: " . ucwords(strtolower($data["name"])) . " ";

$report .= "Product: " . ucwords(strtolower($data["product"])) . " ";

$report .= "Start date: " . date("Y/m/d", $data["startDate"]) . " ";

$report .= "End date: " . date("Y/m/d", $data["endDate"]) . " ";

$report .= "Total: " . $data["total"] . " ";

$report .= "Average x day: " . floor($data["total"] / 365) . " ";

$report .= "Average x week: " . floor($data["total"] / 52) . " ";

$report .= "Average x month: " . floor($data["total"] / 12) . " ";

file_put_contents("./report.txt", $report);



}

}

 
等一下,我们真的完成了?当然,需求确实已经满足,但从技术角度,它似乎有些问题。可以看到很多重复项,虽然代码只有几行,至少写了两次写入文件。显然,这与DRY特性相反。
 
接下来,我们做一些重构。这两个方法的内容大致内容相同,唯一不同的是最终输出。我们来将主干内容提取到新方法中。这样,我们就有一个单一的功能,在一个地方创建报表,其它方法只负责如何处理即可。
class Report
{

public function show(array $data)
{

echo $this->createReport($data);

}



public function saveToFile(array $data)
{

file_put_contents("./report.txt", $this->createReport($data));

}



private function createReport(array $data): string
{

$report = ';

$report .= "Report: " . ucwords(strtolower($data["name"])) . " ";

$report .= "Product: " . ucwords(strtolower($data["product"])) . " ";

$report .= "Start date: " . date("Y/m/d", $data["startDate"]) . " ";

$report .= "End date: " . date("Y/m/d", $data["endDate"]) . " ";

$report .= "Total: " . $data["total"] . " ";

$report .= "Average x day: " . floor($data["total"] / 365) . " ";

$report .= "Average x week: " . floor($data["total"] / 52) . " ";

$report .= "Average x month: " . floor($data["total"] / 12) . " ";

return $report;

}

}

 
这样看起来好多了,还有一些小的重复项需要修复。
$report .= "Report: " . ucwords(strtolower($data["name"])) . "
";

$report .= "Product: " . ucwords(strtolower($data["product"])) . " ";

把这些转换提取到新方法,甚至可以提取到自己的单元测试库中。
private function normalizeName($name): string
{

return ucwords(strtolower($name));

}

另外还一个重复,日期格式:
$report .= "Start date: " . date("Y/m/d", $data["startDate"]) . "
";

$report .= "End date: " . date("Y/m/d", $data["endDate"]) . " ";

将它合并提取为:
private function formatDate($date): string
{

return date("Y/m/d", $date);

}

还有一个,计算平均数。
$report .= "Average x day: " . floor($data["total"] / 365) . "
";

$report .= "Average x week: " . floor($data["total"] / 52) . " ";

$report .= "Average x month: " . floor($data["total"] / 12) . " ";





它们之间的计算结果并不完全一样,但是,我们可以合并成一个函数:
private function calculateAverage(array $data, $period): string
{

return floor($data["total"] / $period);

}

最后,重构的Report类是这个样子的:
class Report
{

public function show(array $data)
{

echo $this->createReport($data);

}



public function saveToFile(array $data)
{

file_put_contents("./report.txt", $this->createReport($data));

}



private function createReport(array $data)
{

$report = ';

$report .= "Report: " . $this->normalizeName($data["name"]) . " ";

$report .= "Product: " . $this->normalizeName($data["product"]) . " ";

$report .= "Start date: " . $this->formatDate($data["startDate"]) . " ";

$report .= "End date: " . $this->formatDate($data["endDate"]) . " ";

$report .= "Total: " . $data["total"] . " ";

$report .= "Average x day: " . $this->calculateAverage($data, 365) . " ";

$report .= "Average x week: " . $this->calculateAverage($data, 52) . " ";

$report .= "Average x month: " . $this->calculateAverage($data, 12) . " ";

return $report;

}



private function formatDate($date): string
{

return date("Y/m/d", $date);

}





private function calculateAverage(array $data, $period): string
{

return floor($data["total"] / $period);

}





private function normalizeName($name): string
{



return ucwords(strtolower($name));

}

}

DRY是编码过程中,开发基础结构以及部署的终结点,开发者应该努力做到这一点,从而全面改善代码环境,让其更具可读性和可管理性。

     


    作者:正明
    来源:21CTO学院


    评论