首页 > 其他分享 >了解策略模式和状态模式,并理解二者差异

了解策略模式和状态模式,并理解二者差异

时间:2024-02-07 23:11:06浏览次数:26  
标签:状态 二者 策略 对象 差异 模式 行为 客户端

策略模式和状态模式的代码结构非常相似,其UML类图更是一致,容易让人困惑。究其原因,是没有理解两种模式的设计目的,以至于明明设计了状态模式的代码结构,仍以策略模式的形式使用这些代码。

策略模式

策略模式比较简单,分析应用类,将类中用于完成特定任务的不同操作抽离成一组独立的类,称之为策略类。

由于不同操作的是服务同一任务的,其功能是一致的,只是具体实现不同,我们将相同的功能抽象为策略接口,所有策略类都通过实现这些接口来实现具体的操作;当然也可以抽离为抽象类,实现一些相同的操作,只抽象那些不同的操作。

这时候原来的应用类,只需要使用一致的策略接口就能完成特定任务,不需要维护具体的策略及其实现。

在客户端使用该类的时候,根据需求传入与需求对应的策略对象即可。在新增需求时,只需要新增对应的策略实现就能完成拓展,无需修改应用类和既有的策略类。

状态模式

状态模式的目的是让一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。

那些适用状态模式的对象,其操作所发生的行为由当前状态决定,且行为的发生可能会使对象的状态从当前状态转移到另一种状态。这就是有限状态机的概念。

简单地实现一个状态机,我们可能会使用 if/elseswitch/case 这样的条件运算符来判断状态、切换行为、转换状态。但是这会随着功能的膨胀使得代码难以维护。

状态的多寡与状态对应的行为会根据客户端需求的变化而变化,这也是造成代码维护困难的原因,将其分离出来即可解决。

策略模式建议将对象所有可能的状态都新建一个类,然后将状态所对应的行为抽离到该状态对应的类中。

状态模式包含以下主要角色:

  1. 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
  2. 抽象状态(State)角色:定义一个接口或抽象类,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
  3. 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下通过持有环境类对象的引用来进行状态切换。

通过将原始对象中的的状态和状态对应的行为进行抽离,改写其所属的类,我们得到了环境类角色;
抽离的状态类实现了与其状态对应的行为,它们就是具体状态角色。
为了实现在环境类对象中对当前状态实现转换以对应不同的具体状态对象,需要对具体的状态类进一步抽离,将行为的定义抽离出来,作为一个接口(或者抽象类),所有具体状态类都通过实现该接口(或继承抽象类)来实现具体的行为。这个抽离出来的接口就是抽象状态角色。

环境类角色只需要定义供客户端使用的功能接口,并维护自身状态,不需要关心状态对应的具体行为,而是将所有与状态相关的工作都委派给该状态对象。

当我们需要拓展状态时,就新增一个状态类;当特定状态的行为发生改动时,只需要修改对应的状态类。环境类不需要进行改动。

但是,状态模式的弊端也很明显,它使类变多了。如果只是维护既有功能,它确实让代码变得清晰明了,易于维护。但是当我们的环境类新增了功能,且新增的功能受状态影响,那我们不得不修改抽象状态接口和所有的具体状态类。

理解策略模式与状态模式的区别

二者的代码组织方式非常相似,都有环境类,而代表行为的策略接口、策略类以及状态接口、状态类更是一一对应。但是其核心区别在于环境类与行为、行为与行为之间的关系。

虽然两种模式中的行为都发生在环境对象中,但是策略模式是由客户端指定策略对象来决定环境对象的行为,客户端对具体行为是有感知的,而环境类对具体的行为是没有感知的

而在状态模式中,状态的变化决定了行为的变化,而状态对象是环境对象的一部分,那么环境对象的行为就是由其自身决定的,环境类对具体的行为是有感知的

虽然状态模式并未规定在哪里定义初始状态、在哪里转换状态。但是我觉得为了解耦,客户端不应对环境对象进行任何状态对象的注入操作;初始的状态应在环境类内部创建并定义,而状态的转换可以在环境类或状态类中进行操作。

客户端调用环境类对象的功能接口,可能间接地导致环境类对象内部状态的转换,但客户端对这些事的发生是没有感知的。

