【抽象那些事】缺失抽象

抽象原则倡导通过精简和概括来简化实体:精简是删除不必要的细节,而概括是找出并定义通用的的重要特征。

这是什么?

这是一个笑脸,那么我们是怎么知道这是一个笑脸的呢?通过抽象。人脸数以亿计,却各不相同。我们忽略了不重要的细节,如发型和发色。我们还概括了相同的东西,每个人都有两只眼睛,微笑时嘴角上扬。这就是抽象。对于软件工程师来说,抽象能力是最重要的能力之一,也恰恰是最难得的能力之一。

应用抽象原则的实现手法

  • 提供清晰的概念边界和唯一身份 每个抽象都必须有清晰而明确的概念边界,还必须有身份。例如,不传递一组表示日期、矩形坐标或图片属性的数据值,而是在代码中分别为日期、矩形坐标或图片属性创建抽象。
  • 映射域实体 必须创建从问题域到解决方案域的词汇映射,即对于问题域中的对象,必须在解决方案域中使用相应的抽象来表示它们。
  • 确保内聚性和完整性 抽象必须对其承担的职责提供全面支持。例如表示组合框的类支持禁用或隐藏特定的元素,就必须同时支持启用或显示这些元素的选项。如果只提供方法的一部分,抽象既不内聚也不完整。
  • 赋予单一而重要的职责 确保每个抽象都分配单一而重要的职责。 单一:每个抽象都应该只负责一件或一类事情。 重要:抽象不能太鸡肋。
  • 避免重复 确保每个抽象(名称和实现)只在设计中出现一次。重复的名称将会给设计的使用者带来困惑,重复的实现将会增加维护负担,因为需要维护多块相同的代码。

违反抽象原则导致的坏味

我们这篇博客主要讲解分析缺失抽象坏味,对于其它抽象坏味将在后面的博客讲解分析。

缺失抽象

使用一系列数据或编码字符串,而不创建类或接口时,将引发这种坏味。

为什么不能缺失抽象?

通常,由于缺失抽象,相关的数据和行为将会分散在其它抽象中,这将会导致两个问题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)
    }
}

现实考虑

有时候,实体只是数据元素,没有任何相关联的行为。在这种情况下,使用类或接口来表示它们可能导致过度设计,增加了设计的复杂性。因为在创建抽象前,一定要根据应用抽象具体情况分析,再决定是否要创建抽象。

参考:《软件设计重构》

                                                        -----END-----

                  喜欢本文的朋友们,欢迎扫一扫下图关注公众号撸码那些事,收看更多精彩内容

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏韩伟的专栏

字节的奥秘

在数码产品中,最常见的名词就是“字节”了。不管是U盘容量、手机存储空间,还是网络带宽,下载速度,都会涉及所谓“字节”这个单位。但到底“字节”是一个什么东西呢?本...

3704
来自专栏静默虚空的博客

[算法题] 安排会议室——贪心算法的应用

题目描述 [题目描述] 在大公司里,会议是很多的,开会得有场子,要场子你得先在电子流里预订。 如果你是项目组新来的小弟,那么恭喜你,每天抢订会议室的任务就光荣的...

3455
来自专栏人工智能LeadAI

讨厌算法的程序员 | 第四章 时间复杂度

增长量级 ? 函数的增长量级 上一篇算法分析基础中,我们分析了插入排序,知道了其最好情况下的运行时间为T(n) = an + b,最差情况下的运行时间为T(n...

2938
来自专栏游戏开发那些事

【游戏开发】浅谈游戏开发中常见的设计原则

  俗话说得好:“设计模式,常读常新~”。的确,每读一遍设计模式都会有些新的体会和收获。马三不才,才读了两遍设计模式(还有一遍是在学校学的),属于菜鸟级别的。这...

1333
来自专栏狮乐园

【译】Understanding SOLID Principles - Liskov Substitution Principle

这句话的意思是说,当我们在传递一个父抽象的子类型时,你需要保证你不会修改任何关于这个父抽象的行为和状态语义。

1031
来自专栏TensorFlow从0到N

讨厌算法的程序员 4 - 时间复杂度

增长量级 ? 函数的增长量级 上一篇算法分析基础中,我们分析了插入排序,知道了其最好情况下的运行时间为T(n) = an + b,最差情况下的运行时间为T(n...

3253
来自专栏玄魂工作室

Python黑帽编程 2.0 第二章概述

于 20世纪80年代末,Guido van Rossum发明了Python,初衷据说是为了打发圣诞节的无趣,1991年首次发布,是ABC语言的继承,同时也是一...

3697
来自专栏IT派

Python学习路线图

Python上手很容易, 基本有其他语言编程经验的人可以在1周内学会Python最基本的内容.

4590
来自专栏撸码那些事

【抽象那些事】缺失抽象

1493
来自专栏程序员维他命

出一套 iOS 高级面试题

一千个读者眼中有一千个哈姆雷特,一千名 iOS 程序员心目中就有一千套 iOS 高级面试题。本文就是笔者认为可以用来面试高级 iOS 程序员的面试题。

5752

扫码关注云+社区

领取腾讯云代金券