发现问题:
大家在Coding的时候,有没有用到很多的选择语句?像这样:
if(…)
{
…
}
else if(…)
{
…
}
else if(…)
{
…
}
else
{
…
}
我是经常碰到,最经常见到的地方就是在struts的业务逻辑――Action的实现的类里, 以前的程序员很牛B,Coding从来都已“just can run ”为最终标准。
下面这个函数:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws java.lang.Exception
的实现,一般都是一个函数里边写2000-3000行代码,从来不关心结构的问题。
“标准示范”就是刚刚上边列出来的if…else if…else…语句,这样的语句大多被用来判断提交了什么动作,然后处理的。当然,需求是在不断变化中的,每当新加了一个业务的提交处理的时候,
怎么办呢?绝大多数人的选择都是在最后一个else if的后面,else的前面,添加一个else if…,^_^,如此处理。长此以往,一段程序或许本来就有n个else if,然后维护又加了n个,本来2000行的函数,搞成了三千行。
哈哈,一个函数体三千行!何其壮观也!!!
因此,我觉得,程序员在写判断语句的时候,用了多个else if就应该小心一点了,这个语句像某位大师所说的,是
在代码中加入了“坏味道”,会引起程序变质,成为“腐坏代码”的。
提出问题:
那么,在出现要使用多个判断,并且判断逻辑经常改变的时候的时候,我们如何才能防止代码腐坏呢?
――
使用state模式就是一个比较好的方法
State模式介绍:
tate模式属于对象行为型模式,
意图:允许一个对象在其内部状态改变时改变它的行为
适用场景:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。
以上是出自GoF的DesignPatterns的官方解释,但是归结到平常使用中,我认为最多的适用场景还是
替代if…if else…else多分支,实现更灵活的设计,防止代码腐坏。
可以看出:上面提到的“经典示例”就是个典型的第2个场景
State模式示例:
一开始我们有这么个Context类,这个类有个state成员,当state改变时,我们需要把它的改变打印出来。(当然,我们得假设各个打印的实现逻辑是彼此不同的)。
先看一下
常规的实现:
public class ContextOriginal
{
private String state;
public String getState()
{
return state;
}
public void setState(String state)
{
this.state = state;
}
public void print(String msg)
{
System.out.println(msg);
}
public void printImplFirst()
{
this.print("printImplFirst: " + this.state);
}
public void printImplSecond()
{
this.print("printImplSecond: " + this.state);
}
public void printImplThird()
{
this.print("printImplFinal: " + this.state);
}
public void execute()
{
if(this.state != null)
{
if(this.state.equals("first"))
{
this.printImplFirst();
}
else if(this.state.equals("second"))
{
this.printImplSecond();
}
else if(this.state.equals("third"))
{
this.printImplThird();
}
else
{
throw new IllegalArgumentException(
"illegalArgumentException: this.state = " + this.state);
}
}
else
{
throw new NullPointerException("this.state is null");
}
}
}
这样的实现方法的弊端刚开始已经分析的很清楚了,如果我们需要再加一个状态“ fourth”,则需要再加一个实现“printImplFourth()”,然后在“最后一个else if的后面,else的前面,添加一个else if…”,
典型的使代码变质的方法。
那么我们使用State模式来实现吧:
我们首先声明一个抽象类State,以后所有的实现都继承这个类来实现它的handle方法。
我们在Context中加入成员State,表示Context的当前状态,
然后把所有对Context的state的处理都通过继承State抽象类来实现。
下面是类图描述:(从类图上来看,state模式和strategy模式的类图是非常相似的)
(见附件)
State抽象类的代码:
package patterns.state;
import patterns.state.impl.Context;
public abstract class State {
public abstract void handle(Context context);
public abstract void changeState(Context context);
}
State的几个实现代码:(只写出了一个,其它实现与之类似)
package patterns.state.impl;
import patterns.state.State;
public class FirstState extends State {
@Override
public void handle(Context context) {
System.out.println("Current State is : "
+ context.getSteate().toString());
this.changeState(context);
}
@Override
public void changeState(Context context) {
context.setState(new SecondState());
}
public String toString() {
return this.getClass().getSimpleName();
}
}
package patterns.state.impl;
import patterns.state.State;
public class SecondState extends State {
@Override
public void handle(Context context) {
System.out.println("Current State is : "
+ context.getSteate().toString());
this.changeState(context);
}
@Override
public void changeState(Context context) {
context.setState(new FirstState());
}
public String toString() {
return this.getClass().getSimpleName();
}
}
Context类的实现代码:
package patterns.state.impl;
import patterns.state.State;
public class Context {
// context的当前状态
private State state;
public Context() {
this.state = new FirstState();
}
public State getSteate() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void execute() {
this.state.handle(this);
}
}
好了,现在State模式的实现写完了。
现在我们什么时候想处理state为first的时候,只需要
package patterns.state.test;
import patterns.state.impl.Context;
import patterns.state.impl.FirstState;
public class Test {
public Test() {
Context context = new Context();
context.execute();
context.setState(new FirstState());
context.execute();
context.execute();
context.execute();
context.execute();
}
public static void main(String[] args) {
new Test();
}
}
通过使用了State模式,不管Context的状态改变多少次,添加了多少个状态,我们都不需要修改它的源代码,而只是通过添加新的实现方法就可以搞定了,这样达到了防止“
代码腐坏”的目的。
State模式的特点:
State模式允许一个对象基于内部状态而拥有不同的行为
State模式允许使用类代表状态
Context会将行为委托给当前对象
通过将每个状态封装进一个类,我们把以后需要做的任何更改局部化了
状态(state)的转换可以由StateHandler类或者context类来控制
状态处理类(StateHandler)可以被多个Context实例共享。
使用状态模式将会导致设计中类的数目大量增加
需要注意的地方:
1. state之间的转换. State的转换可以在State类内部完成, 但是这样会带来的问题是各个State之间出现了关联, 那么如果一个State本身改变(减少, 增加) 会带来很大影响, 你就有可能看看当前发生改变的state是否也影响到了其它的state的执行. 不过经过跟同事的讨论发现也是在所难免的. 另外一个, state的转换也可以由其它类调用Context的setState()来完成, 感觉这种情况更不可靠, 因为这样的话其他类就必须知道context的特定state, 带来了不必要的耦合, 因此建议对setState()的调用尽量放在Context和State这两处.
2. State的创建和销毁. 两个方法: 1.在context内部创建所有state, 一直维护从不销毁.2.在状态转换的时候才创建, 然后上一个state由JVM自动回收. 主要原则需要看实际情况是Context的State的变化是否频繁, 如果不频繁, 建议用第二种,比较优雅.
总结:
1.尽量不要使用太多分支的语句。
2.如果函数超过一屏,你就需要考虑是否需要把功能分割了。如果你写了个3000行的“超长”的函数,以后维护的人会很不爽,也会遭到bs的。
3.如果不幸遇到必须使用太多分支且分支与类的某一个状态有关且经常改变,那可以考虑使用state模式,防止“腐坏”。
4.牢记OO设计原则:“找出应用中需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起”。
- 大小: 8.7 KB
分享到:
相关推荐
设计模式C++学习之状态模式(State)
该PDF是我在学习state pattern时所做的笔记。里面包括了state pattern 的定义、何时使用、是否使用及实例四个部分,实例部分写的比较细,看完这个实例,相信大家也就知道怎么在自己的项目中应用state pattern了。这...
也可以作为高效学生深入学习设计模式的参考读物! 第1章 设计模式基础 第2章 简单工厂 第3章 外观模式 第4章 适配器模式(Adapter) 第5章 单例模式(Singleton) 第6章 工厂方法模式(Factory Method) 第7章...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计...
书名: 设计模式可复用面向对象软件的基础 英文原书名: Design Patterns:Elements of Reusable Object-Oriented software 作者: Erich Gamma 等 译者: 李英军 马晓星 蔡敏 刘建中 书号: 7-111-07575-7 页码: 254 定价...
本书设计实例从面向对象的设计中精选出23个设计模式,总结了面向对象设计中最有价值的经验,并且用简洁可复用的形式表达出来。本书分类描述了一组设计良好,表达清楚的软件设计模式,这些模式在实用环境下有特别有用...
也可以作为高效学生深入学习设计模式的参考读物! 第1章 设计模式基础 第2章 简单工厂 第3章 外观模式 第4章 适配器模式(Adapter) 第5章 单例模式(Singleton) 第6章 工厂方法模式(Factory Method) 第7章...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式...
1.1 什么是设计模式 2 1.2 Smalltalk MVC 中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象...
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计...
“[设计模式]在实用环境下特别有用,因为它分类描述了一组设计良好,表达清楚的面向对象软件设计模式。整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法...
《asp.net设计模式》涵盖了开发企业级asp.net应用程序的知名模式和最佳实践。本书用到的模式可以用于从asp.net1.0到asp.net 4.0的任何版本。不必管模式本身所用的语言,可以将模式用于任何面向对象编程语言。 ...
1.1 什么是设计模式 2 1.2 Smalltalk MVC中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象...