2019-耦合性斗争笔记

开始的工作

我是在2018.11.5开始维护和修改这个winform的ERP系统的。

我感觉代码很乱,因为代码里用了太多继承,窗体类之间相互的访问彼此的成员又很随意。

一句话来说就是耦合性高,封装性太低。

封装性的本质是,一个类自己管理自己的【数据】,和与之相关的【方法】。

其他类和对象,不能随意修改我的数据和方法。

你想要我的数据我给你,你想要我的方法,我来执行。

如果我不知道怎么回事,你就改变了我,那我就会很懵的。

下面列举一些封装性低的地方。

溺爱孩子的父辈

过度的使用继承机制会破坏子类的封装性,应该使用接口来代替继承,这是这个时代的我被教导的金科玉律。

使用继承机制,可能一开始写的时候是省事了,但是后期改起来却更加麻烦了。

因为对于后期一个改代码的人来说,他只关心他新加入的类,或者一个类中他改的那部分是最好的;如果他以前没有接触过这个项目还要瞻前顾后的翻父类子类,去翻和它有数据交互的类;那么他的工作就很麻烦。

这段代码的主要作用就是赋值,将drStore中的一些字段的值赋给drItem中的一些字段。

明明是个简单的赋值,为什么要有这么多strTag == "xxx"的判断呢?

原来strTag是一个和窗体名相同的字段。

而这些窗体呢,都继承自同一个【父窗体】。

这段赋值代码就是在父窗体内的,因为每个表单上都有一个选择物料/产品的按钮,这是一个共性。

于是这个作者就这样写了,在父类中逐个判断子类的类型,然后根据类型不同,逐个赋值。

  • 有点搞笑

这样写我觉得是有些搞笑的,举个现实的例子就是:

我问小明,你吃饭了吗?

小明说,我不知道,你去问问我爸爸吧。

然后我问明爸,小明吃饭了吗?

然后,明爸不慌不忙的说:大明吃了,二明吃了,小明没吃。

what?明爸你糊涂了吧?我没问大明二明呀? 

然后是小明,你好不成器啊,自己吃了没吃都不知道,还要你爸来管。

  • 应该怎样?

就算是非要用继承去写,遇到不一样的地方应该override呀。 

热情的朋友

如果A类需要调用B的方法,那么我就可以说A类依赖于B类。

一般来说,我应该,小心的抽离出关键的参数,让A类把这几个参数给到B类,拿到我的结果,继续向下走我的方法。

然而我看到,原来的作者是这样写的:

A类调用了B类的一个方法,这个方法的一个参数就是A类的实例本身。

假设A类的实例是a,B类的实例是b。

然后b怎么处理的呢?首先它做了自己的事情,帮助a拿到了一些它想要的数据。

接着,b很主动的帮助a给它的公开字段赋值了! 

-------------------------------------------------------------------------------------------------------------------------

这样做的坏处在调试的时候最容易看出来,如果b只提供方法的话,那我a用了b的方法拿到返回值后,就继续往下走了。

这样我调试的时候就可以F10跳过方法的具体实现,直接拿到返回值看下面的代码怎么走的了。

但是b你帮我a赋值的话,我还要再去b里看看你到底是怎么做的。

可读性太差。 

当时修改的方向

1是界面干净。---------------------------因为界面干净,用户看着用着就舒服。

2是每个类的对外接口干净。--------因为这样别人或我自己再去使用这个类的时候很会很容易。

因为到处都感觉有问题,但是到处都改的话工作量很大,所以,最后想到优先保证两个干净。

后来想了一些办法

为了对抗耦合性,后来想了一些办法。

1.是写了一个大大的静态帮助类XHelper。

因为一个可以随便剪切粘贴的纯函数,是封装性良好的最小模块。

这个帮助类的功能包括很多方面:

  • 文件操作。数据库,ini,Excel,导入导出等等。
  • 控件操作。GridView有关的,TreeList有关的。
  • 增删改查有关。增删改查的帮助方法,数据绑定方法,输入校验方法,自动编号方法,下拉框填数据方法,弹出式选框填数据的方法,对后端对象操作的方法。
  • 辅助功能。日志,权限,调试用方法,加密,解密,压缩,解压等等。

2.是写了一些代码生成工具。

有些代码虽然是重复的,但是并不适合封装起来,用继承的话就更乱了,因为本身它们有各自的特点,需要在细节处小修小改。

所以用代码生成工具生成这些代码是最正确的选择。

耦合性的意义

耦合的代码看多了,我想了太多的消灭耦合的办法后,我也想了下耦合性存在的意义。

没有耦合性,系统是无法工作的。就像显示器如果没有插电的接口,就没电不会亮;没有连接主机的接口,就没有显示的内容。

主机,显示器,电源需要相互联系,才能组成系统,才能正常工作。

所谓的耦合,换个褒义词,就是联系嘛。

继承机制对于封装控件来说很完美,确实控件的属性和方法在一起用起来很舒服。

再后来有些看开了

1.是因为一开始大量的改动引起了程序的不稳定。

改同样一个问题,我最简单的办法是按照原来的编码风格去写。

原作者用了耦合性高的写法,我强制改成单一职责的,中间改动量是非常大的,就需要很多测试才能知道对原来的功能有没有影响。

因为原来的代码可能用在很多地方,你的改法满足了这个地方,可能另一个地方会出问题。

所以改动的【成本最低选择】是,照着原来的风格改。

2.是因为我觉得我头脑里的这些观念是时代的产物。

我感觉编码这一工作的发展趋势是越来越工业化,越来越分工明确的。

如果说之前写程序的人员都很稳定,可能用很多继承去写是合适的。

我自己写的,明天也是自己改,我知道父类什么样,我也知道功能有冗余的类是什么样的,我继续用这些东西我还觉得很简单。

而现在可能变成了流水的兵去作业,我们肯定希望新来的人不需要了解太多历史就能工作,希望整个框架是简明的,没有那么多隐含条件,我就会把工作分的很细。

3.我自己发现我自己的代码也是越写越乱的。

我写了一个类A,一开始他只需要给类B提供数据,于是我在类A里写了一个方法FuncForB。

后来呢?我发现类A还要给类C提供数据,我就在类A里写了另外一个方法FuncForC。

然后呢?我发现FuncForC对B也能适用,FuncForC的写法貌似更原子性,能够满足各种数据获取的需求。

所以呢?去掉FuncForB,然后改一下类B。

我写前面的时候真的很难知道,我写的东西对后面通用不通用。 

所以要写出整洁的代码,是需要一些重构,需要一些经验的。

就像是你可能把常用的东西放桌上,放着放着就乱了,需要整理才能干净。

现在的观点

因为本身我对整洁有些强迫症,才会有去整理的想法。

作为工作来说,要不要做这件事,要多考虑的是有没有用。

代码整洁最大的用处是:日后好改。

从“功用”角度看,最重要的就是:把用户经常想要修改的地方抽象出来,他要改,我马上可以改掉。

然后是,大部分时候能很快的实现一些基本功能。

代码有一万种写法,还是从业务需求去考虑它,才能捋清楚。

原文地址:https://www.cnblogs.com/fabao/p/10925043.html