Introduction— SIMPLICITY—> RIGHT —> EXPLAIN
评价软件架构设计好坏的标准:
- 对于代码很小的修改是不是会对其他地方有较大的影响 — flexible
- 代码重用是不是很困难 — reusable
- 软件是不是很难维护 — maintainable
Design — Architecture
Use Object to represent things; Modular,
用户故事的重要性
三种对象
实体对象
对应于现实生活中的一些实体。
知道自身的一些属性,同时可以对自己进行编辑。
在分析时,通常是最先出现的。
边界对象
边界对象位于系统的交界处,例如和网络进行通信的对象。
控制对象
控制对象的主要作用是协调。当把一个大对象拆分成小对象之后,让一个对象控制其他对象是非常有用的。
一个很好的例子就是设计模式之中的Mediator, 其作用是通过协调使得不同的对象之间达到松耦合的效果。
flexible, reusable, and maintainable~
Non functional Requirements
CRC cards:
Class Responsibility Collaborator
Record Organize Refine
Object-Oriented Modeling
1 | abstraction, encapsulation, decomposition, and generalization |
Degisn Pricinples — Abstraction
抽象将概念的简要表示提取出来,并忽略一些不重要的细节,从而让我们更好地理解概念。
Relevent Attributes and Behavior IN THIS CONTEXT
Encapsulation
封装既包括把属性值和行为包含在一个对象里,还包括暴露特定的数据和函数,同时还有将对某些数据和方法的访问限制在同一个对象内。
封装的思想之一是将对某些数据和功能的访问限制为仅在一个对象内.
这就提供了以下几点有用的性能:
- 自身的属性限制—-Integrity and Security
- 对外界数据和方法的保禄—-Changeable Implementation
- 内部的实现外部无法看到—-Black box, abstraction barrier , increase reusability
Decomposition
分解:把一个大的问题拆分成容易理解和解决的小问题
整体中的每一个不同的部分都可以单独开一个类,这样我们就能更好地组织、封装不同的部分。
整体和部分的关系
- 整体会包含多个部分,部分的数目可能是固定的,也可能是可变的,这取决于具体的问题。
- 整体和部分都有自己特定的生存周期,二者的生存周期可能是相同的,也可能是不同步的,同样需要具体问题具体分析。
- 整体之间也可以分享自己的部分
三种分解关系
Association
不依赖于彼此,但是可能会相互交互,
1
2
3
4
5
6
7
8
9Association can be represented in Java code as well.
public class Student {
//Any number of sports can be played by a student and any number of students can play a sport.
public void play( Sport sport ){
execute.play( sport );
}
…
}Aggregation
整体拥有部分,但这种拥有权是比较弱的,部分也可以单独存在。
1
2
3
4
5
6
7
8
9
10
11
12
13Aggregation can be represented in Java code as well.
public class Airliner {
private ArrayList<CrewMember> crew;
public Airliner() {
crew = new ArrayList<CrewMember>();
}
public void add( CrewMember crewMember ) {
…
}
}Composition
合成关系整体对于部分的排他性包含。换句话说,没有部分就不能存在一个整体,如果整体被破坏了,那么这些部分也将被破坏。在这中关系中,我们只能通过整体来访问部分。例如房屋和房间的关系。
1
2
3
4
5
6
7
8
9Composition can be represented using Java code as well.
public class House {
private Room room;
public House(){
room = new Room();
}
}
Generalization
泛化体现在以下方面:
methods: 同一个方法可以用于不同的输入数据,因此我们不需要为每一个数据都建立方法,减少了代码的冗余。
inheritance: 通过继承可以省略重复的代码。
继承的优点:对于不同子类方法的修改只需要一次性在父类中修改即可。可以轻松添加子类,而不用重新添加相同的属性和方法,软件扩展起来更加容易。
1 | Java中受保护的属性只能由以下人员访问: |
继承的不同种类
Java能够支持几种不同类型的继承。本课程中的以上示例是实现继承。
实现继承
只能继承一个父类,提供了方法的实现细节。表示“是”关系。对于狮子来说,它既有动物的属性,又有狮子特有的属性,因此狮子是动物和狮子。
接口继承
可以实现多个接口,同时不会继承方法细节。
这是因为从两个或多个超类继承会引起数据歧义 - 如果子类从两个或多个具有相同名称的属性或具有相同方法签名的行为的超类继承,则无法区分它们。由于Java无法确定引用了哪个对象,因此它不允许多重继承以防止数据歧义。而在接口继承中,具有多个接口的重叠方法签名只有单一实现,这是可以接受的。
在实现继承中,超类类型和子类类型之间具有一致性。子类对象可在程序中要处理超类类型的任何地方使用。类似地,在接口继承中,接口类型与实现类类型之间具有一致性。
使用接口的好处:
在面向对象的语言中,多态是指两个类对行为的描述相同,但是该行为的实现可能不同。
- 接口可以继承其他接口
- 允许多重继承
使用接口的时机
不应该将所有behavioural contracts都归纳为接口。创建接口需要满足特定要求:为相关类提供一种一致工作的方式。
设计的步骤
和顾客沟通时,主要使用的技术是CRC卡片,而在技术设计中,UML类表是更合适的选择。
DESIGN PRINCIPLES
Evaluating Design Complexity
模块:指代组成程序的多个单元,包括其中的类和方法。这也是Design complexity关注的粒度。
良好的设计:模块可以重复使用,并且很方便地连接其他模块。这种特性主要由Cohesion和Couping两种指标来衡量。
耦合: ease to use -> loose couplng, 如果一个模块可以很容易地通过定义明确的接口连接其他模块,则是松耦合的。模块的耦合主要通过三个指标来度量:
- Degree 模块和其他模块连接的数目。
- Ease 模块之间建立连接的容易程度。
- Flexibility 模块之间是否很容易地进行调换, for something better in the future.
高耦合的特征:
- 一个模块需要通过大量的接口和参数来和其他模块建立连接。
- 一个模块相连的其他模块很难找到。
- 模块只能和其他几个特定的模块相连,而难以替换。
内聚: 目标要单一、明确,如果一个模块包含多个目标,则应该对其进行分隔。
需要平衡二者的关系。Complexity要合理地分布在模块之间和模块内。
Separation of Concerns 关注点分离
关注点:任何和问题的解决方法相关的事情。不同的关注点要放在软件的不同位置。