设计模式(12)--State状态模式&Strategy策略模式

一、一个对象根据不同的状态,执行不同的行为。我们如何去编写执行行为的方法呢?用逻辑判断语句判断状态不同而执行不同的代码?显然不会选择这种耦合的复杂的逻辑。解耦是显而易见的,即把不同状态下的执行代码分离开来。从而便有了状态模式。
设计模式(12)--State状态模式&Strategy策略模式_第1张图片
状态模式的要点:
1.把不同状态的行为处理抽象为Handle方法,并在抽象出的状态类中设置这个方法。
2.对象必须持有这个状态类,并设置一个初始的具体状态类,例如ConcreteStateA()
3.传入状态给对象,对象直接调用Handle()方法,执行行为。
4.最重要的逻辑在Handle方法中:a.无论怎样,在执行完逻辑后,必须吧Context持有的state更改为当前应该处于的正确的具体实现类。
b.Context中的初始state有两种情况,一种是肯定是正确的初始值,例如电梯的初始状态肯定是关闭状态。另外一种,则未必是正好对口的初始值,这时候,就应该在handle()中加入if判断,并把Context中的state设置成别的值,并主动的调用这个新state的handle。(有点像职责链了)

实例:一个信贷产品的流程控制程序,当用户进入自己的贷款页面时,从数据库查询出该用户已有的贷款的状态,根据不同的状态,处理不同的内部业务行为,同时在页面展示不同的内容。 这是一个存在很多if else判断的逻辑,可以考虑用状态模式来替代。

//把处理逻辑抽象成状态对象和handle方法
public abstract class LoanState{
    public abstract String handle(ApplyQueryHandle context);
}

//类似于Context对象的总控对象
public class ApplyQueryHandler{
    //要设置一个初始的具体状态实现类,getset方法略
    private LoanState state = new NewApplyState();
    //记录当前的状态码,getset方法略
    private String status;

    public handle(){
        this.state.handle(this);
    }
}

//用户进入自己的贷款页面所执行的方法
public String applyQuery(){
    //查询数据库
    List applyStatus = queryDB();
    ApplyQueryHandler handler = new ApplyQueryHandler();
    //非常简单,省去了所有的if else判断
    for(String status:applyStatus){
        handler.setStatus(status);
        handler.handle();
    }
}

//把逻辑都解耦到这些重要的具体状态类中了
public class NewApplyState extends LoanState{//处于新申请状态的贷款
    public String handle(ApplyQueryHandler context){
        //如果传递过来的贷款状态确实是申请状态,执行
        if(context.status==constant.NEW_APPLY){
            return executeLogic();
        }//否则,最重要的,要把正确的State具体类设置给context,并显示的再执行context的handle
        else{
            context.setState(new GoingApplyState());
            context.handle();
        }   
    }
}

public class GoingApplyStateextends LoanState{//处于进行中状态的贷款
    public String handle(ApplyQueryHandler context){
        //如果传递过来的贷款状态确实是进行中状态,执行
        if(context.status==constant.GOING_APPLY){
            return executeLogic();
        }//否则,最重要的,要把正确的State具体类设置给context,并显示的再执行context的handle
        else{
            context.setState(new FinishApplyState());
            context.handle();
        }   
    }
}

FinishApplyState略

总结:其实这个实例,就是4.b中所说的State具体类“未必是正好对口的初始值”。而且,你设置给Context的另一个具体类,可能仍然未必对口,一直到设置成对口的为止,这真的和职责链的处理方法很类似。所以这个实例在实际开发中是否更适合职责链模式,视情况而选择。
那么职责链和状态模式有什么区别呢?:
看了网上的众多评论,普遍认为最大的区别是,职责链的链条,是在client处组装的,即非编译时确定,是运行时确定。 而状态模式,如果要设置其它的State具体类,都是在方法中固定的,不可配置。各有优劣吧。
从对现实的模拟来理解,职责链模式,是由职责类直接调用下一个职责类来继续处理请求。而状态模式,其实是负责设置下一个状态类给Context,再由Contex来调用下一次处理方法。

ps:设计模式是灵活的不是死板的,如果你认为具体情况有很舒服的改进方式,那么就不需要照搬设计模式的例子。未必是正好对口的初始值。而且,你设置给Context的另一个具体类,可能仍然未必对口,一直到设置成对口的为止”。这段逻辑,其实也有其它的解决办法,那就是在status传入ApplyQueryHandler时,直接由ApplyQueryHandler来判断status从而设置出对口的State具体实现类。 也就是把上面代码实例的if判断,转移到了Context里。也就是说,在Context里使用了一个工厂来提供合适的State具体实现类。在《大话设计模式中》,还提到了把这个if判断都省略,那就是使用反射,比如用Status状态码在常量表中对应出具体的类名,使用Class.forName等形式反射出合适的State具体实现类。

二、状态模式和策略模式非常非常的相似,从UML上几乎看不到区别。典型的应用是:一个商场结算功能,会有数百种打折,积分,vip的结算算法。我们根据结账用户的具体情况在选择不同的算法。那么和状态模式很类似,抽取算法抽象类,每一种算法都有一个具体的实现类。Context根据实际情况选择具体的算法类来执行算法。 那么其与状态模式的区别是什么呢?
非要找区别,那么就是,状态模式的状态这个概念,是可以在State具体实现类中设置的,是由程序决定的,有着一些约束关系。而在策略模式中,State这个情况,必须是客户端输入提供的,找到特定的对口算法具体实现类,执行完就完事了,状态并不会改变,也不需要你设置其它正确的对口实现类。

你可能感兴趣的:(设计模式)