我非常务实,但是我主要关心的是您可能允许它ConfigBlock
以可能不好的方式支配您的界面设计。当你有这样的事情:
explicit MyGreatClass(const ConfigBlock& config);
...更合适的界面可能是这样的:
MyGreatClass(int foo, float bar, const string& baz);
...而不是仅仅foo/bar/baz
从大量的樱桃中挑选这些领域ConfigBlock
。
惰性接口设计
从好的方面来说,这种设计使为构造函数设计一个稳定的接口变得容易,例如,因为如果最终需要一些新的东西,则可以将其加载到ConfigBlock
(可能无需任何代码更改)中,然后进行cherry-选择所需的任何新内容,而无需进行任何类型的界面更改,只需更改的实现即可MyGreatClass
。
因此,从优点和缺点上来说,这使您不必设计更仔细考虑的界面,仅接受实际需要的输入。它采用的思路是:“只要给我这么大量的数据,我就会从中挑出我需要的东西”,而不是诸如“这些精确的参数就是该接口需要工作的东西”之类的东西。
因此,这里肯定有一些优点,但是缺点可能会大大超过它们。
耦合
在这种情况下,从ConfigBlock
实例构造的所有此类类最终都具有其依赖关系,如下所示:
例如,如果要Class2
在此图中单独进行单元测试,则可以成为PITA 。您可能必须表面上模拟ConfigBlock
包含Class2
感兴趣字段的各种输入,以便能够在各种条件下对其进行测试。
在任何类型的新环境中(无论是单元测试还是整个新项目),任何此类类最终都将成为(重用)更多的负担,因为我们最终不得不总是随身携带ConfigBlock
并进行设置相应地。
可重用性/可部署性/可测试性
相反,如果您适当地设计这些接口,我们可以将它们从中解耦,ConfigBlock
并得到如下所示的结果:
如果您在上面的图表中注意到,所有类别将变为独立的(它们的传入/传出耦合减少1)。
这导致了更多的独立类(至少独立于ConfigBlock
),在新的场景/项目中可以更轻松地(重用)/测试这些类。
现在,此Client
代码最终成为了必须依赖于所有内容并将其组装在一起的代码。负担最终被转移到此客户端代码,以从a读取适当的字段ConfigBlock
并将它们作为参数传递到适当的类中。然而,此类客户端代码通常是针对特定上下文进行狭义设计的,并且无论如何,其重用潜力通常都会变得零落或关闭(它可能是应用程序的main
入口点功能或类似功能)。
因此,从可重用性和测试的角度来看,它可以帮助使这些类更加独立。从使用类的人员的界面角度来看,它还可以帮助明确地声明所需的参数,而不是仅一个庞大的参数即可ConfigBlock
建模所有内容所需的整个数据字段。
结论
通常,这种基于类的设计依赖于具有所需要的一切的整体,因此倾向于具有这些特性。结果,它们的适用性,可部署性,可重用性,可测试性等可能会大大降低。但是,如果我们尝试对其进行积极调整,它们可以简化界面设计。由您来衡量这些利弊,并决定权衡是否值得。通常,对此类设计犯错误的做法要安全得多,在这种设计中,您从整体中挑选樱桃,通常是为了对更通用和更广泛应用的模型建模。
最后但并非最不重要的:
extern CodingBlock MyCodingBlock;
...就上述特性而言,这比依赖注入方法可能更糟(更偏斜?),因为它最终不仅将您的类耦合到ConfigBlocks
,而且还直接耦合到它的特定实例。这进一步降低了适用性/可部署性/可测试性。
我的一般建议是在设计不依赖于此类整体的接口以提供其参数方面,至少对于您设计的最普遍适用的类,这是错误的。如果可以的话,请避免使用没有依赖项注入的全局方法,除非您确实有很强的自信理由不这样做。