BUAA_OO_UNIT4 总结
OO_unit4 架构设计
文件结构
- src // 代码根目录
- base // 存放基类,所有的模型继承自此处
- MyUml // uml模型基类
- MyLink // 链接关系的基类
- classes // 类图相关文件
- MyClass
- MyInterface
- MyAttribute
- MyParameter
- MyOperation
- MyAssociationEnd
- collaboration // 顺序图相关文件
- MyCollaboration
- MyInteraction
- MyInteractionItem
- MyMessage
- main // 主类包
- Database // 数据库模型
- MainClass
- MyImplementation
- state // 状态图相关文件
- MyEvent
- MyRegion
- MyState
- MyStateMachine
- MyTransition
UML类图
classes
collaboration
state
架构总结
整体思路
其实整体思路很简单,就是根据题目需求,在原来模型的基础上,简化、去掉部分属性或方法,将其抽离出来,按照自己的方式,形成另一套模型,并加入自己的逻辑。
模型关联
每一个模型都继承自基类MyUml
或者MyLink
。MyUml
定义了最基础的只读属性id
,name
,parentId
,visibility
以及获取他们的方法。MyLink
定义了最基础的关联关系,由一个source
的Uml对象指向另一个target
对象,用于两个对象形成关联或者交互。
代码可读性维护
值得一提的是,在三次作业的逐次扩展、迭代开发中,代码量越来越大,单个文件代码行数也呈爆发式增长,为了不影响代码可读性(其实是checkStyle逼出来的),我将各个文件进行了分包处理,这样会使得整个文件层次更加清晰;同时,引入Database
数据库模型,将数据存储与生成单独分离出来,并使之成为MyImplementation
的一个属性,需要获取某个数据时,直接调用数据库的getter
方法即可。
逐层封装
将某些通用的方法进行单独封装。比如,在MyImplementation
层次,通过名称获取类的对象:
public MyClass getClassByName(String s)
throws ClassNotFoundException, ClassDuplicatedException {
HashMap<String, MyClass> classMap = database.getClassMap();
MyClass myClass = null;
for (MyClass classItem: classMap.values()) {
if (classItem.getName().equals(s)) {
if (myClass == null) {
myClass = classItem;
}
else {
throw new ClassDuplicatedException(s);
}
}
}
if (myClass == null) {
throw new ClassNotFoundException(s);
}
return myClass;
}
再比如,在MyClass的层次,通过方法名,获取该类的方法:
public List<MyOperation> getOperationByName(String s)
throws MethodWrongTypeException, MethodDuplicatedException {
List<MyOperation> operations = new ArrayList<>();
for (MyOperation myOperation: operationList) {
if (myOperation.getName().equals(s)) {
if (!checkOperationValid(myOperation)) {
throw new MethodWrongTypeException(getName(),s);
}
operations.add(myOperation);
}
}
for (int i = 0; i < operations.size() - 1;i++) {
MyOperation myOperation1 = operations.get(i);
for (int j = i + 1; j < operations.size(); j++) {
MyOperation myOperation2 = operations.get(j);
if (checkOperationDuplicated(myOperation1,myOperation2)) {
throw new MethodDuplicatedException(getName(),s);
}
}
}
return operations;
}
隐藏实现,暴露接口。比如实现getClassSubClassCount
时,将需要的方法封装置于MyClass
中,在获取了MyClass
对象后直接从MyClass
对象调用实现。
@Override
public int getClassSubClassCount(String s)
throws ClassNotFoundException, ClassDuplicatedException {
return getClassByName(s).getNumOfSubClass();
}
public int getNumOfSubClass() {
return subClassCount;
}
通过逐层封装,不仅能够减少单个文件、单个方法的代码量,使整个项目可读性提高,增加各个类的独立性,降低类之间的关联程度,符合“高内聚,低耦合”的设计理念。
OO课程学期总结
架构设计思维及OO方法理解的演进
因为大一从事过游戏项目的开发工作,对面向对象有一定的理解基础,因此在一开始接触OO课程的时候就有意去分析需求,抽象模型,打磨架构,在电梯单元的体现尤为明显:从一张架构设计图到整个项目的千行代码,程序开发本身就应该是先有图后有码的过程。如今,经过OO课程的训练,我对抽象与架构有了更深层次的认识,熟练度也有了质的飞跃。
对测试的理解与实践的演进
程序开发过程,很难保证不会出现bug,所以需要对程序进行全方位测试。
第一单元,嵌套括号的拆分是一个递归的过程,那么数据生成中又何尝不是呢。在此基础上,我进行数据的生成,而正确性校验采取标准答案对比的方式。
第二单元,数据生成时,将各个乘客需求进行时间先后的序列化,采用纯随机方式生成即可。正确性校验则采用分点校验,如乘客最终是否出电梯并到达目的地,电梯有无超载等。
第三单元,数据生成采用半随机方式,重点针对边界条件进行测试。正确性校验采用多人对拍的方式进行。
第四单元,未进行测试。
课程收获
知识层面,深入学习并实践了面向对象的编程思想,个人代码力也有很大的提高,从课程单元作业架构到评测机搭建,处处都在学习并实践着OO这一编程思想,对程序开发有了更深层次的体悟。
协同方面,增进了与他人合作开发的能力(开发评测机),提升了自己的团队协作能力,与他人协作开发一个工程的经历让我甚是感念,甚是激动,甚是自豪。
课程建议
- bug修复模块的限制过于严苛,改bug一次改5行以内的规则有时候会很恼人,让人无从下手。
- 增加课程趣味性、实际应用性。像第二单元这样充满实际应用感的作业就一个单元,其他单元感觉都是在与抽象的理论打交道,多少让人少了一点“码”的动力。
- OO指导书有些部分讲述不够清晰,模棱两可,容易产生误导,建议教学团队加强对OO指导书的规范工作。