设计模式09-行为型模式2(状态模式/策略模式/Java)

news2024/12/27 8:17:36

5.4 状态模式

5.4.1 状态模式的定义

1.模式动机:有些对象具有多种状态,这些状态在某些情况下能够相互转换,对象在不同的状态下将具有不同的行为,将拥有状态的对象中和状态的行为分离。

2.模式定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类

5.4.2 状态模式的结构与分析

image-20241103155911551

  • 环境类是指拥有状态的对象,可以对状态进行切换。
  • 抽象状态类是具体状态类的父类,各状态的行为封装在具体的状态类中,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。
public abstract class State {
    public abstract void handle();
}

public class ConcreteState extends State{
    @Override
    public void handle() {

    }
}

public class Context {
    private State state;
    public void setState(State state) {
        this.state = state;
    }
    public void request() {
        state.handle();
    }
}
5.4.3 状态模式的案例

在某论坛系统中,用户可以发表留言,发表留言将增加积分;用户也可以回复留言,回复留言也将增加积分;用户还可以下载文件,下载文件将扣除积分。该系统用户分为三个等级,分别是新手、高手和专家,这三个等级对应三种不同的状态,这三种状态分别定义如下:

(1) 如果积分小于100分,则为新手状态,用户可以发表留言、回复留言,但是不能下载文件。如果积分大于等于1000分,则转换为专家状态;如果积分大于等于100分,则转换为高手状态。

(2) 如果积分大于等于100分但小于1000分,则为高手状态,用户可以发表留言、回复留言,还可以下载文件,而且用户在发表留言时可以获取双倍积分。积分小于100分,转换为新手状态;如果积分大于等于1000分,则转换为专家状态;如果下载文件后积分小于0,则不能下载该文件。

(3) 如果积分大于等于1000分,则为专家状态,用户可以发表留言、回复留言和下载文件,用户除了在发表留言时可以获取双倍积分外,下载文件只扣除所需积分的一半。积分小于100分,则转换为新手状态;积分小于1000分,但大于等于100,则转换为高手状态;如果下载文件后积分小于0,则不能下载该文件。

image-20241103165818020

由于上述类图将point放到了状态方面,不好理解,下面代码将point放到ForumAccount中

image-20241103170254317

public class ForumAccount {
    private String username;
    private State state;
    private int point;

    public ForumAccount(String username) {
        this.username = username;
        this.point = 0;
        this.state = new PrimaryState(this);
    }

