抽象原则倡导通过精简和概括来简化实体:精简是删除不必要的细节,而概括是找出并定义通用的的重要特征。
这是什么?
这是一个笑脸,那么我们是怎么知道这是一个笑脸的呢?通过抽象。人脸数以亿计,却各不相同。我们忽略了不重要的细节,如发型和发色。我们还概括了相同的东西,每个人都有两只眼睛,微笑时嘴角上扬。这就是抽象。对于软件工程师来说,抽象能力是最重要的能力之一,也恰恰是最难得的能力之一。
我们这篇博客主要讲解分析缺失抽象坏味,对于其它抽象坏味将在后面的博客讲解分析。
使用一系列数据或编码字符串,而不创建类或接口时,将引发这种坏味。
通常,由于缺失抽象,相关的数据和行为将会分散在其它抽象中,这将会导致两个问题l:
没有经过充分的设计分析,很容易就会忽略创建抽象,而使用基本数据类型来完成任务。
随着需求的变化和软件的发展,原来使用的基本数据类型可能需要重构为使用类或接口。
例如直接使用数组,而不创建合适的抽象。这种“优化”带来的性能改善都很有限,不值得为此牺牲设计质量。
在一个图书馆信息管理程序中,ISBN(国际标准书号)的存储和处理十分重要,可以使用字符串类型进行存储,但是这种选择很糟糕。ISBN(国际标准书号)有两种表示方式:10位和13位。图书馆信息管理程序逻辑包含ISBN的接受、验证、处理和转换。如果使用基本的字符串类型存储ISBN,处理的逻辑将会分散在很多地方,实体之间高度耦合,代码脆弱且难以重用。
正确的方案是:创建一个抽象类或接口ISBN,其中包含通用的操作。并创建子类ISBN-10和ISBN-13,它们都扩展超类ISBN。
应用程序中常常包含总是同时使用的基本数据类型,通常情况下这些“数据泥团”就意味着缺失抽象。例如在绘画程序中确定一个二维的点的位置,通常比较差的做法可能会用(double x,double y)。重构的建议是将必不可少的字段提取到一个新类(Rectangle)中,并且将操作这些字段的方法移到这个类中。
public class Rectangle
{
/// <summary>
/// 横坐标
/// </summary>
private int x;
/// <summary>
/// 纵坐标
/// </summary>
private int y;
public Rectangle(int x,int y)
{
this.x = x;
this.y = y;
}
public void Draw()
{
//绘制(x,y)
}
}
有时候,实体只是数据元素,没有任何相关联的行为。在这种情况下,使用类或接口来表示它们可能导致过度设计,增加了设计的复杂性。因为在创建抽象前,一定要根据应用抽象具体情况分析,再决定是否要创建抽象。
参考:《软件设计重构》