解耦

事情起源于昨天的一次讨论。模块A如何在不同的时期返回不一样的数据类型的值,供其他不同的模块使用。

我自行脑补了一下,其实这类问题可以归结为对数据类型的解耦。

考虑一种特殊情况,有moduleA,moduleB,moduleC1,moduleC2等四个模块。moduleA在不同的时期产出不同的数据供moduleC1和moduleC2处理。moduleB用于将moduleA产出的数据根据具体情况情况分别调用moduleCx来处理。moduleCx的接口类似moduleC1::doSomething(type1 data);moduleC2::doSomething(type2 data); 

最low的解法莫过于在moduleB中分别定义type1,type2的变量接收一下,然后根据具体情况分别传入相应的moduleCx模块中。然而这样的写法根本不符合open-close原则。moduleCx从属性上来讲应该属于同一种东西的不同变种,以后会有很大的可能增加moduleC3(type3);moduleC4(type4)等模块。几乎每增加一种模块,moduleB都需要相应作出修改。

这样,moduleCx已经与moduleB深深的耦合在一起了。

为了解决这个问题。按照面向对象的做法,应该抽象一个纯虚类定义接口I,moduleCx分别实现接口I。这样moduleB只需要持有接口I的引用,仅仅把数据传入接口I即可。不论增加多少moduleC,对moduleB的修改总是close的。

然而这里存在一个非常大的问题。moduleCx的每个处理接口的数据类型不同,这是对抽象出接口I的最大障碍。只有将接口的数据类型与moduleCx进行解耦,才可以顺利抽象出接口I。

对于c语言来讲,比较粗暴的做法是使用void *,对于c++的做法最常用的做法是对数据类型抽象出一个基类P,所有接口的type均继承自基类P,moduleA的返回及moduleCx的接口类型均使用基类P。到了moduleCx内定后再自行转为实际使用的数据类型。

每一种语言都有相应的思维层次。

站在c语言层面,我眼中是内存和cpu因此我觉得把其他类型转为void *,在moduleCx中再转为相应的类型并没有什么不妥。因为在我眼中不过都是同一块内存罢了。

然而站在c++(面向对象)的层次,我眼中尽是对象。每个moduleC接口的参数type之间并无共同之处,为了使用语法糖而是用继承,总是感觉心里有些许别扭。

于是我想了另外一种独立于语言的做法。

可以定义类typeX,typeX就像是c中的union一样,可以包含type1,type2 … 等moduleCx的所有类型的数据。接口I和moduleB与moduleA的返回值均使用typeX。在moduleCx中通过typeX变量获取自己需要的数据即可。

如何实现typeX使得编码更方便,则需要具体情况具体分析了。

发表评论

26 − = twenty three