转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

原文出处:https://dzone.com/articles/dry-dont-repeat-yourself

我们之前就发过一篇相关的文章:https://www.cnblogs.com/powertoolsteam/p/12758496.html 其中也提到了包括DRY在内的一些软件开发的原则。

DRY 是软件开发的原则之一,其目的主要是为了避免代码重复,指导开发者尽量以抽象的思维去解决重复,基本上是,当您发现自己一遍又一遍地编写相同的代码时,可能会有更好的方法。

实际案例

让我们先看一个例子,看看这个例子是否可以改进,以及如何通过重构来避免代码重复。

这里有一个简单的Report类,该类接收一些数据并通过控制台以格式化的方式直接输出。

我们这里使用php的一个代码片段来举例,相信大家对代码的结构和想要完成的工作都不难理解,所以为了大家更容易理解,我只对一些下面用到的php函数定义做一个解释:

  1. echo()  函数输出一个或多个字符串
  2. ucwords()函数把字符串中每个单词的首字符转换为大写。
  3. strtolower() 函数把字符串转换为小写。
  4. file_put_contents() 函数把一个字符串写入文件中。
  5. floor() 函数向下舍入为最接近的整数。
class Report
{
public function show(array $data)
{
echo "Report: " . ucwords(strtolower($data["name"])) . "\n";
echo "Product: " . ucwords(strtolower($data["product"])) . "\n";
echo "Start date: " . date("Y/m/d", $data["startDate"]) . "\n";
echo "End date: " . date("Y/m/d", $data["endDate"]) . "\n";
echo "Total: " . $data["total"] . "\n";
echo "Average x day: " . floor($data["total"] / 365) . "\n";
echo "Average x week: " . floor($data["total"] / 52) . "\n";
}
}

可以看到,上面的代码完成目标是没有任何问题的。

这时我们对Report类提出一个新的需求:把所有字符串也可以保存到文件中。

我们经过一通复制和粘贴上面的代码,新建一个名为saveToFile的函数,就可以很快的完成这个需求,代码如下:

class Report
{
public function show(array $data)
{
echo "Report: " . ucwords(strtolower($data["name"])) . "\n";
echo "Product: " . ucwords(strtolower($data["product"])) . "\n";
echo "Start date: " . date("Y/m/d", $data["startDate"]) . "\n";
echo "End date: " . date("Y/m/d", $data["endDate"]) . "\n";
echo "Total: " . $data["total"] . "\n";
echo "Average x day: " . floor($data["total"] / 365) . "\n";
echo "Average x week: " . floor($data["total"] / 52) . "\n";
echo "Average x month: " . floor($data["total"] / 12) . "\n";
}
public function saveToFile(array $data)
{
$report = '';
$report .= "Report: " . ucwords(strtolower($data["name"])) . "\n";
$report .= "Product: " . ucwords(strtolower($data["product"])) . "\n";
$report .= "Start date: " . date("Y/m/d", $data["startDate"]) . "\n";
$report .= "End date: " . date("Y/m/d", $data["endDate"]) . "\n";
$report .= "Total: " . $data["total"] . "\n";
$report .= "Average x day: " . floor($data["total"] / 365) . "\n";
$report .= "Average x week: " . floor($data["total"] / 52) . "\n";
$report .= "Average x month: " . floor($data["total"] / 12) . "\n";
file_put_contents("./report.txt", $report);
}
}

那么,上面的代码能够满足我们提出的需求吗?答案当然“是的”。但是从技术角度来看,这段代码似乎是有些问题的,它的重复代码到处都是。无论是对代码阅读及后期维护来讲,这都是一场噩梦。

所以我们需要进行一些重构,抽象能抽象的方法,让冗繁的代码变得更简洁。

首先,我们对Report类进行功能上的抽象,生成报告并输出一共可以分为两个功能,一个只负责创建Report,一个只负责如何处理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): string
{
$report = '';
$report .= "Report: " . ucwords(strtolower($data["name"])) . "\n";
$report .= "Product: " . ucwords(strtolower($data["product"])) . "\n";
$report .= "Start date: " . date("Y/m/d", $data["startDate"]) . "\n";
$report .= "End date: " . date("Y/m/d", $data["endDate"]) . "\n";
$report .= "Total: " . $data["total"] . "\n";
$report .= "Average x day: " . floor($data["total"] / 365) . "\n";
$report .= "Average x week: " . floor($data["total"] / 52) . "\n";
$report .= "Average x month: " . floor($data["total"] / 12) . "\n";
return $report;
}
}

现在看起来更清楚一些,对吗?

下面我们还有函数使用重复的问题要解决,例如,Report和Products的名称函数使用重复:

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

我们可以将这些转换抽象为一个新的函数:

private function normalizeName($name): string
{
return ucwords(strtolower($name));
}

另一个重复:日期格式。

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

让我们将其抽象为:

private function formatDate($date): string
{
return date("Y/m/d", $date);
}

最后一个:平均值计算。

