软件架构————设计启发

关键的设计概念

软件的首要技术使命:管理复杂度

项目的失败大多都是由不尽人意的需求、规划和管理所导致的。但是,当项目的确由技术因素导致失败时,其原因通常就是失控的复杂度。

在软件的架构层次上,可以通过把整个系统分解为多个子系统来降低问题的复杂度。所有设计技术的目标都是把复杂问题分解成简单的部分。子系统间的相互依赖越少,就越容易在同一时间里专注问题的一小部分。精心设计的对象关系使关注点相互分离,从而使你在每个时刻只专注于一件事。


如何应对复杂度?

1.把任何人在同一时间需要处理的本质复杂度的量减到最少。

2.不要让偶然性的复杂度无谓地快速增长。


理想的设计特征:

最小的复杂度:应该设计出简单易于理解的设计。

易于维护:意味着在设计时为做维护工作的程序员着想。

松散耦合:在设计时让程序的各个组成部分之间关联最小。荣国应用类接口中的合理抽象、封装性及信息隐藏等原则,设计出相互关联尽可能最少的类。

可扩展性:当增强系统功能时无需破坏其底层结构。

可重用性:所设计的系统组成部分能在其他系统中重复使用。

高扇入:让大量的类使用某个给定的类。这意味着设计出的系统很好地利用了在较低层次上的工具类。

低扇出:让一个类里少量或适中地使用其他的类。

可移植性:使设计的系统可以很方便的移植到其他系统中。

精简性:意味着设计出的系统没有多余的部分。

层次性:尽量保持系统各个分解层的层次性,使你能在任意的层面上观察系统,并得到某种具有一致性的看法。设计出来的系统应该能在任意层次上观察而不需要进入其他层次。

标准技术:要尽量用标准化的、常用的方法,让整个系统给人一种熟悉的感觉。


设计的层次:

第一层:软件系统


第二层:分解为子系统或包

在这一层次上设计的主要成果是识别出所有的主要子系统。这一层的主要设计活动就是确定如何把程序分为主要的子系统,并定义清楚允许各子系统如何使用其他子系统。对于任何至少需要几周时间才能完成的项目,在这一层次上进行划分通常都是必要的。

这一层次中,最重要的一点就是不同子系统之间相互通信的规则。如果所有的子系统都能同其他子系统通信,你就完全失去了把它们分开所带来的好处。应该通过限制子系统之间的通信来让每个子系统更有存在的意义。

这一层次常用的子系统:业务规则、用户界面、数据库访问、对系统依赖性(写成一个封装体这样可以在换不同的系统时可以方便的修改)


第三层:分解为类

在这一层次上的设计包括识别出系统中所有的类。

当定义子系统中的类时,也就同时定义了这些类与系统的其余部分打交道的细节。尤其是要确定好类的接口。总的来说,这一层的主要设计任务是吧所有的子系统进行适当的分解,并确保分解出的细节都恰当好处,能够用单个的类实现。

类与对象的比较:面向对象设计的一个核心概念就是对象与类的区分。对象是指运行期间在程序中实际存在的具体实体,而类是指在程序源码中存在的静态事务。对象是动态的,他拥有在程序运行期间所能得到的具体的值和属性。


第四层:分解成子程序

这一层的设计包括把每个类细分为子程序。在第三层中定义的类接口已经定义了其中一些子程序,而第四层的设计将细化出类的私用子程序。当查看类里面子程序的细节时,就会发现很多子程序都很简单,但也有些子程序是由更多层次组织的子程序所组成的,这就需要更多的设计工作了。


第五层:子程序内部的设计

在子程序层次上进行设计就是为了每个子程序布置详细的功能。子程序内部的设计工作通常是由负责该子程序的开发人员来完成的。这里的设计工作包括编写伪代码、选择算法、组织子程序内部的代码块,以及用编程语言编写代码。


设计构造块:启发式方法

由于软件设计是非确定性的,因此,灵活熟练地运用一组有效的启发方式方法,便成了合理的软件设计的核心工作。


找出现实世界中的对象:

识别对象及其属性

确定可以对各个对象进行的操作

确定各个对象能对其他对象进行的操作

确定对象的哪些部分对其他对象可见

定义每个对象的接口


形成一致的抽象:

抽象是一种能让你在关注某一概念的同时可以放心地忽略其中一些细节的能力——在不同的层次处理不同的细节。

以复杂度的观点看,抽象的主要好处就在于它使你能忽略无关的细节。大多数现实世界中的物体都已经是某种抽象了。抽象是我们用来得以处理现实世界中复杂度的一种重要手段。


封装实现细节:

封装帮助你管理复杂度的方法是不让你看到那些复杂度。


当继承能简化设计时就继承:

