java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > 对比Java的状态模式和策略模式

对比Java设计模式编程中的状态模式和策略模式

作者:花名有孚

这篇文章主要介绍了Java设计模式编程中的状态模式和策略模式对比,文中列举了两种模式的相似点和不同点,并都举了代码的实例作为参照,需要的朋友可以参考下

为了能在Java应用程序中正确的使用状态模式和策略模式,开发人员需要清楚地知道这两种模式之间的区别。尽管状态模式和策略模式的结构非常相似,它们又同样遵循开闭原则,都代表着SOLID设计原则的'O',但它们的意图是完全不同的。Java中的策略模式是对一组相关的算法进行封装,给调用方提供了运行时的灵活性。调用方可以在运行时选择不同的算法,而不用修改使用策略的那个Context类。使用策略模式的经典例子包括实现加密算法,压缩算法,以及排序算法。另一方面,状态模式使用一个对象可以在不同的状态下表现出不同的行为。真实世界里的对象也是有状态的,并且它们会随着状态的不同而有不同的表现,比方说自动售货机,它只会在hasCoin状态下才能出售物品,如果你不塞硬币进去它是不会售货的。现在你可以很清楚地看到策略模式和状态模式的区别了,它们的目的是不一样的。状态模式可以帮助对象来管理它的状态,而策略模式使得客户端可以选择不同的行为。还有一个不太容易看到的区别是,谁去驱动行为的改变。在策略模式中,是客户端驱动的,它给上下文信息提供了不同的策略,而在状态模式中,状态的迁移是由Context或者State对象自己来管理的。同样的,如果你在State对象里面进行状态的修改,它必须持有Context的引用,也就是说对自动售货机而言,它可以调用setState方法来修改当前Context的状态。另一方面,策略对象不会持有Context的引用 ,它的客户端将选中的策略传递给Context。策略模式和状态模式是最容易碰见的关于Java设计模式的面试题,在这篇关于Java设计模式的文章里,我们将会对这点进行详细的介绍。我们会探索这两种模式的相同点与不同点,这有助于提高你对这两种模式的理解。

状态模式和策略模式的相似点:
如果你看下策略模式和状态模式的UML图,它们看起来非常相似。在状态模式中,使用State对象来改变行为的的对象叫Context对象,类似的在策略模式中,使用Strategy对象来改变行为的对象也是Context对象。记住,客户端是和Context对象交互的。在状态模式中,Context代理了状态对象的方法调用,Context中的当前对象就是具体的状态对象,而在策略模式中,Context操作的也是策略对象,这个对象要么作为参数传入进来,要么是在创建Context对象的时候就已经提供了。

我们再来看一下这两种核心的Java设计模式的一些相似点:

状态模式和策略模式都很容易新增新的状态或者策略,而不会影响到使用它们的Context对象
两种模式都遵循开闭的设计原则,也就是说你的设计对扩展开放而对修改关闭。在这两个模式里,Context对修改是封闭的,新增状态或者策略,你不需要修改其它状态的Context对象,或者只需要很小的改动
正如状态模式中Context对象会有一个初始状态一样,策略模式中的Context通常也有一个默认的策略。
状态模式以不同的状态对象的方式来封装不同的行为,而策略模式以不同的策略对象来封装不同的行为。
这两种模式都依赖具体的子类来实现具体的行为。每一个具体的策略都扩展自一个抽象的策略类,每个状态也都是用来表示状态的接口或者抽象类的子类。


状态模式实例

public class WindowState { 
  private String stateValue; 
   
  public WindowState(String stateValue) { 
    this.stateValue = stateValue; 
  } 
   
  public String getStateValue() { 
    return stateValue; 
  } 
 
  public void setStateValue(String stateValue) { 
    this.stateValue = stateValue; 
  } 
   
  public void handle() { 
    /* 
     * 根据不同状态做不同操作, 再切换状态 
     */ 
    if ("窗口".equals(stateValue)) { 
      switchWindow(); 
      this.stateValue = "全屏"; 
    } else if ("全屏".equals(stateValue)) { 
      switchFullscreen(); 
      this.stateValue = "窗口"; 
    } 
  } 
   
  private void switchWindow() { 
    System.out.println("切换为窗口状态"); 
  } 
   
