结对项目1
结对编程初体验
这次结对项目我的小伙伴是中国的朋友闫昊,因为我的代码能力没有比他那么好所以他辛苦了很多。
关于information hiding,interface design,losse coupling和design by contract,code contract
-
信息隐藏
通过类的封装实现信息的隐藏,信息隐藏使得类内部的私有属性或方法不能被类外部访问,有效地保护了类内的数据,实现了类的封装。具体的,在core.dll文件中所有类的属性都是private,供各个类间调用的方法的访问权限为internal,接口的访问权限为public以便外部程序调用。 -
接口设计
在我的程序中,分为核心计算程序(core)和用户界面程序(ui),ui通过导入core生成的dll,并调用其中的函数,来实现表达式生成、判断对错和计算的功能。ui需要告诉core是否包含负数、是否支持分数、表达式数量和运算符数量等参数,core需要把计算、检验结果以及异常等信息反馈给ui。这就需要在core和ui间定义接口。同样的在类与类之间,类内部各方法相互调用也需要定义接口。接口的定义需要遵循以下原则:- 单一职责原则
Single Responsibility Principle, 简称SRP。
定义:There should never be more than one reason for a class to change. - 里氏替换原则
Liskov Substitution Principle, 简称LSP。
定义:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.(所有引用基类的地方必须能透明地使用其子类的对象) - 依赖倒置原则
Dependence Inversion Principle, 简称DIP
定义:High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions. - 接口隔离原则
定义:1.Clients should not be forced to depend upon interfaces that they don't use.(客户端不应该依赖它不需要的接口)
2.The dependency of one class to anther one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上) - 迪米特法则
Law of Demeter, LOD。又称最少知识原则(Least Knowledge Principle, LKP)。
通俗来讲:一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没有关系,那是你的事情,我就调用你提供的public方法,其他一概不关心。 - 开闭原则
Software entities like classes, modules and functions should be open for extension but closed for modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭)应该有且仅有一个原因引起类的变更。
- 单一职责原则
基于以上规则在ui和core间定义了如下接口:
public static string createExpression(int ExpressionCount, String outputfile_e, String outputfile_a,bool negative, bool bracker, bool muldiv, bool profraction, int range, int op_num)
public static String checkExpression(String exercisefile, String anwserfile)
public static string calculate(String expression)
分别用于产生表达式、检验表达式、计算。
- 松耦合
很多设计模式就是为了解决紧耦合的问题。如果两个组件耦合太紧,则说明一个组件和另一个组件直接相关,这样的话,如果修改一个组件的逻辑,那么另外一个组件的逻辑也需修改。当能够做到修改一个组件而不需要更改其他的组件时,就做到了松耦合。利用面向对象建模的方法、信息隐藏的设计思想和遵守接口间的设计原则可以很好的降低程序间的耦合度,实现程序的松耦合。
Design by Contract & Code Contract
代码契约(Code Contract)就是让你用额外的代码来表达应用程序中对代码的假设情况,一般可以执行前置条件、后置调剂和不变式。在我看来:代码契约有点类似断言,但是比断言要强大;也类似单元测试,但是比单元测试好,根据底层也是对单元测试的一种补充。Dirk Strauss的这篇文章有简单明了的示例代码和直观的截图,对于这个工具的使用是一个很好的入门教程。
原文地址:http://www.dirkstrauss.com/programming/introducing-code-contracts#.VWCNlvnvO70
契约式设计(Design by Contract)是一种设计计算机软件的方法。这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。这种方法的名字里用到的“契约”或者说“契约”是一种比喻,因为它和商业契约的情况有点类似,在DbC中,使用者和被调用者地位平等,双方必须彼此履行义务,才可以行驶权利。调用者必须提供正确的参数,被调用者必须保证正确的结果和调用者要求的不变性。双方都有必须履行的义务,也有使用的权利,这样就保证了双方代码的质量,提高了软件工程的效率和质量。缺点是这个契约在项目的不断迭代中,由于需求、功能发生的变化,这个契约很可能会改变,并且契约式编程并未被标准化,因此项目之间的定义和修改各不一样,给代码造成了混乱。在我的代码中,对方法间的调用采用了契约的思想,调用者必须保证传入参数是正确的,否则被调用者不保证结果的正确性。
单元测试
核心算法
主要的算法分为两个部分
1.表达式运算
在定义好分数之间的运算的前提下可以利用调度场算法进行计算。
调度场算法详见:http://blog.csdn.net/kyfvc/article/details/7404752
2.判断表达式是否重复
分离表达式含有的运算数和运算符,把运算数从大到小排列,把运算符按出现顺序排列将这两个字符串拼接起来形成表达式的id,在判断表达式是否重复的时候只需判断表达式id是否出现过。这种方法虽然简单但也有缺陷,可能导致不同的表达式的id是一样的从而导致过滤掉不该过滤的表达式,但是这种情况的概率很小。更好的方法是根据运算符为每个表达式构造一棵树,判断并生成这棵树的最小表示,由于这个方法有些麻烦,为了提高开发效率选择了前种算法。