`
hl756799782
  • 浏览: 74075 次
  • 性别: 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学习笔记---15.面向对象编程10-Java中final关键字,抽象类与接口

    //接口中包含了抽象类和抽象方法 public static final String NAME = "newsainton"; public abstract void fun(); } // 一个类可以继承多个接口,但如果该类不是抽象类的话,则必须实现抽象类中的所有抽象方法 ...

    STM32 L0 hal库

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

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

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

    leetcode下载-CodingInterviews:《剑指offer》面试题java版,leetcode题目分享

    举例让抽象问题具体化 分解让复杂问题简单化 ##第五章 优化时间和空间效率 时间效率 时间效率与空间效率的平衡 第六章 面试中的各项能力 知识迁移能力 抽象建模能力 发散思维能力 leetcode 题目分享(长期更新): ...

    二十三种设计模式【PDF版】

    关于本站“设计模式” Java 提供了丰富的 API,同时又有强大的数据库系统作底层支持,那么我们的编程似乎变成了类似积木的简单"拼凑"和调用, 甚至有人提倡"蓝领程序员",这些都是对现代编程技术的不了解所至. 在...

    学习人工智能需要哪些必备的数学基础?.pdf

    着重于抽象概念的解释⽽⾮具体的数学公式来看,线性代数要点如下:线性代数的本质在于将具体事物抽象为数学对象,并描述其静态和动 态的特性;向量的实质是 n 维线性空间中的静⽌点;线性变换描述了向量或者作为...

    jdk-8u241-windows-i586 (1).exe

    版权声明:本文为CSDN博主「絕了千年良緣」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_43432523/article/details/97183453

    java设计模式CatalogDAOFactory是典型的工厂方法

    抽象工厂还有另外一个关键要点,是因为 SimpleFactory内,生产Sample和生产Sample2的方法之间有一定联系,所以才要将这两个方法捆绑在一个类中,这个工厂类有其本身特征,也许制造过程是统一的,比如:制造工艺比较...

    虚拟数据层 Struts2、Hibernate、Spring整合的泛型DAO Version 2010.9.27

    如果你真能只用一个dao解决,那么祝贺你,你得到了一个虚拟数据层(高度抽象的数据接口)。这是一个比dao更高级的存在。 欢迎大家指正 -_- 虚心求教 代码层次: bean-->dao-->service-->action 技术概述:1....

    泛型dao 泛型dao 泛型dao

    如果你真能只用一个dao解决,那么祝贺你,你得到了一个虚拟数据层(高度抽象的数据接口)。这是一个比dao更高级的存在。 欢迎大家指正 -_- 虚心求教 代码层次: bean-->dao-->service-->action 技术概述:1....

    asp.net知识库

    从NUnit中理解.NET自定义属性的应用(转载) 如何在.NET中实现脚本引擎 (CodeDom篇) .NET的插件机制的简单实现 我对J2EE和.NET的一点理解 难分难舍的DSO(一) InternalsVisibleToAttribute,友元程序集访问属性 ...

    制作第一个页面 欢迎您进入.Net启动运行

    – 抽象类和接口 二 √(vs2005101) 110. 深入继承 – 抽象类和接口 三 √(vs2005102) 111. 深入继承 – 实例剖析 一 √(vs2005103) 112. 深入继承 – 实例剖析 二√(vs2005105) .Net程序集和定制...

    GridView使用技巧一

    – 抽象类和接口 二 √(vs2005101) 110. 深入继承 – 抽象类和接口 三 √(vs2005102) 111. 深入继承 – 实例剖析 一 √(vs2005103) 112. 深入继承 – 实例剖析 二√(vs2005105) .Net程序集和定制...

    GridView使用技巧二

    – 抽象类和接口 二 √(vs2005101) 110. 深入继承 – 抽象类和接口 三 √(vs2005102) 111. 深入继承 – 实例剖析 一 √(vs2005103) 112. 深入继承 – 实例剖析 二√(vs2005105) .Net程序集和定制...

    leetcode下载-leetcode-csharp:根据问题标签使用C#forleetcode的解决方案,每天更新。我的联系方式:guozh

    这一部分论述了刷题的好处,文章此部分转载: 虽然刷题一直饱受诟病,不过不可否认刷题确实能锻炼我们的编程能力,相信每个认真刷题的人都会有体会。现在提供在线编程评测的平台有很多,比较有名的有 hihocoder , ...

    HumanMotionTrack 全

    现在解决最后的问题了,如何旋转了,具体来讲就是骨骼从原来自然的状态旋转到目前的方向,例如手臂从自然垂下变成抬起,垂下和抬起两个状态的矢量是不同的方向的,如何旋转呢? 这里就要用到了空间几何里的点积和叉积...

Global site tag (gtag.js) - Google Analytics