什么是依赖,什么是抽象

1.关于依赖和耦合:从小国寡民到和谐社会

在老子的“小国寡民”论中,提出了一种理想的社会状态:邻国相望,鸡犬之声相闻,民至老死,不相往来。这是他老人家的一种社会理想,老死不相往来的人群呈现了一片和谐景象。因为不发生瓜葛,也就无所谓关联,进而无法导致冲突。这是先祖哲学中的至纯哲理,但理想的大同总是和现实的生态有着或多或少的差距,人类社会无法避免联系的发生,所以小国寡民的理想成为一种美丽的梦想,不可实现。同样的道理,映射到软件“社会”中,也就是软件系统结构中,也预示着不同的层次、模块、类型之间也必然存在着或多或少的联系,这种联系不可避免但可管理。正如人类社会虽然无法实现小国寡民,但是理想的状态下我们推崇和谐社会,把人群的联系由复杂变为简单,由曲折变为统一,同样可以使得这种关联很和谐。所以,软件系统的使命也应该朝着和谐社会的目标前进,对于不同的关系处理,使用一套行之有效的哲学,把复杂问题简单化,把僵化问题柔性化,这种哲学或者说方法,在我看来就是:依赖的哲学,也就是本文所要阐释的中心思想。

因为“耦合是不可避免的”,所以首先就从认识依赖和耦合的概念开始,来一步步阐释依赖的哲学思想。

(1)什么是依赖和耦合

依赖,就是关系,代表了软件实体之间的联系。软件的实体可能是模块,可能是层次,也可能是具体的类型,不同的实体直接发生依赖,也就意味着发生了耦合。所以,依赖和耦合在我看来是对一个问题的两种表达,依赖阐释了耦合本质,而耦合量化了依赖程度。因此,对于关系的描述方式,就可以从两个方面的观点来分析。

从依赖的角度而言,可以分类为:

·  无依赖,代表没有发生任何联系,所以二者相互独立,互不影响,没有耦合关系。

·  单向依赖,关系双方的依赖是单向的,代表了影响的方向也是单向的,其中一个实体发生改变,会对另外的实体产生影响,反之则不然,耦合度不高。

·  双向依赖,关系双方的依赖是相互的,影响也是相互的,耦合度较高。

从耦合的角度而言,可以分类为(此处回归到具体的代码级耦合概念,以方便概念的阐释):

·  零耦合,表示两个类没有依赖。

·  具体耦合,如果一个类持有另一个具体类的引用,那么这两个类就发生了具体耦合关系。所以,具体耦合发生在具体类之间的依赖,因此具体类的变更将引起对其关联类的影响。

·  抽象耦合,发生在具体类和抽象类的依赖,其最大的作用就是通过对抽象的依赖,应用面向对象的多态机制,实现了灵活的扩展性和稳定性。

不同的耦合,代表了依赖程度的差别,以“粒度”为概念来分析其耦合的程度。引用中间层来分离耦合,可以使设计更加优雅,架构更加富有柔性,但直接的依赖也存在其市场,过度的设计也并非可取之道。因为,效率与性能同样是设计需要考量的因素,过多的不必要分离会增加调用的次数,造成效率浪费。

后文分析依赖倒置原则的弊端之一正是对此问题的进一步阐述。

(2)耦合是如何产生的

那么,软件实体之间的耦合是如何产生呢?回归每天挥洒的代码片段,其实就是在重复的创造着耦合,并且得益于对这种耦合带来的数据通信。如果将历史的目光回归到软件设计之初,人类以简单的机器语言来实现最简单的逻辑,给一个输入,实现一个输出,可以表达为如图3-1所示的形式。

随着软件世界的革命,业务逻辑的复杂,以上的简单化处理已经不足以实现更复杂的软件产品,当系统内部的复杂度超越人脑可识别的程度时,就需要通过更科学的方法或者方式来梳理,如图3-2所示。

