`
xiao_yi
  • 浏览: 407711 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

从 if else 到设计模式的转变

阅读更多
面向过程设计和面向对象设计的主要区别是:是否在业务逻辑层使用冗长的if else判断。如果你还在大量使用if else,当然,界面表现层除外,即使你使用Java/C#这样完全面向对象的语言,也只能说明你的思维停留在传统的面向过程语言上。
传统思维习惯分析

  为什么会业务逻辑层使用if else,其实使用者的目的也是为了重用,但是这是面向过程编程的重用,程序员只看到代码重用,因为他看到if else几种情况下大部分代码都是重复的,只有个别不同,因此使用if else可以避免重复代码,并且认为这是模板Template模式。

  他范的错误是:程序员只从代码运行顺序这个方向来看待它的代码,这种思维类似水管或串行电路,水沿着水管流动(代码运行次序),当遇到几个分管(子管),就分到这几个分管子在流动,这里就相当于碰到代码的if else处了。

  而使用OO,则首先打破这个代码由上向下顺序等同于运行时的先后循序这个规律,代码结构不由执行循序决定,由什么决定呢?由OO设计;设计模式会取代这些if else,但是最后总是由一个Service等总类按照运行顺序组装这些OO模块,只有一处,这处可包含事务,一般就是Service,EJB中是Session bean。

  一旦需求变化,我们更多的可能是Service中各个OO模块,甚至是只改动Service中的OO模块执行顺序就能符合需求。

  这里我们也看到OO分离的思路,将以前过程语言的一个Main函数彻底分解,将运行顺序与代码其他逻辑分离开来,而不是象面向过程那样混乱在一起。所以有人感慨,OO也是要顺序的,这是肯定的,关键是运行顺序要单独分离出来。

  是否有if else可以看出你有没有将运行顺序分离到家。

设计模式的切入口

  经常有人反映,设计模式是不错,但是我很难用到,其实如果你使用if else来写代码时(除显示控制以外),就是在写业务逻辑,只不过使用简单的判断语句来作为现实情况的替代者。

   还是以大家熟悉的论坛帖子为例子,如ForumMessage是一个模型,但是实际中帖子分两种性质:主题贴(第一个根贴)和回帖(回以前帖子的帖子),这里有一个朴素的解决方案:
建立一个ForumMessage,然后在ForumMessage加入isTopic这样判断语句,注意,你这里一个简单属性的判断引入,可能导致你的程序其他地方到处存在if else 的判断。

  如果我们改用另外一种分析实现思路,以对象化概念看待,实际中有主题贴和回帖,就是两种对象,但是这两种对象大部分是一致的,因此,我将ForumMessage设为表达主题贴;然后创建一个继承ForumMessage的子类ForumMessageReply作为回帖,这样,我在程序地方,如Service中,我已经确定这个Model是回帖了,我就直接下溯为ForumMessageReply即可,这个有点类似向Collection放入对象和取出时的强制类型转换。通过这个手段我消灭了以后程序中if else的判断语句出现可能。

  从这里体现了,如果分析方向错误,也会导致误用模式。

  讨论设计模式举例,不能没有业务上下文场景的案例,否则无法决定是否该用模式,下面举两个对比的例子:

  第一. 这个帖子中举例的第一个代码案例是没有上下文的,文中只说明有一段代码:

main() {
if(case A){

//do with strategy A

}else(case B){

//do with strategy B

}else(case C){

//do with strategy C

}

}

第二.在这个帖子中,作者举了一个PacketParser业务案例,这段代码是体现业务功能的,是一个数据包的分析,作者也比较了各种模式使用的不同,所以我们还是使用动态代理模式或Command模式来消灭那些可能存在的if else

  由以上两个案例表明:业务逻辑是我们使用设计模式的切入点,而在分解业务逻辑时,我们习惯则可能使用if else来实现,当你有这种企图或者已经实现代码了,那么就应该考虑是否需要重构Refactoring了。


if else替代者

  那么实战中,哪些设计模式可以替代if else呢?其实GoF设计模式都可以用来替代if else,我们分别描述如下:

状态模式 
  当数据对象存在各种可能性的状态,而且这种状态将会影响到不同业务结果时,那么我们就应该考虑是否使用状态模式,当然,使用状态模式之前,你必须首先有内存状态这个概念,而不是数据库概念,因为在传统的面向过程的/面向数据库的系统中,你很难发现状态的,从数据库中读取某个值,然后根据这个值进行代码运行分流,这是很多初学者常干的事情。参考文章:状态对象:数据库的替代者
  使用传统语言思维的情况还有:使用一个类整数变量标识状态:



public class Order{

private int status;

//说明:

//status=1 表示订货但为查看 ;

//status=2 表示已经查看未处理;

//status=3 表示已经处理未付款

//status=4 表示已经付款未发货

//status=5 表示已经发货

}


  上述类设计,无疑是将类作为传统语言的函数来使用,这样导致程序代码中存在大量的if else。


策略模式 
  当你面临几种算法或者公式选择时,可以考虑策略模式,传统过程语言情况是:从数据库中读取算法数值,数值1表示策略1,例如保存到数据库;数值为2表示策略2,例如保存到XMl文件中。这里使用if else作为策略选择的开关。


command模式 
  传统过程的思维情况是:如果客户端发出代号是1或"A",那么我调用A.java这个对象来处理;如果代号是2或"B",我就调用B.java来处理,通过if else来判断客户端发送过来的代码,然后按事先约定的对应表,调用相应的类来处理。


MVC模式 
  MVC模式的传统语言误用和Command模式类似,在一个Action类中,使用if else进行前后台调度,如果客户端传送什么命令;我就调用后台什么结果;如果后台处理什么结构,再决定推什么页面,不过,现在我们使用Struts/JSF这样MVC模式的框架实现者就不必范这种低级错误。


职责链模式 
  职责链模式和Command模式是可选的,如果你实在不知道客户端会发出什么代号;也没有一个事先定义好的对照表,那么你只能编写一个个类去碰运气一样打开这个包看一下就可以。与Command是不同在AOP vs Decorator一文中有分析。


代理或动态代理模式 
  代理对象可以是符合某种条件的代表者,比如,权限检验,传统面向过程思维是:当一个用户登陆后,访问某资源时,使用if else进行判断,只有某种条件符合时,才能允许访问,这样权限判断和业务数据逻辑混乱在一起,使用代理模式可以清晰分离,如果嫌不太好,使用动态代理,或者下面AOP等方式。


AOP或Decorator模式
  
  其实使用filter过滤器也可以替代我们业务中的if else,过滤器起到一种过滤和筛选作用,将符合本过滤器条件的对象拦截下来做某件事情,这就是一个过滤器的功能,多个过滤器组合在一起实际就是if else的组合。
  所以,如果你实在想不出什么办法,可以使用过滤器,将过滤器看成防火墙就比较好理解,当客户端有一个请求时,经过不同性质的防火墙,这个防火墙是拦截端口的;那个防火墙是安全检查拦截等等。过滤器也如同红蓝白各种光滤镜;红色滤镜只能将通过光线中的红色拦截了;蓝色滤镜将光线中的蓝色拦截下来,这实际上是对光线使用if else进行分解。


  如图,通过一个个条件过滤器我们立体地实现了对信号的分离,如果你使用if else,说明你是将图中的条件1/2/3/4合并在一起,在同一个地方实现条件判断。
  需要深入了解过滤器的实现细节和微小区别,请参考文章:AOP vs Decorator
OO设计的总结  

  还有一种伪模式,虽然使用了状态等模式,但是在模式内部实质还是使用if else或switch进行状态切换或重要条件判断,那么无疑说明还需要进一步努力。更重要的是,不能以模式自居,而且出书示人。

  真正掌握面向对象这些思想是一件困难的事情,目前有各种属于揪着自己头发向上拔的解说,都是误人子弟的,所以我觉得初学者读Thinking in Java(Java编程思想)是没有用,它试图从语言层次来讲OO编程思想,非常失败,作为语言参考书可以,但是作为Java体现的OO思想的学习资料,就错了。

  OO编程思想是一种方法论,方法论如果没有应用比较,是无法体会这个方法论的特点的,禅是古代一个方法论,悟禅是靠挑水砍柴这些应用才能体会。

  那么OO思想靠什么应用能够体会到了?是GoF设计模式,GoF设计模式是等于软件人员的挑水砍柴等基本活,所以,如果一个程序员连基本活都不会,他何以自居OO程序员?从事OO专业设计编程这个工作,如果不掌握设计模式基本功,就象一个做和尚的人不愿意挑水砍柴,他何以立足这个行业?早就被师傅赶下山。

  最后总结:将if else用在小地方还可以,如简单的数值判断;但是如果按照你的传统习惯思维,在实现业务功能时也使用if else,那么说明你的思维可能需要重塑,你的编程经验越丰富,传统过程思维模式就容易根深蒂固,想靠自己改变很困难;建议接受专业头脑风暴培训。

  用一句话总结:如果你做了不少系统,很久没有使用if else了,那么说明你可能真正进入OO设计的境地了。(这是本人自己发明的实战性的衡量考核标准)。

分享到:
评论
18 楼 wuhua 2008-03-06  
抛出异常的爱 写道
wuhua 写道
OO与非OO得区别很多。
作者只是谈到了一点。
我个人感觉是,面向过程很符合人们的常规思维
而面向对象了反而是扭曲了这种思维。

人们很自然的想到做完了这件事情,应该做下面的事情。
而不会想到应该通过代理啊,委托啊来处理这些事情,除非是非常规思维的人。
比如那些大师啊,头脑转的特别快的人。


如果你喜欢看过程性的代码
只能说明。。。
你的大脑与普通人的不一样

PS:很烂的OO见过太多。。。已经忘记了好的OO代码是什么样子的除外

管他OO与不OO呢。程序稳定是王道。
17 楼 jomper 2008-03-06  
正是"道可道,非常道"
16 楼 抛出异常的爱 2008-03-06  
wuhua 写道
OO与非OO得区别很多。
作者只是谈到了一点。
我个人感觉是,面向过程很符合人们的常规思维
而面向对象了反而是扭曲了这种思维。

人们很自然的想到做完了这件事情,应该做下面的事情。
而不会想到应该通过代理啊,委托啊来处理这些事情,除非是非常规思维的人。
比如那些大师啊,头脑转的特别快的人。


如果你喜欢看过程性的代码
只能说明。。。
你的大脑与普通人的不一样

PS:很烂的OO见过太多。。。已经忘记了好的OO代码是什么样子的除外
15 楼 wuhua 2008-03-06  
OO与非OO得区别很多。
作者只是谈到了一点。
我个人感觉是,面向过程很符合人们的常规思维
而面向对象了反而是扭曲了这种思维。

人们很自然的想到做完了这件事情,应该做下面的事情。
而不会想到应该通过代理啊,委托啊来处理这些事情,除非是非常规思维的人。
比如那些大师啊,头脑转的特别快的人。
14 楼 hongkong 2008-03-06  
一看这个题目,就想到会有很多不顶你的回复 
其实面向过程也是很优秀的,这点在校学生是无法体会的
13 楼 抛出异常的爱 2008-03-06  
程序如果只想完成任务的话。
只要用if + for就差不多可以完成大多数工作了。

但为了让人类能看懂
就不得不把枯燥的if变成能看懂的东西。
如:OO方式的代码
减少了观注
集中了业务
缩减了代码的长度
12 楼 sunarrow 2008-03-06  
我只知道if else 用起来很方便,很多情况下不需要设计模式那一大堆东西来弄得很复杂
11 楼 bluemeteor 2008-03-06  
ray_linn 写道
if else if有罪么???? 


if else 无罪,罪在滥用
10 楼 惊鸿逝水 2008-03-06  
很明显,这是转贴,而且是来自JDON
9 楼 zdonking 2008-03-05  
文章的内容好像在哪儿见过.
8 楼 gigix 2008-03-05  
不明白你俩在争啥……写得好的C程序也很漂亮的。长函数,switch/case,搁在哪儿都是bad smell。好的程序都是一样的,C程序员一样会把条件逻辑变成查表逻辑,跟OO不OO没关系。
要说起来的话,C程序员更在乎开和闭的分界,因为一不小心就会把编译和链接搞得很慢。当然烂程序总是很多的,但优秀的C程序员,对于这种事情的在乎程度比我可高多了。
7 楼 sg552 2008-03-05  
恩,我的印象很深刻,在一段话里,说JAVA对方法调用的开销现在非常小了。所以可以在很多开源项目中,都会看到一个方法调用一个方法,这会让C/C++ 背景的人非常不习惯。 

当时看了真是深有感触,具体哪本书忘了,不是WITHOUT EJB就是REFACTORING,半年前看的了。

为OO而OO才是最吗?这个要看情况吧。不过JAVA本身就是OO语言,你非要把它当C用,别人也管不了啊。

6 楼 ray_linn 2008-03-05  
sg552 写道
回答楼上,在java中的方法调用开销非常小,貌似我在《Without EJB》中看到的。

另外,在《重构》中专门有一章"Simplify conditional xxx" ,说的就是如何用多态取代if else 。 它的罪就在于不是OO。


比C小???呵呵大概不太可能吧? 我觉得为OO而OO那才是罪.
5 楼 sg552 2008-03-05  
回答楼上,在java中的方法调用开销非常小,貌似我在《Without EJB》中看到的。

另外,在《重构》中专门有一章"Simplify conditional xxx" ,说的就是如何用多态取代if else 。 它的罪就在于不是OO。
4 楼 ray_linn 2008-03-05  
if else if有罪么???? 

我记得在玩C的时候,人家可说方法调用是有开销的.
3 楼 rainlife 2008-03-05  
貌似这篇文章的题目叫"你还在用if else吗?",投隐了。
2 楼 movingboy 2008-03-05  
引用
面向过程设计和面向对象设计的主要区别是:是否在业务逻辑层使用冗长的if else判断。......

这样说让我很惊讶:我所了解的OOD的一个原则是按照职责划分对象,而不是流程。我从未听说过将是否使用冗长的if else判断作为是否OOD的依据
1 楼 gigix 2008-03-05  
这个,根本就是扯淡
引用
而使用OO,则首先打破这个代码由上向下顺序等同于运行时的先后循序这个规律,代码结构不由执行循序决定,由什么决定呢?由OO设计;设计模式会取代这些if else,但是最后总是由一个Service等总类按照运行顺序组装这些OO模块

除非烂熟于心的重复工作,否则对象大部分是重构出来的,不是想出来的

相关推荐

    \设计模式.docx

    ### 设计模式之状态机详解 #### 一、状态机概述及分类 状态机作为一种重要的设计模式,在软件工程中有着广泛的应用。它主要用于模拟对象的行为,特别是那些具有多个状态的对象,能够根据不同的输入(事件)从一个...

    从VB到Python:高中信息技术教学的转变.zip

    《从VB到Python:高中信息技术教学的转变》 在当今快速发展的信息技术领域,编程语言的选择对教育至关重要。VB(Visual Basic)曾是许多高中信息技术课程的首选教学语言,以其直观的图形用户界面和易于理解的语法...

    架构培训测试.docx

    图A到图B的转变,即依赖从具体类转向接口,实现了这一原则。没有`Platform`包时,`Application`仍然可以编译,因为依赖的是抽象接口。 6. **MVC模式(Model-View-Controller)**:在实际开发中,尤其是Web应用程序,...

    高职网页设计与制作课程信息化教学设计研究——以JavaScript条件语句为例.pdf

    在信息化教学改革中,教师的角色也发生了转变,从传统的知识传授者转变为学习的引导者和促进者。教师需不断更新教学方法,利用信息技术手段,如【在线学习和交流】,创建讨论区,鼓励学生分享见解,形成协作学习氛围...

    Implementation Patterns

    与设计模式关注的是系统级别的结构不同,实现模式更侧重于代码层面的具体实践,帮助开发者写出易于理解、维护且具有良好可读性的代码。 #### 书籍概览 《实现模式》一书得到了许多业界知名人士的高度评价,包括 ...

    C游戏编程从入门到精通

    本书旨在通过TC(Turbo C)这个经典的C语言编译器,引导读者逐步掌握游戏开发的基本技能和原理,从而实现从零基础到熟练掌握游戏编程的转变。 在C语言的基础上,游戏编程主要涉及以下几个关键知识点: 1. **基本...

    三段式状态机思维陷阱

    该实现存在明显的问题:在状态从`wr_st`向`rd_st`转变时,输出信号`q`未能正确更新。原因在于`nextstate`由组合逻辑直接决定,导致`q`的更新未能与状态转移同步。 ##### 思维陷阱解析 1. **基于`nextstate`的输出...

    基于Python教学的中学计算思维等级评价模式构建-于露.pdf

    总的来说,基于Python的教学能够帮助中学生建立坚实的计算思维基础,通过逐步进阶的评价体系,可以有效促进学生从掌握基础知识到运用计算思维解决问题的转变,从而提高他们的创新能力和问题解决能力。这种评价模式为...

    “C语言程序设计”教学案例分析——以发红包程序算法的实现为例.pdf

    在实际编写发红包程序时,学生需要综合运用if-else条件判断、循环结构、函数定义、数组使用等知识点,这些技能几乎涵盖了课程大纲要求学生掌握的全部知识点。 通过实现发红包程序,学生能够更深刻地理解程序设计的...

    轻松学JAVA编程(源码)

    【标题】"轻松学JAVA编程(源码)"所涵盖的知识点主要集中在Java编程语言的基础概念、语法结构以及实际应用上。这本书通过提供源码实例,旨在帮助...随着学习的深入,你将逐步掌握Java编程,实现从新手到熟练者的转变。

    delphi编程知识

    Delphi编程知识是面向对象的开发环境,基于Pascal语言,由Embarcadero Technologies公司维护。它以其高效、快速的编译器和强大的VCL(Visual ...通过深入学习和实践,开发者可以精通Delphi,实现从入门到精通的转变。

    编译原理实验,PL/0语言功能扩展

    通过这些扩展,PL/0语言从一个基础的教学工具转变为一个更接近实际编程需求的语言,使得学习编译原理的学生能够更好地理解和实现编译器的基本概念,如词法分析、语法分析、语义分析和代码生成。同时,C语言作为编译...

    java程序员面试宝典+java EE面试题

    - **语法**:变量、数据类型、运算符、控制结构(如if/else、switch、for/while循环)、方法、类和对象。 - **封装、继承和多态**:面向对象编程的三大特性,如何通过它们实现代码的重用和灵活性。 - **异常处理*...

    java金典50题.zip

    通过解决"Java经典50题",学习者可以逐步加深对这些概念的理解,通过实践巩固理论知识,从而实现从Java新手到入门的转变。记住,学习编程不仅是学习语法,更重要的是理解和应用这些知识去解决问题。不断地练习和实践...

    重构——改善既有代码的设计 中文版

    《重构——改善既有代码的设计》这本书被视为软件工程领域的经典之作,与《设计模式》齐名,被誉为“软工双雄”。本书通过详细的案例分析、实用技巧和方法论,向读者展示了如何有效地重构代码。 #### 重点知识点...

    Tcl与Design Compiler 二DC综合与Tcl语法结构概述.pdf

    在这个过程中,Design Compiler (DC) 是一种广泛使用的逻辑综合工具,它能够自动化地完成从高级描述到可制造的门级电路的转变。 **Synthesis = Translation + Logic Optimization + Gate Mapping** 1. **...

    易语言源码易语言学习进阶如果源码.rar

    通过分析和研究这个压缩包内的源码,你可以逐步提升对易语言的理解,掌握编程技巧,实现从初学者到进阶者的转变。同时,学习源码也能培养解决问题的能力,因为源码中往往包含了作者解决特定问题的方法和思路。对于...

    《C语言程序设计》课程一体化教学课堂教学研究.pdf

    《C语言程序设计》是计算机科学领域的一门基础课程,对于理解和掌握计算机编程思维具有重要意义。一体化教学模式旨在将理论...在C语言的教学过程中,应注重实践环节,使学生从理论到实践的过渡更加平滑,提高教学质量。

    Python语言编程的课程教学设计-金罡.pdf

    Python编程的核心概念包括变量、数据类型、控制结构(如if-else语句、for循环和while循环)、函数定义和调用、类与对象(面向对象编程)以及模块和包的使用。Python语言还支持异常处理、文件操作、网络编程和多线程...

    2020下-C语言程序设计(C64)实验-学生版.doc

    随着教学方法的不断创新,C语言的教学也逐步从传统的理论讲授转变为更加注重实践操作的实验教学模式。本文档“2020下-C语言程序设计(C64)实验-学生版”对C语言程序设计实验进行了概述,并详细介绍了多个实验的目标...

Global site tag (gtag.js) - Google Analytics