270
社区成员
发帖
与我相关
我的任务
分享将除输入简单处理后,传递给InputAnalysis进行处理,方便进行统一的测试,同时防止MainClass逻辑过于复杂。其管理一个冒险者的列表,并调用Print静态类来进行输入输出操作。

使用一个Item作为父类,对于每一个Adventurer,使用一个Map来描述由id到item的映射,组织起每一个冒险者的物品携带逻辑。使用一个Usable接口,来统一组织物品使用时的逻辑。

使用一个工厂模式为每一个Item的细分类型进行统一实例化,ItemFactory作为统一接口(虽然ItemFactory有过度设计之嫌)

使用try-catch和Exception,处理冒险者攻击时,出现的各种失败情况。无需使用复杂的返回值与“魔数”。BaseExeption继承自IllegalArgumentException,如果出现未处理的失败情况便于即使发现。
使用树结构处理复杂的输入逻辑,此处箭头表示内部类,使用内部类可以减少类的数目,最终SyntaxTree转化为RelationshipList提供给InputAnalysis处理。(使用内部类其实主要是我想试试(?))

大的架构调整主要有以下几次:
将Bottle、Equipment、Spell抽象为统一的Item,并建立Usable接口,减少了Adventurer对于这些物品的管理时的代码数量。(不需要同样的代码逻辑写三遍)
对Item的管理从ArrayList改为Map。(体会到了模板泛型的好处)
从MainClass中分离出InputAnalysis类,方便测试并简化MainClass逻辑。
设立了多个Factory,抽象出物品的实例化工作。(现在反思,应该使用简单工厂模式更加合适)
增加观察者模式,处理援助逻辑。
增加多个Exception。(不再需要使用bool类型的返回值,同时可以分别处理不同类型的特殊情况)
增加了简单的输入分析,将复杂的输入转化为简单的逻辑执行。
JUnit可以对每一类型进行单独的测试,方便测试发现错误之后的快速定位;同时可以重复使用,在逻辑修改/功能添加后快速地检查该修改是否影响到之前的代码逻辑。比如在对于某一个类型的修改之后,可能会发现其他的一个类型的测试出现问题,提醒我们可能对于这个地方的修改有影响到其他模块的正常工作。
同时JUnit测试的编写十分耗时(……),尤其时在有时修改代码逻辑之后,可能需要重写测试代码。这也提醒我们要降低代码之间的耦合关系,同时在写一个方法的时候,应该提前考虑到未来可能的新需求,对于被大量调用的方法,如果需要不同的逻辑应该首先考虑使用一个新的方法而不是在老方法上重复修改。JUnit编写很麻烦也在一定程度上提醒我不要过度设计,否则写JUnit容易累4。(Exception类往往有大量的实例化方法,但是往往不都能用到。导致方法的测试覆盖率巨低。。。最终不得不删除了很多的Exception)
面向对象的程序设计相较于面向过程的编程在设计思想上有很大差异。虽然对于小型的任务,选用面向对象的编程语言可能导致更长的代码与更长的编写时间,但是当这个任务可能有源源不断的新需求时,面向对象的设计方式在长远角度上来讲有巨大的优势,大大提升了代码的可读性和可维护性。
在我看来,面向对象和面向过程并没有优劣之分,两者实际上适应着不同的任务需求。对于小型、逻辑简单的任务,面向对象语言不仅代码量更大,同时可能导致对于计算资源的要求更大(比如过长的继承链、大量的重载等),得不偿失;对于计算资源十分有限/涉及更底层的情况(比如嵌入式、系统开发等),可能C语言这类中级语言更加适合。
在这一段时间的程序设计实践中,我认为十分重要的是对于未来需求的预测,在当前阶段的设计中应该为以后可能的新需求预留扩展空间,而不是追求最快速地实现当前的逻辑,否则之后阶段的开发所需时间将指数级上升。
希望JUnit的评价机制更加多元,同时希望教学中能有更多如何编写JUnit的教学。