也就是说状态模式下,客户端对具体的行为不应有感知

如果非要在客户端进行状态的转换,这时候状态就变成了策略。不能理解状态和环境是一个整体,写出来的状态模式的代码就和策略模式一样了。

标签:状态,二者,策略,对象,差异,模式,行为,客户端
From: https://www.cnblogs.com/chaihuibin/p/18011456

相关文章

  • Python实现软件设计模式9:组合模式 Composite Pattern
    动机如何将容器和叶子进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器和叶子?典型案例如:文件系统,在树形目录结构中,包含文件和文件夹两类不同的元素;在文件夹中可以继续包含文件或子文件夹,在文件中不能再包含子文件或者子文件夹。概念组合多个对象形成树形......
  • TypeScript 设计模式之发布订阅者模式
    订阅发布模式(Publish-SubscribePattern)是一种行之有效的解耦框架与业务逻辑的方式,也是一种常见的观察者设计模式,它被广泛应用于事件驱动架构中。在这个模式中,发布者(或者说是主题)并不直接发送消息给订阅者,而是通过调度中心(或者叫消息代理)来传递消息。发布者(或者说是主题)并不知道订......
  • 【设计模式】建造者模式——OkHttp源码中的建造者模式
    OkHttp源码中的建造者模式之所以有必要单独拿出来讲,是因为OkHttp3.x和4.x分别用Java语言和Kotlin语言写的,所以需要做一个对比分析。在OkHttp的源码中搜索“Builder”,可以看到OkHttp的OkHttpClient、Request和Response等很多类的代码里包含名为Builder的子类,这些都是建造者模式的应......
  • 分布式事务(六):Seata之AT模式原理
    1、整体机制SeataAT模型,基于本地ACID事务的关系型数据库实现。两阶段提交协议机制如下:一阶段:业务数据和回滚日志在同一个本地事务中提交,释放本地锁和连接资源二阶段:提交异步化,非常快速地完成;回滚通过一阶段的回滚日志进行反向补偿2、事务状态global_table......
  • 分布式事务(四):Seata之Saga事务模式原理
    Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。  Seata2.x提供的Saga是基于状态机引擎实现的,下面来看看状态机引擎。1、状态机......
  • 分布式事务(五):Seata之XA事务模式原理
    1、XA事务模式概述XA事务模式是在Seata定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对XA协议的支持,以XA协议的机制来管理分支事务的一种事务模式。 1.1、执行阶段可回滚:业务SQL操作放在XA分支中进行,由资源对XA协议的支持来保证可回滚持......
  • 分布式事务(三):Seata之TCC事务模式原理
    TCC模式是Seata支持的一种由业务方细粒度控制的侵入式分布式事务解决方案,是继AT模式后第二种支持的事务模式。其分布式事务模型直接作用于服务层,不依赖底层数据库,可以灵活选择业务资源的锁定粒度,减少资源锁持有时间,可扩展性好,是为独立部署的SOA服务而设计的。TCC......
  • 设计模式:适配器模式
    设计模式是通用的、可复用的代码设计方案,也可以说是针对某类问题的解决方案,因此,掌握好设计模式,可以帮助我们编写更健壮的代码。wiki中将设计模式分为四类,分别是:创建模式(creationalpatterns)结构模式(structuralpatterns)行为模式(behavioralpatterns)并发模式(concurrencypatt......
  • 互联网医院|互联网医院系统创新诊疗模式
    互联网医院,看似简单却隐藏着复杂的操作。想要在线上开展合法合规的诊疗业务,并非易事。有三个关键要素不可少:一是符合当地政策要求的线下实体医疗机构;二是合法合规的互联网医院系统;三是通过申办获得的互联网医院牌照。互联网医院牌照申办费用实际上包括了线下实体医疗机构建设和互联......
  • 软件架构模式系列:0. 导航
     写在前面:春节放假,闲着无聊,发现了一本好书《Softwarearchitecturepatterns》的第二版。越看越觉得有意思,索性全部翻译出来。作者是Mark Richards,大师级人物,相信很多同学都有所耳闻。1. 如果喜欢看英文原版的同学,直接去看原版。也欢迎各位同学看完原文之后回来交流。2. ......