组合对象的设计模式
我有一个很复杂的函数,想要对它进行重构。简单来说,这个函数接收两个对象,访问这两个对象的多个属性和方法,然后把它们结合起来,最后用这些结合的结果来创建一个新的结果对象。
它的样子是这样的:
def ugly(obj_a, obj_b):
a_1 = obj_a.a_1
sub_a_1 = obj_a.get_sub()
r_1 = obj_b.combine(a_1)
if r_1 < 0:
raise ValueError
if not sub_a_1.validate():
raise Exception
return ResultObj(a_1, r_1, sub_a_1.get_matrix(), obj_b.some_other_attribute)
不过实际上,这两个对象上访问的属性和方法非常多,而且传给结果对象的构造值也很多。
这个函数在单元测试和集成测试时简直是一场噩梦。现在的情况是,我得模拟 obj_a 和 obj_b 以及它们所有的方法和属性。
你有什么建议可以用来重构这种代码吗?理想情况下,我不想改变 obj_a 和 obj_b 的实现。
这是用 Python 写的,所以面向对象和函数式的设计都可以用。
谢谢!
1 个回答
1
让这种过程性代码更容易测试的一种方法是添加“缝隙”,也就是说把代码分成可以单独运行的部分。因为没有实际的代码,逻辑上的缝隙很难看出来,所以很难抽象地回答你的问题。
你可以返回一个参数列表来创建一个结果对象,而不是直接创建一个。这让你可以测试处理过程,而不需要同时测试结果对象。而且,之后用 ResultObj(*args)
来创建结果对象也很简单。不过,这样你还是要处理很多值。
你也可以考虑写几个独立的函数,分别从A和B获取并验证数据,然后返回简单的“扁平”数据结构(比如命名元组),再由第三个函数将它们组合起来。
除此之外,重构类本身对我来说是最有意义的,尽管你说你想避免这样做。如果创建A和B对象没有副作用或者依赖关系不太多,那就更好了,但这还是要看你具体的代码情况。
另外要考虑的是,“把两个对象合并成一个超级对象”本质上更像是一个集成测试案例,而不是单元测试案例。