只是工作中对遇到的问题的思考,本人小白一个,欢迎大家指正错误。
整个界面上只有算法参数配置界面是更改最多的,不同的算法类型需要不同的配置参数(也有重叠的部分,但是整体上依旧是有差别)。曾经的做法是一个算法对应一个配置界面,多一个算法规则就会多一个配置界面,就会多一个界面类,那就会多增加三个文件(.cpp .h .ui)。前期这种做法确实很高效,但是随着时间的流失,现在算法规则已经增加到了30个左右,问题也愈加的凸显出来。
-
每增加一个算法规则,那么配置参数界面就要新增一个,而这30多个算法配置界面的运行逻辑和代码结构几乎相同,有时配置界面的控件都是90%相同的,所以开发一个算法配置界面基本就是找一个旧的算法配置界面copy一下然后再改改,十分枯燥。
-
30多个算法配置界面就基本相当于一个算配置界面的30个分身,由于运行逻辑相同,所以改一个算法配置文件(比如界面控件的效果、源文件中逻辑判断),那么其他配置都要手动修改,以保证界面使用效果相同,想想就恐怖
现在要认真的想想这个问题了,这么一团臃肿的东西,怎么能修改的苗条一些。问题的重点在于,不同的算法规则要对应不同的算法配置界面类(.cpp .h .ui),算法配置界面类不能一直增加,否则就控制不住,无论显示什么控件,都在这一个类里完成,就像一个电视可以播放多个频道一样。原有的算法配置界面都拆开成一个个的基础控件,这些控件就像"字母“一样,组装成不同的"单词"(算法配置界面),基础控件不会无限制的增加,有十几个常用的就够了。修改一个基础控件类,那么所有用到这个控件的地方就都改了,大大提高了修改速度,减少了修改范围。那么算法配置界面类只需要做以下几件事。
- 搭建好界面布局
- 确定要展示的算法界面以及要使用的控件
- 向界面布局中填入控件完成展示。
现在来看看算法配置界面类,这里用A来表示类对象,A对象在被调用时需要知道显示哪个算法规则的界面,常规思路就是if else,那么外界传来一个枚举值M(表示展示哪个算法界面),A的内部就需要去用if else来判断,M=1就是展示算法规则1的界面,M=2就是展示算法规则2的界面,这个if else中对应的就是上面所述的第二步和第三步。如下,
if(M==1){
创建算法规则1需要的控件;
将控件摆放到对应的布局中; //不同的算法规则界面中同一个控件的摆放位置可能不同,所以第三步也放到里面
}else if(M==2){
创建算法规则1需要的控件;
将控件摆放到对应的布局中;
}else if{
//...
}
从上面伪代码中,还是能感觉到臃肿,比如一个界面需要5个控件组成,那么30个if就要写150个控件的创建,更可气的是有两个if中控件用的都相同,但是就是位置不同,但是大家都会这么想,都用if else写了,多写一个也无所谓了,很快这个if else又会变得无法控制。而且if中创建的控件都要以成员变量(大部分情况是指针)的形式存在A类中,每个控件指针变量的个数是多少这也不确定,那这样每个控件指针是不是要存储到对应的vector中,需要多少就放多少个,想想就觉得不对劲。
如果A类是具象类,那么可能就得像上面的写法,所有需要的元素都得在类中存放,所以转变思想将A类转变抽象类变成抽象算法配置界面类,算法1配置界面、算法2配置界面都继承A类,很明显这种创建具体类的方法有点像工厂模式。现在需要创建的有控件和具体的算法配置界面,控件是在配置界面中创建的,所以不用考虑控件,配置界面类像产品类,只有这一种产品,所以用简单工厂就足够了。这样每个具体配置界面类中只需要创建自己需要的控件并填充界面布局即可,而且控件指针变量的个数也是可控的。而客户只需要向简单工厂中传入枚举值即可,那么简单工厂内部逻辑如下
if(M == 1){
创建算法1配置界面类对象
}else if(M == 2){
创建算法2配置界面类对象
}
又是熟悉的if else,不过还算有进步,每个if中只是创建一个算法配置界面对象并向外返回这个对象。其实这里也可以在简单工厂中将所有的具体类对象都创建出来存到map<枚举值,配置界面对象指针>里面,外界用哪个就返回哪个。继续想,如果客户调用前已经传递参数说我只用1-10配置界面中的2,5,7,那么将所有的配置界面对象创建出来会造成空间的浪费,不想浪费那就还得在简单工厂中使用if else创建,这其实还是把业务代码(我认为if else这一块是和业务相关的)带进来了。如果要把if else部分完全从工厂部分的代码中剔除,可以采用工厂+策略模式,虽然开始写觉得框架里面的东西很少,但是扩展性很好,后期只需要增加具体的配置界面类以及对应的具体的工厂就行了。