具有臭味的代码 领域模型设计模式EclipseSwingMVC
程序员文章站
2022-07-05 09:56:16
...
下面介绍几种具有坏味道的代码结构,其中很多经验学习自Eclipse,与Martin Fowler不同的是,我找到的几种坏味道都存在于设计理念之中,而不是缺乏设计模式的抽象,也不是未重构的代码。先别急着反驳,也别急着嗤之以鼻,先想想这些设计理念的优点,看看是不是微不足道,再看看这些理念的缺点,是不是有可能铸成大错,作者还给出了去掉这些坏味道的某个思路,即作者自己的思路,仅供参考。最后,别忘了想想自己手中的软件的设计,看看会不会遇到其中的熟面孔啊。。。。。
1。味道:控件耦合。
“如果第一个复选框被选中,那么下面的文本域全部失效。”通过这种方式表述的效果在软件开发中经常遇到,很多人称之为“界面逻辑”,想想看,界面逻辑真的可以直接变成代码吗?
典型重构思路:有限状态机。
状态与控件属性集一一对应,控件属性被改变时,状态机收到事件,检查状态是否发生了迁移,如果是则向控件属性集的控制器发出状态迁移事件,控制器批量改变控件状态。
2。味道:控件/绘制器存在状态。
有人认为Motif和Windows已经差别很大了,有没有想过它们和IBM收银机上的字符界面差别有多大呢?既然差别这么大的绘制器仍然存在相同的复杂了(有时是很复杂的)状态,那我们为什么不把它们extract出来而要让它们冗余呢?
典型重构思路:视图的模型。
视图有视图的模型,并不是MVC中的模型,这种方式就是Swing的基础。
3。味道:视图发出有意义的事件。
什么?你的意思是视图应该发出无意义的事件咯?不是这样吗?视图应该不了解任何业务逻辑,也不应该了解任何界面逻辑,如果界面逻辑真的存在的话。
典型重构思路:事件翻译器。
视图发出无意义的事件,比如鼠标事件,键盘事件,或某个控件的事件,事件翻译器把低级事件翻译为高级事件,再把高级事件包装成请求,请求被传递给一个根控制器。
4。味道:动作/命令知道自己的形象。
很多时候,一个Action或者一个Command都知道自己叫什么名字,能不能被禁用,有没有被禁用,图标如何,甚至还知道及时帮助的字符串,执行需要什么条件,返回什么结果等等,如果这么做的话Action和Command就有了自己的视图状态,发出了第2种味道。
典型重构思路:动作代理。
重磅的工作交给代理完成,动作/命令只是一个视图的模型罢了。在UI系统装载之初,动作/命令被装载并绘制在界面上,直到用户点击或触发了这个动作/命令,它的代理才被调入并开始工作。
5。味道:模型知道自己的每一个用处。
有n种视图对应同一个模型,比如对一个网页制作工具来说,一个html文件至少有三种视图:代码、设计、预览。如果模型同时能满足这三种视图的需求的话,这个模型就太重磅了,而且还不好添加一种新视图。比如Dreamwaver的代码/设计页面。
典型重构思路1:一个模型,多个维度。
如果一个模型拥有n个维度,则n个对象,就可以确定一个事实,n-1个对象就可以得到一个线性聚集,n-2个对象就可以得到一个二维表。每个维度就是一组Interface,而事实的类型,其实是不可见的,(内部的巨大类型),只能通过维度确定事实,再提取事实的属性。
典型重构思路2:适配器模式。
模型首先实现最必要的接口,然后当需要模型实现某个非必要接口时,模型会主动或被动的适配为一个满足需求接口的“意外”对象。
6。味道:控制器变成顾问类。
有些人认为我们的社会需要复合型的人才,因为每个人都要具备管理的能力,控制器也要懂管理,它要负责视图和模型之间的交互。但是仔细想想,如果被模型以外的对象知道了业务逻辑的话,那模型还可以替换吗?
典型重构思路:控制器标准化。
控制器将请求包装为命令,并将命令交给命令堆栈执行。控制器并不了解模型,模型只能由模型自己了解,控制器也不知道领域逻辑,它只是做一些机械的翻译工作,并利用视图和模型提供的(互补相关)的素材,创建和模型相关的命令。
7。味道:模型变成无所不知博士。
在没有发生上面六种情况的时候,千万不要大意啊,你很有可能发生了这一种情况,恰恰是因为控制器和视图都不知道业务逻辑,模型才有可能发展为Dr.Know。但是视图往往是树状结构的啊,它怎么和Dr.Know合作呢?通过代理?还是Facade?
典型重构思路:复杂模型结构(树状、图状、知识/操作分离)。
如果有可能,模型也是树状的,可以和视图一一对应;如果这一点做不到,不要紧,可以把大模型划分成轻量小板块,或者迭代子,再用关系对象解释它们之间的关系;如果还不行,那总得做到知识和操作分离吧。。。。。。。
1。味道:控件耦合。
“如果第一个复选框被选中,那么下面的文本域全部失效。”通过这种方式表述的效果在软件开发中经常遇到,很多人称之为“界面逻辑”,想想看,界面逻辑真的可以直接变成代码吗?
典型重构思路:有限状态机。
状态与控件属性集一一对应,控件属性被改变时,状态机收到事件,检查状态是否发生了迁移,如果是则向控件属性集的控制器发出状态迁移事件,控制器批量改变控件状态。
2。味道:控件/绘制器存在状态。
有人认为Motif和Windows已经差别很大了,有没有想过它们和IBM收银机上的字符界面差别有多大呢?既然差别这么大的绘制器仍然存在相同的复杂了(有时是很复杂的)状态,那我们为什么不把它们extract出来而要让它们冗余呢?
典型重构思路:视图的模型。
视图有视图的模型,并不是MVC中的模型,这种方式就是Swing的基础。
3。味道:视图发出有意义的事件。
什么?你的意思是视图应该发出无意义的事件咯?不是这样吗?视图应该不了解任何业务逻辑,也不应该了解任何界面逻辑,如果界面逻辑真的存在的话。
典型重构思路:事件翻译器。
视图发出无意义的事件,比如鼠标事件,键盘事件,或某个控件的事件,事件翻译器把低级事件翻译为高级事件,再把高级事件包装成请求,请求被传递给一个根控制器。
4。味道:动作/命令知道自己的形象。
很多时候,一个Action或者一个Command都知道自己叫什么名字,能不能被禁用,有没有被禁用,图标如何,甚至还知道及时帮助的字符串,执行需要什么条件,返回什么结果等等,如果这么做的话Action和Command就有了自己的视图状态,发出了第2种味道。
典型重构思路:动作代理。
重磅的工作交给代理完成,动作/命令只是一个视图的模型罢了。在UI系统装载之初,动作/命令被装载并绘制在界面上,直到用户点击或触发了这个动作/命令,它的代理才被调入并开始工作。
5。味道:模型知道自己的每一个用处。
有n种视图对应同一个模型,比如对一个网页制作工具来说,一个html文件至少有三种视图:代码、设计、预览。如果模型同时能满足这三种视图的需求的话,这个模型就太重磅了,而且还不好添加一种新视图。比如Dreamwaver的代码/设计页面。
典型重构思路1:一个模型,多个维度。
如果一个模型拥有n个维度,则n个对象,就可以确定一个事实,n-1个对象就可以得到一个线性聚集,n-2个对象就可以得到一个二维表。每个维度就是一组Interface,而事实的类型,其实是不可见的,(内部的巨大类型),只能通过维度确定事实,再提取事实的属性。
典型重构思路2:适配器模式。
模型首先实现最必要的接口,然后当需要模型实现某个非必要接口时,模型会主动或被动的适配为一个满足需求接口的“意外”对象。
6。味道:控制器变成顾问类。
有些人认为我们的社会需要复合型的人才,因为每个人都要具备管理的能力,控制器也要懂管理,它要负责视图和模型之间的交互。但是仔细想想,如果被模型以外的对象知道了业务逻辑的话,那模型还可以替换吗?
典型重构思路:控制器标准化。
控制器将请求包装为命令,并将命令交给命令堆栈执行。控制器并不了解模型,模型只能由模型自己了解,控制器也不知道领域逻辑,它只是做一些机械的翻译工作,并利用视图和模型提供的(互补相关)的素材,创建和模型相关的命令。
7。味道:模型变成无所不知博士。
在没有发生上面六种情况的时候,千万不要大意啊,你很有可能发生了这一种情况,恰恰是因为控制器和视图都不知道业务逻辑,模型才有可能发展为Dr.Know。但是视图往往是树状结构的啊,它怎么和Dr.Know合作呢?通过代理?还是Facade?
典型重构思路:复杂模型结构(树状、图状、知识/操作分离)。
如果有可能,模型也是树状的,可以和视图一一对应;如果这一点做不到,不要紧,可以把大模型划分成轻量小板块,或者迭代子,再用关系对象解释它们之间的关系;如果还不行,那总得做到知识和操作分离吧。。。。。。。
上一篇: 搜索引擎中网络爬虫的设计分析
下一篇: Oracle时间问题