定义对象之间的相同点和不同点就叫做“继承”,继承的好处在于它能很好地辅佐抽象的概念。抽象是从不同的细节层次来看对象的。


隐藏秘密(信息隐藏)

信息隐藏是结构化程序设计与面向对象设计的基础之一。当信息被隐藏后,每个类都代表了某种对其他类保密的设计或构建决策。隐藏起来的秘密可能是某个易变的区域,或者某种文件格式,或者某种数据类型的实现方式,或者某个需要隔离的区域,在这个区域中发生的错误不会给程序其余部分带来太大损失。在这里,类的职责就是把这部分信息隐藏起来,并保护自己的隐私权。


信息隐藏中所说的秘密主要分为两大类:

1、隐藏复杂度,这样就不用再去应付他,除非要特别关注的时候。

2、隐藏变化源,这样当变化发生时,其影响就能被限制在局部范围内。


信息隐藏的障碍:

少数情况下,信息隐藏是根本不可能的。

信息过度分散:信息隐藏的常见障碍之一是信息在系统内过度分散。你可能吧100这个数字直接写到了程序里,这样会导致对他的引用过于分散。最好把这部分信息隐藏起来,如果写一个MAX_VALUE,而这个常量要改变只需要一次。

循环依赖:避免各个类之间的相互依赖形成一个环,这样会让系统难以进行测试。

把类内数据误认为全局数据:有效地隐藏信息的障碍之一就是把类内数据误认为是全局数据并避免使用它,因为你想避免全局数据可能带来的问题。

全局数据通常会困于两类问题:一种是子程序在全局数据之上执行的操作,但却不知道还有其他的子程序也在用这些全局数据进行操作:另一种是子程序知道其他的子程序也在用全局数据进行操作,但却无法明确地知道都进行了哪些操作。


找出容易改变的区域

好的程序设计所面临的最重要挑战之一就是适应变化。目标应该是把不稳定的区域隔离出来,从而把变化所带来的影响限制在一个子程序、类或者包的内部。采取的应对各种变动的措施:

1.找出看起来容易变化的项目。

2.把容易变化的项目分离出来。

3.把看起来容易变化的项目隔离开来。


容易变化的区域:

业务规则、对硬件的依赖性、输入和输出、非标准的语言特性、困难的涉及区域和构建区域、状态变量、数据量的限制。


预料不同程度的变化:

找出容易发生变化的区域的一个好办法是:首先找出程序中可能对用户有用的最小子集。这一子集构成了系统的核心,不容易发生改变。接下来,用微小的步伐扩充这个系统。这里的增量可以非常微小,小到看似微不足道。当你考虑功能上的改变时,同时也要考虑质的变化:比如说让程序编程线程安全的,使程序能够本地化等。


保持松散耦合:

耦合度表示类与类之间或者子程序与子程序之间关系的紧密程度。耦合度设计的目标是创建出小的、直接的、清晰的类或者子程序,使他们与其他类或子程序之间关系尽可能地灵活,这就被称作”松散耦合“。模块之间的好的耦合关系会松散到恰好能使一个模块能够很容易地被其他模块使用。


耦合标准:

规模->这里的规模是指模块之间的连接数。对于耦合度来说,小就是美,因为只要做很少的事情,就可以把其他模块与一个有着很小的接口的模块连接起来。只有一个参数的子程序与调用它的子程序之间的耦合关系比有六个参数的紫长旭与他的调用方之间的耦合关系更为松散。


可见性->指的是两个模块之间的连接的显著。通过参数表传递数据便是一种明显的连接,通过全局变量进行连接的设计不提倡。


灵活性->指的是模块之间的连接是否容易改动。一定程度上,灵活性是其他几个耦合特性综合作用的结果,但是也的确有所不同。


耦合的种类:

简单数据参数耦合、简单对象耦合、对象参数耦合、语义上的耦合(不提倡)


松散耦合的关键之处在于,一个有效的模块提供了一层附加的抽象,一旦写好了,就可以想当然的去用它。这样就降低了整体系统的复杂度,使得可以在同一时间只关注一件事情。类和子程序是用于降低复杂度的首选和最重要的工具,如果他们没有简化工作,那么他们就是失职的。


查阅常用的设计模式:

设计模式通过现成的抽象来减少复杂度

设计模式通常把常见解决方案的细节予以制度化来减少出错

设计模式通过提供多种设计方案而带来启发性的价值

设计模式通过把设计对话提升到一个更高的层次上来简化交流


总结:

1.寻找现实世界的对象

2.形成一致的抽象

3.封装实现细节

4.在可能的情况下继承

5.藏住秘密(信息隐藏)

6.找出容易改变的区域

7.保持松散耦合度

8.探寻通用的设计模式



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值