软件构造 课堂笔记4
这篇文章会较多的搬运PPT上面内容,因为我认为确实比较重要,也会在里面加上一些我个人的理解
类接口设计建议
一:好的抽象
类的接口应能提供一组 明显相关 的子程序
类的接口应该尽量展现一致的抽象层次
class EmployeeCensus: public ListContainer {
public:
void AddEmployee(Employee employee);
void RemoveEmployee(Employee employee);
Employee NexItemInList();
Employee FirstItem();
Employee LastItem();
private:
};
在这里面,前两个方法是EmployeeCensus类的ADT功能,而后三个是ListContainer接口里的方法。也许可能有人认为前面两个接口也都是ListContainer里面的,但是从命名来看,确实前两个方法更贴近于Employee的层次。也就是这里表现出了两种抽象,最主要的原因是EmployeeCensus这个类继承了ListContainer类,但是这里不符合”is a”原则,因此不应该使用继承,而应该使用组合。
class EmployeeCensus {
public:
void AddEmployee(Employee employee);
void RemoveEmployee(Employee employee);
Employee NexItemInList();
Employee FirstItem();
Employee LastItem();
private:
ListContainer m_EmployeeList;
};
这种写法与上一种写法相比,要稍微好一些。上一种对于各个方法的实现需要自己直接管理数据,也要处理逻辑。下一种写法的话,对于数据的管理交给了m_EmployeeList,自己来处理逻辑。
- 谨防在修改时破坏接口抽象
这是因为,在很多赶工期的时候,人们会不自觉地将需要的接口随便先找个地方放进去,而不考虑抽象的事情。
二:好的封装
不要暴露自身数据和实现细节
-
封装比抽象更严格,二者相辅相成
- 抽象:提供可以忽略实现细节的模型来管理复杂度
- 封装:阻止你看到细节
-
尽可能限制类和成员的可访问性
- 采用最严格且可行的访问级别
即所有类成员的访问限定符都是private,然后根据访问器来访问。
不要公开暴露成员数据
错误的做法:
public:
float x;
float y;
float z;
正确的做法:
public:
float getX();
float getY();
float getZ();
void setX(float x);
void setY(float y);
void setZ(float z);
我们这么做,是可以不暴露x,y,z的属性的,因为假设我们将x设置为string类型,这么做可能是为了前端显示起来比较方便,那么这时候get和set方法就隐藏了x的变量类型。
- 避免把私有的实现细节放到类的接口中
由于我们平时都是写Java,所以不管怎么样都是可以看到实现细节的,所以这里不列出PPT上的内容了,其实也是《代码大全》上的内容。
-
不要对类的使用者做任何假设
很多东西不应该写在注释里,而应该写在代码里。比如我们不希望使用者将x初始化为0,我们可以用assert而不是使用注释。
避免使用友元类
不要因为一个子程序里仅使用公用子程序,就把它归入公开接口
让阅读代码比编写代码更方便
要格外警惕从语义上破坏封装性
如果必须要看到底层实现才能理解发生的事情,那还算不上抽象。——P.J Plauger
表现为:调用方代码不是依赖于类的公开接口,而是依赖于类的私用实现。
解决方案是针对接口编程。
不知道如何使用类的接口时,联系类的作者,作者应该修改类的接口文档。
二者相关,或者两者都有,或者两者皆失
设计实现
包含
- 面向对象编程中的主力技术
- 警惕超过7个数据成员的类
继承
- 使用时应该谨慎
- 遵循里氏替换原则
- 基类中定义的所有子程序,在它的任何一个派生类中含义应该是相同的。典型的例子是借款、存款Account里面的InterestRate,一个是借钱,一个是还钱,需要程序员记得其中的差异才行,所以不能继承同一个类。
- 在多处使用switch-case时,很可能应该使用多态
Demeter原则
假设有一个类O,O里面有一个方法M
public class O{
private int x;
public void A() {
}
public void M(O1 o1) {
O2 o2 = new O2();
}
}
这时候M只可以调用一下几种对象的方法:
- O里面的方法
- O的直接组件对象 // 不应该出现多层.调用的情况
- M的参数
- 在M中创建的对象
构造函数
- 尽可能在所有构造函数中初始化所有数据成员
先给一个全部参数的构造函数,然后在别的构造函数里面调用全部参数的构造函数
上一篇: 软件构造课程笔记——软件质量目标
下一篇: 软件构造实验2 : 实验记录
推荐阅读
-
[HITSC]哈工大软件构造Lab3+Lab4实验总结
-
软件构造3.2设计规约笔记
-
【课堂笔记精选】为了能够用“Unity”软件做游戏,我要从最基础的开始复习JavaScript
-
CSS高效开发实战:CSS 3、LESS、SASS、Bootstrap、Foundation 读书笔记(4)构造尺寸更灵活的背景_html/css_WEB-ITnose
-
【课堂笔记精选】为了能够用“Unity”软件做游戏,我要从最基础的开始复习JavaScript
-
CSS高效开发实战:CSS 3、LESS、SASS、Bootstrap、Foundation 读书笔记(4)构造尺寸更灵活的背景_html/css_WEB-ITnose
-
c++11学习笔记(4)- 移动构造函数与移动语义
-
软件构造学习笔记1--github提交问题解决与阶段学习感想
-
软件构造——《代码大全》第六章读书笔记
-
软件构造——Lab4测试部分客户端代码的方法