因此,人类开始发挥重组和简单化处理的优势,开发者不得不在软件设计上做出平衡。平衡的结果就是通过对复杂的系统模块化,把复杂问题简单处理,从而达到能够被人脑识别的目的。基于这种指导原则,随着复杂度的增加模块的划分更加朝着精细化发展,尤其是面向对象程序设计理论的出现,使得对复杂的处理实现了更科学的理论基础。然而,复杂的问题可以通过划分实现简单的功能模块或者技术单元,但由此应运而生的子单元会越来越多,而且越来越多的子单元必须发生数据的通信才能完成统一的业务处理,所以产生的数据通信管理也越来越多。对于子单元的管理,也就是本文关注的核心概念——依赖,成为新的软件设计问题,那么总结前人的经验,提炼今人的智慧,对耦合的产生做如下归纳:

·  继承

·  聚合

·  接口

·  方法调用和引用

·  服务调用

了解了耦合发生的一般方式,就可以进入核心思想的讨论,那就是在认识和了解依赖的基础上,最终追求的目标。

话说

设计的目标:高内聚(High cohesion)、低耦合(Low coupling)。

讨论了半天,终于是时候对依赖和耦合进行一点儿总结了,也是该进行一点目标诉求了。在软件设计领域,有那么几个至高原则值得每个开发者铭记于心,它们是:

·  面向抽象编程

·  低耦合,高内聚

·  封装变化

·  实现重用:代码重用、算法重用

对了,就是这些平凡的字眼,汇集了面向对象思想的核心内容,也是本文力求阐释的禅意心经。关于面向抽象编程和封装变化,会在后面详细阐释,在此我们需要将注意力关注于“低耦合,高内聚”这一目标。

低耦合,代表了实现最简单的依赖关系,尽可能地减少类与类、模块与模块、层次与层次、系统与系统之间的联系。低耦合,体现了人类追求简单操作的理想状态,按照软件开发的基本实现技巧来追求软件实体之间的关系简单化,正是大部分设计模式力图追求的目标;低耦合,降低了一个类或一个模块发生修改对其他类或模块造成的影响,将影响范围简单化。在本文阐释的依赖关系方式中,实现单向的依赖,实现抽象的耦合,都是实现低耦合的基础条件。

高内聚,一方面代表了职责的统一管理,一方面体现了关系的有效隔离。例如单一职责原则其实归根结底是对功能性的一种指导性体现,将功能紧密联系的职责封装为一个类(或模块),而判断的准则正是基于引起类变化的原因。所以,封装离不开依赖,而抽象离不开变化,二者的概念和本质都是相对而言的。因此,高内聚的目标体现了以隔离为目标进行统一管理的思想。

那么,为了达到低耦合、高内聚的目标,通常意义上的设计原则和设计模式其实都是朝着这个方向实现的,因此仅仅总结并非普遍意义的规则:

·  尽可能实现单项依赖。

