作者: 邢政
在移动APP的开发中,GUI的设计有时会遇到如下场景:
假设当前界面为A,内包含自定义控件B,通过点击B来弹出窗体C。实例创建的顺序是由A及B,再由B创建C。
由类图可以推出,构建C用到的parameter1InC和parameter2InC需要由B给出。
同理,在构建B时,需要A给出parameterInB。可以看到A为了构建B和C,包含了自身完全无用的3个参数。代码极其丑陋。
这就好比三顾茅庐第一次报名号的刘备,包含的参数有:汉左将军,宜城亭侯,领豫州牧,皇叔。
书童 直接告诉他,我记不得许多名字,你去重构下。
皇叔作为一个要招CTO的CEO,不得不展示了一下自己的代码功底,做了一层封装,将要传递的参数封装到AppContext中。再次调用书童的接口(可能同时还塞了一个红包)。
AppContext的代码大概长成这样,包含了构建B和C所用到的所有参数,差不多相当于皇叔的名片,包含了所有的头衔。
然后在构建B时,将整个AppContext丢进去。
在构建C时像这样:
放到我们的剧情里,是这样一副画面:
这样的好处在于不用将一长串的参数暴露给并不感兴趣的书童。
而是将信息封装在AppContext里,由最终感兴趣的对象自己去拿。
缺点也很明显,仅仅是将大量的参数做了一层包装,犹如开了美图的网红,卸了妆长啥样自己心里清楚……
再激进一点,我们可以将构建A,B,C实例的逻辑放倒工厂类里面。再将AppContext做成单例,由工厂类创建实例时自行获取需要的参数。
可以看到B的构造函数参数仅包含它关心的ParameterInB
CFactory根据Parameter1InC和Parameter2InC创建了C的实例
用过Factory之后,基本就相当于皇叔与书童相视一笑,书童默契叫醒午睡的诸葛先生,孔明掐指一算,就知道来的是谁,想干什么。
到这里有同学会问了,折腾了半天,代码没减少,还多出来三个工厂类,会不会有点累呢?
说实话写这个东西是挺累的,本篇我们到目前为止,都在说减少不必要的参数传递。
而我们最终的目的是通过抽象,来解决A,B,C三个类耦合过紧的问题。
依赖抽象,不要依赖具体,是什么意思呢?
假设存在一个抽象的“诸葛亮接口”,不同的“诸葛亮工厂”可以生产符合“诸葛亮接口”的各种诸葛亮。
那我们既可以生产唐国强那个诸葛亮,同时UnitTest工程的“Fake诸葛亮工厂”也可以生产下图这种符合接口的诸葛亮,然后搭建一个测试用例……
更进一步,是给工厂类也实现接口,业务类A,B,C不再依赖具体的Factory实现,仅包含对Factory接口的引用。将具体的依赖都放倒可以替换的Factory中。这样的话Factory就有点像是配置文件。
本篇的代码放在全球最大的同性交友平台Github上,欢迎查阅
https://github.com/manupstairs/FactoryTest
样例代码使用跨平台的Visual Studio Code + 跨平台的.NET Core编写,Mac上也能跑,考虑再写篇攻略安利你哟。