`
hl756799782
  • 浏览: 77776 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

关于抽象和具体(转载)

阅读更多

原文链接:http://space.itpub.net/13164110/viewspace-704885

什么是抽象呢?首先不必澄清什么是抽象,而从什么算抽象说起,稳定的、高层的就代表了抽象。就像一个公司,最好保证了高层的稳定,才能保证全局的发展。在进行系统设计时,稳定的抽象接口和高层逻辑,也代表了整个系统的稳定与柔性。兵熊熊一窝,将良良一窝,软件的构建也正如打仗,良好的设计都是自上而下的。而对具体的编程实践而言,接口和抽象类则代表了语言层次的抽象。

 

追溯概念的分析,一一过招,首先来看依赖于具体,如图3-3所示。

 

因此,为了分离这种紧耦合,最好的办法就是隔离,引入中间层来分离变化,同时确保中间层本身的稳定性,因此抽象的中间层是最佳的选择(如图3-4所示)。

 

  

 

以例而理,从最常见的服务端逻辑举例,如下所示:

 

public interface IUserService

 

{

 

}

 

 

 

public class UserService : IUserService

 

{

 

}

 

如果依赖于具体:

 

public class UserManager

 

{

 

  private UserService service = null;

 

}

 

或者依赖于抽象:

 

public class UserManager

 

{

 

  private IUserService service = null;

 

}

 

二者的区别仅在于引入了接口IUserService,从而使得UserManager对于UserService的依赖由强减弱。然而对于依赖的方式并非仅此一种,设计模式中的智慧正是通过各种编程技巧进行依赖关系的解耦,值得关注和学习,后文将对设计模式进行概要性的讨论。

 

WCF熟悉的读者一定不难看出这种实现方式如此类似于WCF的推荐模式,也是契约编程的基本思想。关于WCFSOA的相关内容,我们在后文进行了相关的讨论。

 

总结一番,什么是抽象,什么是具体?在作者看来,抽象就是系统中对变化封装的战略逻辑,体现了系统的必然性和稳定性,能够被具体层次复用和覆写;而具体则包含了与具体实现相关的逻辑,体现了系统的动态性和变动性。因此,抽象是稳定的,而具体是变动的。

 

Bob大叔在《Agile Principles, Patterns, and Practices》一书中直言,程序中所有的依赖关系都应终止于抽象类或者接口,就是对面向抽象编程一针见血的回应,其原因归根到底源自于对抽象和具体的认知和分解:关联应该终止于抽象,而不是具体,保证了系统依赖关系的稳定。具体类发生的修改,不会影响其他模块或者关系。那么如何做到这种理想的依赖于抽象的设计呢?

 

 层次清晰化

 

将复杂的问题简单化,是人类思维的普世智慧,也自然而然是实现软件设计的基本思路。将复杂的业务需求通过建模过程的抽象化提炼,去粗取精,去伪存真,凡此种种。而抽象的过程,其目标之一就是形成对于复杂问题简单化的处理过程,只有形成层次简单的逻辑才能将复杂需求中的关系梳理清晰,而依赖的本质正如上文所言,不就是处理关系吗?

 

所以,清晰的层次划分,进而形成的模块化,是实现系统抽象的必经之路。

 

 分散集中化

 

需求而设计的过程,就是一个分散集中化的过程,把需求相关的业务通过开发流程的需求分析过程进行整理,逐步形成需求规格说明、概要设计和详细设计等基本流程。分散集中化,是一个梳理需求到形成设计的过程,因此对于把握系统中的抽象和具体而言,是一个重要的分析过程和手段。现代软件工程已经对此形成了科学的标准化流程处理逻辑,例如可以借助UML更加清晰地设计流程、分析设计要素,进行标准化沟通和交流。

 

 具体抽象化

 

将具体问题抽象化,是本节关注的要点,而处理的方法是什么呢?答案就在设计模式。设计模式是前辈智慧的总结和实践,所以熟悉和学习设计模式,是学习和实践设计问题的必经之路。然而,没有哪个问题是由设计模式全权解决,也没有哪个模式能够适应所有的问题,因此要努力的是尽量积累更多的模式来应对多变的需求。作为软件设计话题中最重量级的话题,关注模式和实践模式是成长的记录。

 

 封装变化点

 

总的来说,抽象和变化就像一对孪生兄弟,将具体的变化点隔离出来以抽象的方式进行封装,在变化的地方寻找抽象是面对抽象最理想的方式。所以,如何去寻找变化是设计要解决的首要问题,例如工厂模式的目标是封装对象创建的变化,桥接模式关注对象间的依赖关系变化等。23个经典的设计模式,从某种角度来看,正是对不同变化点的封装角度提出的不同解决方案。

 

这一设计原则还被称为SoCSeparation of Concerns)原则,定义了对于实现理想的高耦合、低内聚目标的统一规则。

 

3.设计的哲学

 

之所以花如此篇幅来讲述一个看似简单的问题,其实最终理想是回归到软件设计目标这个命题上。如果悉心钻研就可发现,设计的最后就是对关系的处理,正如同生活的意义在于对社会的适应一样。因此,回归到设计的目标上就自然可知,完美的设计过程就是对关系的处理过程,也就是对依赖的梳理过程,并最终形成一种合理的耦合结果。

 

所以,面向对象并不神秘,以生活的现实眼光来看更是如此。把面向对象深度浓缩起来,可以概括为:

 

 目标:重用、扩展、兼容。

 

 核心:低耦合、高内聚。

 

 手段:封装变化。

 

 思想:面向接口编程、面向抽象编程、面向服务编程。

 

其实,就是这么简单。在这种意义上来说,面向对象思想是现代软件架构设计的基础。下面以三层架构的设计为例,来进一步感受这种依赖哲学在具体软件系统中的应用。关于依赖的抽象和对变化隔离的基本思路,其实也是实现典型三层架构或者多层架构的重要基础。只有使各个层次之间依赖于较稳定的接口,才能使得各个层次之间的变化被隔离在本层之内,不会造成对其他层次的影响,这完全符合开放封闭原则追求的优良设计理念。将这种思路表达为设计,可以表示为如图3-5所示的形式。

 

由图3-5可知,IDataProvider作为隔离业务层和数据层的抽象,IService作为隔离业务层和表现层的抽象,保证了各个层次的相对稳定和封装。而体现在此的设计逻辑,就正是对于抽象和耦合基本目标概念的体现,例如作为重用的单元,抽象隔离保证了对外发布接口的单一和稳定,所以达到了最高限度的重用;通过引入中间的稳定接口,达到了不同层次的有效隔离,层与层之间体现为轻度耦合,业务层只持有IDataProvider就可以获取数据层的所有服务,而表现层也同样如此;最后,这种方式显然也直接实践了面向接口编程,面向抽象编程的经典理念。

 

同样的道理,对于架构设计的很多概念,放大可以扩展为面向服务设计所借鉴,放小这正是反复降调的依赖倒置原则在类设计中的基本思想。因此,牢记一位软件大牛的说法:软件设计的任何问题,都可以通过引入中间逻辑得到解决。而这个中间逻辑,很多时候被封装为抽象,是最为合理和智慧的解决方案。

 

让我们再次高颂《老子》的小国寡民论,来回味关于依赖哲学中,如何实现更好的和谐统一以及如何遵守科学的软件管理思想:邻国相望,鸡犬之声相闻,民至老死,不相往来。

特别说明:本人转载文章纯为技术学习,总结经验,并无其他目的,若有他人继续转载,请链接原作者的地址,而不是本文的地址,以示对作者的尊重。最后对原作者的辛勤劳动表示感谢!

分享到:
评论

相关推荐

    抽象工厂模式 源代码

    此资源出自下面的作者,我只是转载,非常实用的设计方法,如果您想成位出色的设计师,那就再复习复习吧!如果您想成为软件设计师,通过学习,您将会站另一个高度看待软件设计. 原始地址:...

    数据模型设计心得(转载)

    数据模型设计是数据库系统开发中的核心环节,它用于抽象和描述现实世界的数据结构,以便于计算机存储和处理。本文将围绕“数据模型设计心得”展开,结合提供的文档资源,探讨在广告平台项目系统和会员模块设计中如何...

    网上转载JAVA面试基本大全

    抽象分为过程抽象(方法)和数据抽象(属性)。 - **继承**:继承允许一个类(子类)从另一个类(父类)继承属性和行为。这样可以避免重复代码,增强代码的可重用性。子类可以覆盖或扩展父类的方法,以适应特定需求...

    zigbee组网分析 转载

    【Zigbee组网分析】 Zigbee是一种短距离、低功耗的无线通信技术,广泛应用于物联网设备的连接和数据传输。...在实际应用中,开发者需要根据具体需求调整和优化这些步骤,以实现最佳的网络性能和用户体验。

    STM32 L0 hal库

    官网介绍说,hal(hardware abstract layer)是一层硬件的抽象,看到这里,我非常激动,看来st终于意识到原来标准库的问题了,原来的标准库非常依赖于具体硬件细节,很难体现出使用库的优势,而且很难移植。...

    Java程序员面试的试题集(1_122)帮助初学者的技术问题(转载)

    在Java中,抽象可以通过抽象类和接口来实现,使开发者能够定义类的骨架而不必提供具体实现,从而促进代码的复用和模块化设计。 2. **继承**:继承支持类之间的层次结构,允许创建的新类(子类)继承现有类(父类)...

    java编写建议(转载)

    - 抽象类适合于提供部分实现,而具体实现留给子类完成。 - 在设计时考虑未来可能的变化,以便于扩展而不影响现有代码。 #### 六、资源泄露与垃圾回收 **6.1 资源泄露** - 避免资源泄露,特别是对文件和网络连接的...

    C++实现KNN文本分类算法

    将书本上关于文本分类的相关内容,如分类器、特征词选择算法等,用程序实现,让入门者对文本分类有个感性的、具体的了解,毕竟数学公式还是蛮抽象的; 2.“尽信书不如无书”,“纸上得来终觉浅,绝知此事要躬行”,...

    [转载]医学检验专业实习总结心得实习学习总结.doc

    理论知识可能在课本上显得抽象,但在实际操作中,它们会变得具体且实用。例如,血液生化指标的学习在理论上可能枯燥,但在实际检测中,这些指标能够直接影响医生对疾病的诊断和治疗方案的制定。 实习不仅是技能的...

    骆昊JAVA面试题全集2018博客文章整理

    - **抽象**:抽象是提取对象共性的过程,包括数据抽象和行为抽象。它关注对象的属性和行为,而不涉及具体实现。 - **继承**:继承允许子类从父类继承特性,增强代码的扩展性,降低软件的复杂性。 - **封装**:...

    Linux字符设备驱动(转载)

    总之,Linux字符设备驱动是连接用户空间应用和硬件设备的桥梁,它实现了设备的抽象化,使得应用程序可以以统一的方式与各种不同的硬件设备进行交互。理解并掌握字符设备驱动的原理和实现方法,对于进行系统级编程和...

    (转载)安卓点击和滑动切换页面FragmentActivity

    FragmentActivity是Android Support Library中的一个抽象类,它是Activity的扩展,提供了对Fragment的支持。使用FragmentActivity,开发者可以轻松地在同一个界面上添加、移除或替换多个Fragment。下面我们将详细...

    51单片机开发实例100例(转载)_51单片机开发例程_

    C语言则提供了更高级别的抽象,使得程序更易理解和维护。实例中,两种语言的使用都有所涉及,可以帮助你根据项目需求选择合适的编程语言。 在实例中,你将接触到51单片机的中断系统,它是处理突发事件的重要机制。...

    java文件路径操作详细(转载)

    Java中的`java.io.File`类是用于表示文件和目录路径名的抽象表示。它提供了许多操作,如创建、删除、重命名文件和目录,以及获取文件属性等。 2. **路径构造**: 可以通过传递字符串参数给File构造器来创建一个...

    利用 Java 实现组合式解析器,基于 Java 的界面布局 DSL 的设计与实现(转载)

    1. **解析器构造**: 解析器是如何工作的,包括词法分析(将输入分解为单词或符号)和语法分析(将单词或符号转换为抽象语法树)。 2. **组合解析器的概念**:如何通过组合小的解析器来构建复杂的解析逻辑,以及如何...

    常用的数据分析方法(转载)

    它包括了销售业务过程中的属性、数量、位置及其相互关系等内容的抽象表示。 **数据的表现形式**: 1. **列表形式**:如客户销售分析报表,通过表格的形式清晰地展示了不同客户在各月份的销售情况。 2. **图表形式**...

    spark使用案例------

    DataFrame和DataSet是Spark 2.0引入的新特性,它们提供了更高级别的抽象,使得SQL查询和类型安全的数据操作变得更加便捷。 在大数据处理中,Spark的Shuffle过程是非常关键的,它涉及到数据在集群中的重新分布,通常...

Global site tag (gtag.js) - Google Analytics