·  不需要进行数据交换的双方,不要实现多此一举的关联,人们将此形象称为“不要向陌生人说话(Don't talk to strangers)”。

·  保持内部的封装性,关联的双方不要深入实现细节进行通信,这是保证高内聚的必需条件。

本文节选自《你必须知道的.NET(第2版)》一书

图书详细信息:http://blog.csdn.net/broadview2006/article/details/6673353

什么是依赖,什么是抽象相关推荐

  1. 【简译】关于依赖反转原则、控制反转和依赖注入的抽象的初学者指南

    原文在此. ======================================分割线==================================== 介绍 文章以介绍依赖反转原则开始 ...

  2. 抽象工廠與工廠方法的區別

    它的里面是一堆工厂方法,每个工厂方法返回某种类型的对象. 比如说工厂可以生产鼠标和键盘.那么抽象工厂的实现类(它的某个具体子类)的对象都可以生产鼠标和键盘,但可能工厂A生产的是罗技的键盘和鼠标,工厂B ...

  3. 设计模式六大原则:依赖倒置原则、为什么、多例子、分析例子、总结

    1. 依赖倒置原则的定义 高层模块不应该依赖低层模块,二者都应该依赖其抽象 抽象不应该依赖细节,细节应该依赖抽象 依赖倒转的中心思想是面向接口编程 依赖倒转原则是基于这样的设计理念: 相对于细节的多变 ...

  4. 抽象工厂模式-与-工厂方法模式区别

    转自:http://blog.csdn.net/wangwenhui11/article/details/3955125 --------------------------------- 对于jav ...

  5. 从针对接口编程到依赖注入

    1.概况说明 2.猫狗大战举例 3.说明为什么要针对接口编程,优点 4.说明为什么要"依赖抽象,不要依赖具体类" 5.说明"依赖倒置"与抽象工厂模式 6.说明& ...

  6. ASP.NET 设计模式中依赖倒置原则

    依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象. B.抽象不应该依赖于具体,具体应该依赖于抽象. 依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于 ...

  7. C#软件设计——小话设计模式原则之:依赖倒置原则DIP

    前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做" ...

  8. 设计模式-依赖倒置-Dependency Inversion Principle

    依赖倒置原则: 一般来说我们认为作为底层基础框架的逻辑是不应该依赖于上层逻辑的, 所以我们设计软件时也经常是: 需求 - 上层逻辑(直接实现需求) - 发现需要固化的逻辑 - 开发底层模块 - 然后上 ...

  9. 依赖注入 这样的坑游戏编程要谨慎

    1 IGame游戏公司的故事 1.1 讨论会 话说有一个叫IGame的游戏公司,正在开发一款ARPG游戏(动作&角色扮演类游戏,如魔兽世界.梦幻西游这一类的游戏).一般这类游戏都有一个基本的功 ...

  10. C#中的依赖注入那些事儿

    目录 目录 1 IGame游戏公司的故事 1.1 讨论会 1.2 实习生小李的实现方法 1.3 架构师的建议 1.4 小李的小结 2 探究依赖注入 2.1 故事的启迪 2.2 正式定义依赖注入 3 依 ...

最新文章

  1. eclipse字体大小设置_Java 设置Excel单元格格式—基于Spire.Cloud.SDK for Java
  2. 关于在SVG中如何实现gif动画的问题?
  3. 实验图文详解——apache的编译安装及httpd服务开机自启
  4. 小米 华为都要造车?.NET高薪潮来了!(附招聘链接)
  5. 跟我一起学.NetCore之.NetCore概述
  6. 写给中学生的算法入门:学代码之前看这篇就够了
  7. 《java入门第一季》之类面试题
  8. OSI七层参考模型、TCP/IP参考模型、数据封装与解封装、TCP三次握手四次挥手及面试题
  9. 11.Handle assignment to self in operator =
  10. 卫星地图上,深圳梧桐山这一条白线是什么
  11. 【转】用java将pdf转换成jpg图片的代码
  12. STM8S的按键PWM调光灯历程
  13. 5G 技术特性、频段、架构、部署极5G 手机
  14. llqrcode.js识别二维码,解析二维码信息
  15. C语言知识-零零散散(三)
  16. 寄存器一般多大,cpu一级缓存一般多大
  17. js 模拟enter键
  18. NFS服务6---四种情况的权限实验
  19. 菜单栏、工具栏和状态栏
  20. 程序员的1024|我学开发第二年|专心练剑

热门文章

  1. JavaScript实现按字典排序进行md5加密, 以及个人在小程序也可以实现
  2. Centos7 超简单将Centos的yum源更换为国内的阿里云源
  3. C++的函数指针的使用(仍存在问题)
  4. IE9 表格错位bug
  5. PL/pgSQL的RETURN QUERY例子
  6. SVN server
  7. (LINQ 学习系列)(3)学习Linq的几个基础知识
  8. ppt使用记录之添加带圈的20以内的数字编号
  9. orangepi香橙派安装VNC Viewer远程桌面
  10. leetcode 1037. 有效的回旋镖(Valid Boomerang)