    public void writeNote(int point) {
        state.writeNote(point);
    }
    public void replyNote(int point) {
        state.replyNote(point);
    }
    public void downloadNote(int point) {
        state.downloadNote(point);
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public State getState() {
        System.out.println(state.getStateName());
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public int getPoint() {
        return point;
    }

    public void setPoint(int point) {
        this.point = point;
    }

}
public abstract class State {
    protected ForumAccount forumAccount;
    protected String stateName;
    public State(ForumAccount forumAccount) {
        this.forumAccount = forumAccount;
    }
    public abstract void writeNote(int point);
    public abstract void replyNote(int point);
    public abstract void downloadNote(int point);
    public void updateState(int point) {
        if (point >= 1000) {
            forumAccount.setState(new HighState(forumAccount));
        } else if (point >= 100) {
            forumAccount.setState(new MiddleState(forumAccount));
        } else {
            forumAccount.setState(new PrimaryState(forumAccount));
        }
    }
    public String getStateName() {
        return stateName;
    }
}
public class PrimaryState extends State{
    public PrimaryState(ForumAccount forumAccount) {
        super(forumAccount);
        this.stateName = "新手级别";
    }

    @Override
    public void writeNote(int point) {
        System.out.println("新手版-写评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void replyNote(int point) {
        System.out.println("新手版-回复评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void downloadNote(int point) {
        System.out.println("新手状态-无法下载文件");
    }
}
public class MiddleState extends State{
    public MiddleState(ForumAccount forumAccount) {
        super(forumAccount);
        this.stateName = "高手级别";
    }

    @Override
    public void writeNote(int point) {
        System.out.println("高手版-写评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void replyNote(int point) {
        System.out.println("高手版-回复评论");
        forumAccount.setPoint(forumAccount.getPoint() + point * 2);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void downloadNote(int point) {
        if (point > forumAccount.getPoint()) {
            System.out.println("积分不足,不能下载");
        } else {
            System.out.println("高手版-下载文件");
            forumAccount.setPoint(forumAccount.getPoint() - point);
            updateState(forumAccount.getPoint());
        }
    }
}
public class HighState extends State {
    public HighState(ForumAccount forumAccount) {
        super(forumAccount);
        this.stateName = "专家级别";
    }

    @Override
    public void writeNote(int point) {
        System.out.println("专家版-写评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void replyNote(int point) {
        System.out.println("专家版-回复评论");
        forumAccount.setPoint(forumAccount.getPoint() + point * 2);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void downloadNote(int point) {
        if (point / 2 > forumAccount.getPoint()) {
            System.out.println("积分不足,不能下载");
        } else {
            System.out.println("专家版-下载文件");
            forumAccount.setPoint(forumAccount.getPoint() - point / 2);
            updateState(forumAccount.getPoint());
        }
    }
}
5.4.4 状态模式的优缺点
优点缺点
1.封装了状态的转换规则,可以对状态转换代码进行集中管理,而不是需要冗长的if-else判断1.会增加系统中类和对象的个数,导致系统运行开销增大
2.将所有与某个状态有关的行为放到一个类中,注入一个不同的状态对象即可使环境对象拥有不同行为2.结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱,增加系统设计的难度
3.允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块3.对开闭原则的支持并不太好
4.可让多个环境对象共享一个状态对象,从而减少系统中对象的个数
5.4.5 状态模式的适用场景
  • 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化

  • 在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强

5.5 策略模式

5.5.1 策略模式的定义

1.模式动机:解决某一问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便地更换算法或者增加新的算法。

2.模式定义:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。

5.5.2 策略模式的结构与分析

image-20241103171555824

  • 它将每一个算法封装在一个称为具体策略的类中,同时为其提供统一的抽象策略类,而使用这些算法完成某一业务功能的类称为环境类。

  • 策略模式实现了算法定义和算法使用的分离,它通过继承和多态的机制实现对算法族的使用和管理,是一种简单易用的对象行为型模式。

  • 各算法是由客户端决定的,不是策略模式自己决定的。

public abstract class Strategy {
    public abstract void algorithm();
}
public class ConcreteStrategy extends Strategy{
    @Override
    public void algorithm() {
    }
}
public class Context {
    private Strategy strategy;

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void request() {
        strategy.algorithm();
    }
}
5.5.3 策略模式的案例

image-20241103172356690

image-20241103172459035

public class Person {
    private String name;
    private TravelStrategy travelStrategy;
    public Person(String name) {
        this.name = name;
    }

    public void setTravelStrategy(TravelStrategy travelStrategy) {
        this.travelStrategy = travelStrategy;
    }

    public void travel() {
        System.out.print(this.name);
        travelStrategy.travel();
    }
}

public interface TravelStrategy {
    public void travel();
}

public class TrainStrategy implements TravelStrategy{
    @Override
    public void travel() {
        System.out.println("乘坐火车去旅行");
    }
}

public class Main {
    public static void main(String[] args) {
        TravelStrategy bean = (AirPlaneTravelStrategy) XMLUtil.getBean();
        Person person = new Person("xyx");
        person.setTravelStrategy(bean);
        person.travel();
    }
}
5.5.4 策略模式的优缺点
优点缺点
1.符合开闭原则,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类
2.提供了管理相关的算法族的办法,避免多重条件选择语句2.将造成系统产生很多具体策略类
3.提供了一种可以替换继承关系的办法3.无法同时在客户端使用多个策略类
5.5.5 策略模式的适用场景
  • 一个系统需要动态地在几种算法中选择一种

  • 避免使用难以维护的多重条件选择语句

  • 不希望客户端知道复杂的、与算法相关的数据结构,提高算法的保密性与安全性

5.5.6 状态模式和策略模式的对比
状态模式策略模式
环境类状态个数多个状态,可以相互转化存在一个状态,一旦选择不能随意改变
环境类与状态类关系若环境类会影响状态的改变,为双向关联关系单向的关联关系
客户端无需知道具体状态,会根据行为自动切换需要知道所选策略
行为各状态下有多个行为一个行为的多种实现方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2235227.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Postman上传图片如何处理

打开Postman,创建一个新的请求 URL: http://90.104.232.49:80/dev-api/appcommon/upload 如果有解密进入上传就在请求头添加 点击“Body”选项卡。 选择“form-data”类型。 在“KEY”列中输入文件字段的名称,例如file。 在“VALUE”列中&#xff0…

MongoDB笔记03-MongoDB索引

文章目录 一、前言1.1 概述1.2 MongoDB索引使用B-Tree还是BTree?1.3 B 树和 B 树的对比1.4 总结 二、索引的类型2.1 单字段索引2.2 复合索引2.3 其他索引 三、索引的管理操作3.1 索引的查看3.2 索引的创建3.2.1 单字段索引3.2.2 复合索引 3.3 索引的移除3.3.1 指定索…

MongoDB Shell 基本命令(三)聚合管道

管道含义 类似Linux中的管道,前一个命令的输出作为后一个命令的输入。 显示网络连接、路由表和网络接口统计信息 netstat -ano -netstat:network statistics 网络统计 -a:显示所有连接和监听端口,包括所有活动的TCP和UDP连接。 -n:以数字形式显示地址…

2024年10月国产数据库大事记-墨天轮

本文为墨天轮社区整理的2024年10月国产数据库大事件和重要产品发布消息。 目录 2024年10月国产数据库大事记 TOP102024年10月国产数据库大事记(时间线)产品/版本发布代表厂商大事记信创数据库上市公司2024年Q3财报 达梦数据:2024年前三季度…

SQL Server 日志记录

SQL Server是一个关系数据库管理系统(RDBMS),旨在有效地存储、组织、检索和操作大量结构化数据。SQL Server日志是监控数据库活动、排查问题和确保数据一致性的基础,这些日志记录了SQL Server实例中发生的事件的时间顺序。它们充当…

yolo v5 开源项目

项目地址:https://gitcode.net/EricLee/yolo_v5

队列详解

目录 队列队列的概念及结构队列的实现代码 队列功能的实现队列的尾插void QueuePush(Queue*pq, QDataType x);结构体封装指针typedef struct Queue总结 代码 队列的头删void QueuePop(Queue* pq)代码 队列的初始化void QueueInit(Queue* pq)代码 队列的销毁void QueueDestroy(Q…

ViT模型复现项目实战

项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…

是时候用开源降低AI落地门槛了

过去三十多年,从Linux到KVM,从OpenStack到Kubernetes,IT领域众多关键技术都来自开源。开源技术不仅大幅降低了IT成本,也降低了企业技术创新的门槛。 那么,在生成式AI时代,开源能够为AI带来什么?…

【C++打怪之路Lv13】- “继承“篇

🌈 个人主页:白子寰 🔥 分类专栏:重生之我在学Linux,C打怪之路,python从入门到精通,数据结构,C语言,C语言题集👈 希望得到您的订阅和支持~ 💡 坚持…

数据特征工程:如何计算Teager能量算子(TEO)? | 基于SQL实现

目录 0 TKEO能量算子 1 数据准备 2 特征求解 3 小结 0 TKEO能量算子 TEO(Teager能量算子),由Kaiser于1990年代提出的非线性分析方法(参见Kaiser, 1990; 1993),是一种有效的非线性信号处理工具,它能即时反映信号能量的变化。通过计算相邻采样点的值,TEO能够迅速跟…

淘宝/天猫探店大冒险:用taobao.item_search_shop API把宝贝一网打尽

想象一下,你是一位勇敢的探险家,手拿藏宝图(店铺ID),准备潜入神秘的淘宝/天猫店铺,寻找那些隐藏在角落里的宝贝。今天,我们要用taobao.item_search_shop API这张神奇的藏宝图,带你走…

D60【python 接口自动化学习】- python基础之数据库

day60 数据库定义 学习日期:20241106 学习目标:MySQL数据库-- 128:数据库定义 学习笔记: 无处不在的数据库 数据库如何存储数据 数据库管理系统(数据库软件) 数据库和SQL的关系 总结 数据库就是指数据…

2024年最佳解压软件推荐:轻松管理压缩文件的必备工具

在当今数字化时代,文件的传输和存储变得日益频繁,解压软件在文件管理中扮演着至关重要的角色。 随着数据量的不断增长,大文件的压缩和解压需求也越来越高。解压软件能够将大容量的文件压缩成较小的体积,便于存储和传输&#xff0…

Kubernetes的基本构建块和最小可调度单元pod-0

文章目录 一,什么是pod1.1pod在k8s中使用方法(1)使用方法一(2)使用方法二 1.2pod中容器的进程1.3pod的网络隔离管理(1)pause容器的作用 1.4 Pod分类:(1)自主式…

vue实现天地图电子围栏

一、文档 vue3 javascript WGS84、GCj02相互转换 天地图官方文档 注册登录然后申请应用key&#xff0c;通过CDN引入 <script src"http://api.tianditu.gov.cn/api?v4.0&tk您的密钥" type"text/javascript"></script>二、分析 所谓电子围…

QT 实现绘制汽车仪表盘

1.界面实现效果 以下是具体的项目需要用到的效果展示,通常需要使用QPainter类来绘制各种图形和文本,包括一个圆形的仪表盘、刻度、指针和数字。 2.简介 分为以下几个部分,首先设置抗锯齿 painter.setRenderHint(QPainter::Antialiasing)。 QPainter p(this);p.setRender…

【网络】传输层协议TCP(下)

目录 四次挥手状态变化 流量控制 PSH标记位 URG标记位 滑动窗口 快重传 拥塞控制 延迟应答 mtu TCP异常情况 四次挥手状态变化 之前我们讲了四次挥手的具体过程以及为什么要进行四次挥手&#xff0c;下面是四次挥手的状态变化 那么我们下面可以来验证一下CLOSE_WAIT这…

阿里云docker安装禅道记录

docker network ls docker network create -d bridge cl_network sudo docker run --name zentao --restart always -p 9982:80 --networkcl_network -v /data/zentao:/data -e MYSQL_INTERNALtrue -d hub.zentao.net/app/zentao:18.5 升级禅道 推荐用按照此文档升级&a…

迈入国际舞台,AORO M8防爆手机获国际IECEx、欧盟ATEX防爆认证

近日&#xff0c;深圳市遨游通讯设备有限公司&#xff08;以下简称“遨游通讯”&#xff09;旗下5G防爆手机——AORO M8&#xff0c;通过了CSA集团的严格测试和评估&#xff0c;荣获国际IECEx及欧盟ATEX防爆认证证书。2024年11月5日&#xff0c;CSA集团和遨游通讯双方领导在遨游…