当设计一个对象可能在不同情况下有不同的行为时,一般使用的是父类 子类 多态重载的方法,
Person a=new WhitePerson();
Person b=new BlackPerson();
a.speak();// i'm white
b.speak();// i'm black
但这样做不好的地方在于 假如对象创建后了之后想在运行时改变对象的行为是不可能的,(当然可以用if else判断状态值,但这样一、多次判断状态的话有重复代码 二、增加状态的时候增加else会违反开闭原则)除非重新创建对象,所以这时可以用策略分离行为
interface SpeakAction(){
void speak();
}
class BlackSpeak implements SpeakAction(){
void speak(){
print "I'm black"
}
}
class WhiteSpeak implements SpeakAction(){
void speak(){
print "I'm white"
}
}
Person{
SpeakAction speak;
void speak(){
speak.speak();
}
void setSpeak(SpeakAction speak){
this.speak=speak;
}
}
这样当你想改变行为的时候通过setSpeak设置新的行为就可以了
--------------------------------------------------------------------------------------------------
状态模式的类图和策略模式的类图很相似,都是面向一个接口有一系列不同的实现,然后调用的时候面向接口调用不同的实现;但是,策略模式和状态模式虽然类图上很相似,但是运用的时候,个人觉得有很大的区别,关键在于你在如何理解你的代码需求和设计要求,状态模式在gof的定义如下:
当一个状态的内部状态改变时允许改变其行为,这个对象看起来改变了其类;
状态模式主要突出了两个字:”改变”,对!对象的状态决定了状态的行为,事物的本质决定了事物的行为,我们精神亢奋的时候,我们拼命的工作,我们拼命的工作就导致了我们身心疲惫,物品们身心疲惫就导致我们的行为是需要休息;从这里我们可以看出,事物的内在状态决定了事物所做出的行为,而事物的行为势必又会改变我们事物的状态,两者在不断的相互影响,然后实现状态的迁移和跃迁;
从这两点,我们可以看出策略模式和状态模式的应用场景有很大的不同;一个是封装一系列平行且复杂多变的实现方式,一个是实现把对象的内在状态的变化封装起来,用外部行为来表现出来;
example:
----------------------------------------------------------------------------------
* 帐户(Account)分为普通帐户,VIP帐户和信用卡帐户三种.
* 每个帐户都可以执行取钱,存钱,注销三种操作
* 关于取钱操作的细节:
普通帐户每次取钱限额为1000元,不能透支
VIP帐户每次取钱限额为3000元,不能透支
信用卡帐户每次取钱限额为3000元,可以透支
* 另外每个帐户有四种可能的状态:新建、正常、冻结、挂失
* 帐号处于不同状态时对于上面提到的三种操作会产生影响:
新建状态时不能执行注销操作
挂失状态时不能执行存钱、取钱操作
冻结状态时不能执行存钱、取钱、注销操作
这是简单的需求,在设计时,
* 我将帐户设置为抽象类(Account),普通帐户,VIP帐户和信用卡帐户为其子类
* 使用状态模式管理帐户的四种状态,具体做法为:建立接口AccountState,其中包含取钱,存钱,注销三个方法,然后给出四个实现类,分别对应新建、正常、冻结、挂失四种状态。在Accout中保持一个对状态的引用
问题:在实现状态模式中的三个方法的时候出现了问题,以取钱为例,显然取钱时要判断当前帐号的类别,这样一来难免引入if判断,二来需要在状态类中依赖Account子类,感觉并不好,请教好的解决思路。
(为了避免代码冗余,希望能用策略模式实现取钱,存钱等方法)
-------------------------------------------------------------------------------------------------
>以取钱为例,显然取钱时要判断当前帐号的类别,这样一来难免引入if判断,
这个问题是因为你状态设计有些问题,我培训时一直强调:使用状态模式之前一定要搞清楚事件和状态,这个案例中,取钱是个动作,无疑是事件,目前你的状态有新建、正常、挂失、冻结和注销四个状态,其他都是事件,你必须将这四个状态设为四个状态对象,事件导致状态变化,你要分析下这四个状态的切换是依靠什么事件完成的。
象取钱这样的事件,我目前发现不能造成上述四个状态的切换,所以,取钱应该写在普通的业务层里面,当然,为了封装只有正常状态才可以取钱这个规则,你可以在状态模式基础上再封装一层规则策略层,在其中将取钱规则写入,外部客户端调用时,只需传入事件特征如取钱,然后获得结果:要么正常;要么返回特定Exception,无法取钱。
至于if else只是一个设计结果的体现,可能会在规则策略层也用到if else,但是这时我的if else已经是一个非常简单,粒度很小的判断了,这就达到设计目的了。
希望对你有帮助。
二来需要在状态类中依赖Account子类,感觉并不好,