Java设计模式之策略模式与状态模式

时间:2022-11-21 21:58:36

版权声明:本文出自汪磊的博客,转载请务必注明出处。

一、略模式定义

定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化。

好了,定义看看就完了,我知道你很烦看定义。

二、策略模式涉及到的三个角色

环境(Context)角色  持有一个Strategy的引用

抽象策略(Strategy)角色  这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

具体策略(ConcreteStrategy)角色  包装了具体的算法或行为。

三、策略模式使用举例

还是赶快看代码吧,知道你看上面定义都烦死了。

我们写一个简单的Demo来对策略模式进行更深的理解,我们模拟游戏中玩家参与一个活动购买金币,普通玩家没有折扣,高级玩家9折优惠,VIP玩家7折优惠。

首先我们定义一个接口,这就是抽象策略角色,如下:

1 public interface GameStrategy {
2
3 public void goldCoin();
4
5 }

很简单,就是一个接口。

接下来我们编写具体策略角色类,从需求就能明白,需要有三个具体策略角色类,也就是三个策略对应不同等级玩家。

普通玩家策略类:

1 public class normalStrategy implements GameStrategy {
2
3 @Override
4 public void goldCoin() {
5 //
6 System.out.println("普通玩家没有折扣");
7 }
8 }

高级玩家策略类:

public class advancedStrategy implements GameStrategy {

@Override
public void goldCoin() {
// TODO Auto-generated method stub
System.out.println("高级会员9折优惠");
}
}

VIP玩家策略类:

1 public class vipStrategy implements GameStrategy {
2
3 @Override
4 public void goldCoin() {
5 //
6 System.out.println("VIP会员7折优惠");
7 }
8 }

都很简单,就是简单打印信息。

然后编写环境角色类,如下:

 1 public class Context {
2   //持有一个Strategy的引用
3 private GameStrategy mGameStrategy;
4
5 // 构造函数
6 public Context(GameStrategy strategy) {
7 this.mGameStrategy = strategy;
8 }
9
10 public void setStrategy(GameStrategy strategy) {
11 this.mGameStrategy = strategy;
12 }
13
14 public void goldCoin() {
15 this.mGameStrategy.goldCoin();
16 }
17 }

最后就是调用了,根据不同情况调用不同策略:

 1 public class main {
2
3 public static void main(String[] args) {
4 //普通玩家策略
5 Context context = new Context(new normalStrategy());
6 context.goldCoin();
7 //高级玩家策略
8 context.setStrategy(new advancedStrategy());
9 context.goldCoin();
10 //高级玩家策略
11 context.setStrategy(new vipStrategy());
12 context.goldCoin();
13 }
14 }

不同情况下我们替换为对应策略就可以了。

四、策略模式优缺点

优点

策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法让子类实现

缺点

通过上面Demo我们会发现调用者必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类并且由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。

好了上面就是策略模式的介绍了,关键是自己慢慢理解。接下来我们了解一下状态模式。

五、状态模式定义

当一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。又称状态对象模式,状态模式是对象的行为模式。

简单的理解就是一个类其状态改变了,那么其功能也相应的改变了。比如水变为冰,状态改变了,其功能也发生了相应变化。

六、状态模式角色

 Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。

 State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。

 ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。

七、状态模式使用举例

接下来我们编写一个小Demo来进行更深入理解:在办公系统中,一个文件会有不同状态:未处理,正在处理,已经处理。我们就简单模拟一下文件状态的切换。

首先我们看下抽象状态类,很简单就是定义一个接口:

1 public interface State {
2
3 void fileState();
4 }

接下来看下三个具体状态类:

未处理状态类

1 public class NotDealState  implements State{
2
3 @Override
4 public void fileState() {
5 // TODO Auto-generated method stub
6 System.out.println("文件未处理状态");
7 }
8 }

正在处理状态类:

1 public class DealingState implements State{
2
3 @Override
4 public void fileState() {
5 // TODO Auto-generated method stub
6 System.out.println("文件正在处理状态");
7 }
8 }

已经处理状态类

1 public class HasDealState implements State{
2
3 @Override
4 public void fileState() {
5 // TODO Auto-generated method stub
6 System.out.println("文件已经处理状态");
7 }
8 }

是不是很简单,同样也只是打印一些简单的信息罢了。

然后看下上下文类:

 1 public class FileContext {
2
3 //默认情况下未处理状态
4 private State fileState = new NotDealState();
5
6 /**
7 * 文件状态切换为未处理状态
8 */
9 public void notDeal(){
10
11 this.fileState = new NotDealState();
12 }
13
14 /**
15 * 文件状态切换为正在处理状态
16 */
17 public void Dealing(){
18
19 this.fileState = new DealingState();
20 }
21
22 /**
23 * 文件状态切换为已经处理状态
24 */
25 public void HasDeal(){
26
27 this.fileState = new HasDealState();
28 }
29
30 /**
31 * 获取当前文件的状态
32 */
33 public void getFileState(){
34 fileState.fileState();
35 }
36 }

上下文类主要就是封装当前文件状态并且对外提供状态切换的方法

最后看下怎么使用吧:

 1 public class Client {
2
3 public static void main(String[] args) {
4
5 FileContext fileContext = new FileContext();
6 fileContext.getFileState();
7 //切换为正在处理状态
8 fileContext.Dealing();
9 fileContext.getFileState();
10 //切换为已经处理状态
11 fileContext.HasDeal();
12 fileContext.getFileState();
13 }
14 }

外部使用调用相应切换状态方法就可以了,很简单,没有什么需要特别说明的。

八、状态模式与策略模式区别以及联系

策略模式与状态模式及其相似,但是二者有其内在的差别,策略模式将具体策略类暴露出去,调用者需要具体明白每个策略的不同之处以便正确使用。而状态模式状态的改变是由其内部条件来改变的,与外界无关,二者在思想上有本质区别。

好了,状态模式与策略模式讲解到此为止,二者区别联系不是几句话就能说清楚,关键是思想上的不同,具体感悟需要在实践中自己慢慢体会。