$report .= "Average x day: " . floor($data["total"] / 365) . "\n";
$report .= "Average x week: " . floor($data["total"] / 52) . "\n";
$report .= "Average x month: " . floor($data["total"] / 12) . "\n";

尽管计算结果并不完全相同,但执行的操作大家是一致的,所以可以抽象为如下:

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"]) . "\n";
$report .= "Product: " . $this->normalizeName($data["product"]) . "\n";
$report .= "Start date: " . $this->formatDate($data["startDate"]) . "\n";
$report .= "End date: " . $this->formatDate($data["endDate"]) . "\n";
$report .= "Total: " . $data["total"] . "\n";
$report .= "Average x day: " . $this->calculateAverage($data, 365) . "\n";
$report .= "Average x week: " . $this->calculateAverage($data, 52) . "\n";
$report .= "Average x month: " . $this->calculateAverage($data, 12) . "\n";
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原则,并随时抱着不要重复自己代码的想法去完成开发工作。

DRY原则的一个简单实践的更多相关文章

  1. 【阿菜做实践】利用go语言写一个简单的Pow样例

    本篇博客的主要内容是用go写一个简单的Proof-of-Work共识机制,不涉及到网络通信环节,只是一个本地的简单demo.开发IDE用的是JB Golang. 整个项目的文件结构如下: PoWdem ...

  2. DRY原则

    DRY--Don't Repeat Yourself Principle,直译为"不要重复自己"原则 DRY简而言之,就是不要写重复的代码.原则本身很简单,但是,对于OOAD(面向 ...

  3. 敏捷软件开发:原则、模式与实践——第14章 使用UML

    第14章 使用UML 在探索UML的细节之前,我们应该先讲讲何时以及为何使用它.UML的误用和滥用已经对软件项目造成了太多的危害. 14.1 为什么建模 建模就是为了弄清楚某些东西是否可行.当模型比要 ...

  4. 敏捷软件开发:原则、模式与实践——第10章 LSP:Liskov替换原则

    第10章 LSP:Liskov替换原则    Liskov替换原则:子类型(subtype)必须能够替换掉它们的基类型(base type). 10.1 违反LSP的情形 10.1.1 简单例子 对L ...

  5. 敏捷软件开发:原则、模式与实践——第8章 SRP:单一职责原则

    第8章 SRP:单一职责原则 一个类应该只有一个发生变化的原因. 8.1 定义职责 在SRP中我们把职责定义为变化的原因.如果你想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责.同时,我 ...

  6. 从一个简单的Java单例示例谈谈并发

    一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...

  7. Android 设计随便说说之简单实践(合理组合)

    上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示appl ...

  8. 【转】DRY原则的误区

    很多编程的人,喜欢鼓吹各种各样的“原则”,比如KISS原则,DRY原则…… 总有人把这些所谓原则奉为教条或者秘方,以为兢兢业业地遵循这些,空喊几个口号,就可以写出好的代码.同时,他们对违反这些原则的人 ...

  9. 敏捷软件开发:原则、模式与实践——第13章 写给C#程序员的UML概述

    第13章 写给C#程序员的UML概述 UML包含3类主要的图示.静态图(static diagram)描述了类.对象.数据结构以及它们之间的关系,藉此表现出了软件元素间那些不变的逻辑结构.动态图(dy ...

随机推荐

  1. Django之AJAX简单使用

    AJAX简介: AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传输 ...

  2. 去重函数unique,sort,erase的应用

    std::unique 一.总述 unique函数属于STL中比较常用函数,它的功能是元素去重.即"删除"序列中所有相邻的重复元素(只保留一个).此处的删除,并不 是真的删除,而是 ...

  3. 重学 Java 设计模式:实战抽象工厂模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  4. Swiper的jquery动态渲染不能滑动

    <!-- 下面俩行代码就是解决异步加载数据导致swiper不轮播的关键 --> observer: true,//修改swiper自己或子元素时,自动初始化swiper observePa ...

  5. springmvc数据处理-中文乱码

    首先解决中文乱码 通过mvc过滤器解决,在web.xml中配置 <filter> <filter-name>CharacterEncodingFilter</filter ...

  6. 《HelloGitHub》第 50 期

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  7. Ant标签详解--基础操作

    Ant的一些核心概念: build.xml:构建文件是以XML 文件来描述的,默认构建文件名为build.xml.        project:每个构建文件包含一个工程. property:属性,一 ...

  8. [计划任务 - Linux]三分钟学会cron

    cron——计划任务,是任务在约定的时间执行已经计划好的工作,是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业. 也就是说cron只适合于linux系统,用windows电脑的同学 ...

  9. [Objective-C] 007_Foundation框架之NSString与NSMutableString

    在Cocoa Foundation中的NSString和NSMutableString类,为我们提供了Unicode字符串的支持,NSString和NSMutableString类最大的区别是:NSS ...

  10. Map接口之HashMap,LinkedHashMap,TreeMap

    Map与Collection 并列存在,用于保存具有映射关系的数据:Key-Value Map中的Key和Value都可以是任何引用类型的数据 Map中的Key用Set存放,不允许重复,即同一个Map ...