  private void switchFullscreen() { 
    System.out.println("切换为全屏状态"); 
  } 
   
} 
/** 
 * 状态的使用 
 */ 
public class WindowContext { 
  private WindowState state; 
   
  public WindowContext(WindowState state) { 
    this.state = state; 
  } 
   
  public WindowState getState() { 
    return state; 
  } 
   
  public void setState(WindowState state) { 
    this.state = state; 
  } 
   
  public void switchState() { 
    this.state.handle(); 
  } 
} 

/* 
 * 状态(State)模式 行为型模式 
 * 既改变对象的状态,又改变对象的行为 
 * 根据状态,改变行为 
 */ 
public class Test { 
  public static void main(String[] args) { 
    /* 
     * 本例的 状态值只有两个,由状态类自身控制 
     * 也可以把状态值的控制,交由客户端来设置 
     */ 
    WindowContext context = new WindowContext(new WindowState("窗口")); 
    context.switchState(); 
    context.switchState(); 
    context.switchState(); 
    context.switchState(); 
 
  } 
} 

打印

切换为窗口状态 
切换为全屏状态 
切换为窗口状态 
切换为全屏状态 


策略模式实例

/** 
 * 商品促销 
 * 本类为:收取现金的类 
 */ 
public interface ICashSuper { 
   double acceptCash(double money); 
} 
/** 
 * 正常收取现金 
 * @author stone 
 * 
 */ 
public class CashNormal implements ICashSuper { 
 
  @Override 
  public double acceptCash(double money) { 
    return money; 
  } 
 
} 

/** 
 * 打折收取现金 
 * @author stone 
 * 
 */ 
public class CashRebate implements ICashSuper { 
  private double rebate; //折扣 
  public CashRebate (double rebate) { 
    this.rebate = rebate; 
  } 
 
  @Override 
  public double acceptCash(double money) { 
    return new BigDecimal(money * rebate / 10).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 
  } 
   
   
} 


/** 
 * 让利返现 收取现金 
 * @author stone 
 * 
 */ 
public class CashReturn implements ICashSuper { 
  private double moneyCondition; //返现底限金额 
  private double returnMoney; //返还金额 
  public CashReturn(double moneyCondition, double returnMoney) { 
    this.moneyCondition = moneyCondition; 
    this.returnMoney = returnMoney; 
  } 
 
  @Override 
  public double acceptCash(double money) {//多重返利 
    if (money >= moneyCondition) { 
      return money - Math.floor(money / moneyCondition) * returnMoney; 
    } else { 
      return money; 
    } 
  } 
   
   
} 

/** 
 * 根据传递的的策略类,执行相应的行为 
 */ 
public class CashContext { 
  private ICashSuper casher; 
   
  public CashContext() { 
     
  } 
   
  public CashContext(ICashSuper casher) { 
    this.casher = casher; 
  } 
   
  public void setCasher(ICashSuper casher) { 
    this.casher = casher; 
  } 
   
  //根据具体的策略对象,调用它的算法行为 
  public double acceptCash(double money) { 
    return this.casher.acceptCash(money); 
  } 
   
} 

public class Test { 
  public static void main(String[] args) { 
    double money = 998; //原价 
    CashContext cashContext = new CashContext(new CashNormal()); 
    System.out.println("原价:" + cashContext.acceptCash(money)); //通常 策略 
     
    cashContext.setCasher(new CashRebate(8.5)); 
    System.out.println("打85折:" + cashContext.acceptCash(money)); //折扣  策略  85折 
     
    cashContext.setCasher(new CashReturn(300, 50)); 
    System.out.println("满300 返50:" + cashContext.acceptCash(money)); //返现 策略  满300 返50 
     
  } 
} 

打印

原价:998.0 
打85折:848.3 
满300 返50:848.0 

策略模式和状态模式的区别
我们已经了解到这两个模式在结构上非常相似,但它们仍有不同的地方。下面来看下它们之间一些关键的不同点。

这就是关于Java中策略模式和状态模式的所有区别。正如我所说的,它们在UML图中看起来非常类似,两者都遵循了开闭原则,并且封装了行为。策略模式是用来封装算法或者策略的,它会在运行时作为参数或者组合对象来提供给Context对象,而状态模式则是用来管理状态迁移 的。

您可能感兴趣的文章:
阅读全文