热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

对比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 

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

  • 策略模式封装了一系列的相关的算法,使用客户端可以在运行时通过组合和委托来使用不同的行为,而状态模式使得对象可以在不同的状态下展现出不同的行为。
  • 这两个模式的另一个不同之处在于状态模式封装的是对象的状态,而策略模式封装的是一个算法或者策略。由于状态是和对象耦合在一起的,它无法重用,而通过策略或者算法独立于它的上下文,使得它们可以重复使用。
  • 状态模式中,状态本身会包含Context的引用,从而实现状态迁移 ,但策略模式则没有Context的引用
  • 具体的策略可以作为一个参数传递给使用它们的对象,比如说Collections.sort()接受一个Comparator,这是一个策略。另状态本身 是 Context对象的一部分,随着时间的迁移,Context对象会从一个状态迁移迁移到另一个状态下。
  • 尽管两种模式都遵循了开闭原则,策略模式还遵循了单一职责原则,因为每个策略都 封装的是独立 的算法,不同的策略独立于其它策略。改变一个策略并不会影响到另一个策略的实现。
  • 从理论上说,策略模式和状态模式还有一个不同,前者定义的是一个对象“如何”去做一件事情,比如说如何对数据进行排序,而另一方面,状态模式定义的是“什么”以及“何时“,比如说一个对象能做什么,某个时间点它处于哪个状态。
  • 状态的迁移顺序在状态模式中是定义好的,而策略模式则没有这样的要求。客户端可以随便选择使用哪个策略。
  • 常见的策略模式的例子都是封装算法,比如说排序算法,加密算法,或者压缩算法。如果你发现代码中需要使用到不同的算法,那么你可以考虑使用策略模式。而如果你需要管理状态进行状态间的迁移,而不希望嵌套许多条件语句,那么状态模式就是你的首选,因为它非常简单.
  • 最后也是最重要的一个区别在于,策略模式是由客户端进行处理的,而状态的改变Context或者State对象都可以进行。

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


推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • Søren Kierkegaard famously stated that life can only be understood in retrospect but must be lived moving forward. This perspective delves into the intricate relationship between our lived experiences and our reflections on them. ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 在 Windows 10 中,F1 至 F12 键默认设置为快捷功能键。本文将介绍几种有效方法来禁用这些快捷键,并恢复其标准功能键的作用。请注意,部分笔记本电脑的快捷键可能无法完全关闭。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
author-avatar
wujinlin74
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有