我已经查看了一些答案并在Google上进行了搜索,但是找不到任何有用的东西(即不会产生尴尬的副作用)。
总的来说,我的问题是我有一个对象,需要对它执行长时间的操作。我将其视为一种装配线,例如制造汽车。
我相信这些对象将称为“ 方法对象”。
因此,在此示例中的某个点上,我将拥有一个CarWithoutUpholstery,然后需要在其上运行installBackSeat,installFrontSeat,installWoodenInserts(这些操作不会互相干扰,甚至可以并行执行)。这些操作由CarWithoutUpholstery.worker()执行,并产生一个新的对象,该对象将是CarWithUpholstery,然后在其上运行cleanInsides(),verifyNoUpholsteryDefects()等。
单个阶段中的操作已经是独立的,也就是说,我已经在努力应对可以按任何顺序执行的子集(可以按任何顺序安装前排和后排座椅)。
我的逻辑当前使用反射来简化实现。
也就是说,一旦有了CarWithoutUpholstery,该对象就会检查自身是否有名为performSomething()的方法。此时,它执行所有这些方法:
myObject.perform001SomeOperation();
myObject.perform002SomeOtherOperation();
...
同时检查错误和内容。虽然操作的顺序是不重要的,我已经在指定情况下,我曾经发现毕竟一些顺序很重要,一个字典顺序。这与YAGNI矛盾,但是它花费很少-简单的sort()-并且可以节省大量的方法重命名(或引入其他执行测试的方法,例如方法数组)的费用。
一个不同的例子
让我们说,除了要制造汽车外,我还必须编辑某人的秘密警察报告,并将其提交给我的邪恶霸主。我的最后一个对象将是ReadyReport。为了构建它,我首先收集基本信息(姓名,姓氏,配偶...)。这是我的A阶段。根据是否有配偶,我可能不得不进入B1或B2阶段,并收集一两个人的性行为数据。这是由对不同的Evil Minions的几个不同的查询所组成,它们控制着夜生活,街拍,性用品商店的销售收据以及不收什么。等等等等。
如果受害者没有家庭,我什至不会进入GetInformationAboutFamily阶段,但是如果我这样做了,那么我是首先瞄准父亲还是母亲还是兄弟姐妹(如果有)就没有关系了。但是,如果我还没有执行FamilyStatusCheck,那我就无法做到这一点,因此它属于早期阶段。
一切都很棒...
- 如果我需要一些其他操作,我只需要添加一个私有方法,
- 如果该操作在多个阶段都是通用的,那么我可以让它从超类继承,
- 操作简单且自成体系。任何其他操作都不需要从任何操作中获得任何价值(在不同阶段执行的操作),
- 线下的对象不需要执行许多测试,因为如果其创建者对象首先没有验证这些条件,它们甚至可能不存在。即,在将插入物放入仪表板,清洁仪表板并验证仪表板时,我不需要验证仪表板是否确实存在。
- 它便于测试。我可以轻松模拟部分对象并在其上运行任何方法,并且所有操作都是确定性的黑匣子。
...但...
当我在我的方法对象之一中添加最后一个操作时,就会出现问题,这导致整个模块超过了强制性的复杂性指标(“少于N个私有方法”)。
我已经在楼上解决了这个问题,并建议在这种情况下,私有方法的丰富并不是灾难的故事。复杂性是存在的,但它的存在,因为操作是复杂的,实际上它不是那么复杂-它只是长。
以邪恶的霸王为例,我的问题是邪恶的霸王(又名不容否认的他)要求了所有饮食信息,我的饮食奴才告诉我,我需要查询餐馆,小厨房,街头小贩,无牌街头小贩,温室所有者等,以及邪恶的(sub)Overlord(众所周知的也不应被拒绝的他)抱怨我在GetDietaryInformation阶段执行了太多查询。
注意:我知道从多个角度来看这根本不是问题(忽略可能的性能问题等)。发生的一切是,一个特定的指标不满意,对此有充分的理由。
什么我想我能做到
除了第一个以外,所有这些选择都是可行的,而且我认为是可以辩护的。
- 我已经证实自己可以偷偷摸摸,并声明一半的方法
protected
。但是我会利用测试程序中的弱点,除了在被抓住时证明自己是合理的之外,我也不喜欢这样。另外,这是权宜之计。如果所需操作次数加倍怎么办?不太可能,但是那又如何呢? - 我可以将此阶段任意拆分为AnnealedObjectAlpha,AnnealedObjectBravo和AnnealedObjectCharlie,并使每个阶段要执行的操作占三分之一。我的印象是,这实际上增加了复杂性(增加了 N-1个类),除了通过测试之外没有任何好处。我当然可以认为,CarWithFrontSeatsInstalled和CarWithAllSeatsInstall在逻辑上是连续的阶段。Alpha后来要求使用Bravo方法的风险很小,如果我打得很好的话,风险甚至会更低。但是还是。
- 我可以将一个远程相似的不同操作组合在一起。
performAllSeatsInstallation()
。这只是权宜之计,并且确实增加了单个操作的复杂性。如果我需要以不同的顺序执行操作A和B,并且将它们打包在E =(A + C)和F(B + D)内,则必须解开E和F并重新整理代码。 - 我可以使用lambda函数数组,并完全避开检查,但是我发现这很笨拙。但是,这是迄今为止最好的选择。它会摆脱反思。我遇到的两个问题是,可能会要求我重写所有方法对象,不仅是假设对象,
CarWithEngineInstalled
而且这虽然是很好的工作安全性,但实际上并没有那么大的吸引力。并且代码覆盖率检查器存在lambda 问题(可以解决,但仍然存在)。
所以...
- 您认为哪个是我最好的选择?
- 有没有我没有考虑过的更好的方法?(也许我最好打扫卫生,直接问一下是什么?)
- 这种设计是否存在绝望的缺陷,我最好承认失败与否-这种体系结构?这对我的职业生涯不利,但是从长远来看,编写错误的代码会更好吗?
- 我当前的选择是否真的是“唯一的方式”,我需要努力获得更好的质量指标(和/或仪器)?对于这最后一个选项,我需要参考...我不能只在抱怨的同时对@PHB挥手,这不是您要查找的指标。不管我想要多少