整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

SSM订单智慧管理系统-使用手册.pdf

、简介

1.1、开发目的和背景


随着电子商务的快速发展,企业对订单管理的需求日益增长,传统的手动操作方式已经无法满足现代化企业高效、精准、智能的运营需求。为此,我们推出了这款专为中小型企业量身打造的SSM订单智慧管理系统。其核心目标是通过集成先进的信息技术,简化业务流程,提升运营效率,降低管理成本,同时提供全方位的客户服务支持。


在当今数字化时代,企业间的竞争已从产品和价格转向服务和体验。对于订单管理,企业不仅需要处理大量的日常交易,还需要实时跟踪订单状态,有效管理库存,快速响应客户查询,以及生成准确的财务报表。然而,传统系统往往过于复杂,操作繁琐,难以适应这种变化。


SSM订单智慧管理系统正是为解决这一问题而设计。它以用户友好和易用性为核心,将多个关键业务环节如订单创建、处理、发货、支付、发票开具等整合在一个平台上,实现了信息的无缝流转和共享。此外,强大的数据分析功能可以帮助企业进行精细化运营,通过对历史数据的深入挖掘,预测销售趋势,制定更有效的营销策略。


在支持中心模块,我们提供了详细的操作指南和常见问题解答,确保用户能够快速上手并解决问题。财务报表管理模块则能自动生成精确的报表,帮助企业做出明智的决策。无论是内部运营管理还是外部客户服务,SSM都力求为用户提供一站式的解决方案。


总之,SSM订单智慧管理系统旨在通过技术创新,帮助企业提升竞争力,实现数字化转型,从而在激烈的市场竞争中立于不败之地。

1.2、软件的目标用户


SSM订单智慧管理系统是一款专为电商、零售和服务业设计的全面解决方案,它旨在帮助企业提升运营效率,优化客户服务,并实现数据驱动的决策。以下是该软件的应用场景和目标用户的描述:


1. 在日常运营中,帮助企业管理员工快速响应客户需求,通过帮助中心提供即时解答,节省大量客服时间。


2. 财务报表管理模块可以帮助财务人员实时跟踪收入和支出,以便进行有效的成本控制和预算规划。


3. 订单管理模块能自动化处理订单流程,从接收到发货全程跟踪,降低出错率,提高客户满意度。


4. 通过库存管理和商品管理,企业能够实时了解销售情况,避免断货或过度库存的风险。


- 中小型电商平台和零售商,他们需要一个集成的平台来简化操作流程,提升工作效率。


- 需要高效管理订单、财务、库存的零售企业,特别是那些面临快速扩张或频繁促销活动的企业。


- 对数据可视化和分析有需求的企业,他们可以利用统计分析功能进行业务洞察和策略调整。


- 服务型企业,如餐饮、美容院等,可通过系统管理客户信息,提供个性化的服务体验。


这款软件的目标用户是寻求数字化转型,希望通过技术驱动业务增长,提升客户体验并降低成本的企业决策者和技术团队。无论是新手还是经验丰富的用户,SSM订单智慧管理系统都能提供直观易用的界面和强大功能支持。

二、软件总体设计

2.1、系统概述


ssm订单智慧管理系统是一款高效整合的商业智能工具,专为现代企业打造,主要利用Java编程语言和SpringMVC开发框架构建而成,数据库采用业界广泛认可的MySQL。该系统集成了多种关键业务模块,旨在提升企业的运营效率和管理水平。


1. 帮助中心:提供详尽的操作指南和常见问题解答,让用户快速上手和解决问题。


2. 财务报表管理:生成各种财务报告,如收入、支出、利润等,帮助管理者实时掌握财务状况。


3. 订单管理:实时跟踪订单状态,包括创建、处理、发货和退款等全过程,确保流程透明。


4. 发票管理:自动化发票开具与管理,简化发票流程,降低出错风险。


5. 活动管理:支持促销活动策划与执行,帮助企业提高销售转化率。


6. 积分管理:设计激励体系,通过积分制度增强用户黏性。


7. 技术支持:为用户提供专业的技术咨询与维护服务,确保系统的稳定运行。


8. 客服管理:集成客户关系管理系统,便于团队协作处理客户咨询与投诉。


9. 库存管理:实时监控库存水平,预警低库存,防止断货风险。


10. 商品管理:方便添加、编辑和删除商品信息,维护商品目录。


11. 收货地址管理:便捷管理用户的收货地址,提高配送效率。


12. 统计分析:提供数据可视化图表,帮助企业洞察业务趋势,做出数据驱动的决策。


13. 推广管理:支持多渠道营销活动,优化营销策略。


14. 退款管理:清晰的退款流程,减少纠纷,提升用户满意度。


15. 物流管理:无缝对接第三方物流公司,实时更新物流信息。


16. 消息管理:集成推送通知,确保重要信息不被遗漏。


17. 用户管理:全面管理用户账户,权限设置灵活。


18. 优惠券管理:支持多种类型的优惠券发放,促进消费。


总之,ssm订单智慧管理系统是一款全方位的企业管理解决方案,通过集成化的功能设计,旨在简化复杂业务操作,实现业务流程的自动化,助力企业实现数字化转型和高效运营。

2.2、系统架构


SSM订单智慧管理系统是一款基于Java+Spring MVC的B/S架构的全面企业管理软件。该架构设计的核心思想是将业务逻辑与表示层分离,以提高代码复用性和系统的可维护性。


1. 前端界面(B/S):采用浏览器/服务器模式,用户通过Web浏览器访问,无需安装任何客户端软件。前端使用HTML、CSS和JavaScript技术构建,提供直观、用户友好的图形用户界面,展示各种功能模块,如订单、发票、库存等信息。


2. Spring MVC:作为核心框架,Spring MVC实现了模型-视图-控制器(Model-View-Controller,MVC)的设计模式。控制器处理用户的请求,调用服务层的业务逻辑,视图负责数据的呈现,模型则存储和管理数据。这种设计使代码结构清晰,易于理解和扩展。


3. Java后端:选用Java语言,因其强大的面向对象特性和丰富的库支持。Java后台处理复杂的业务逻辑,调用持久层(DAO)操作数据库,实现数据的增删改查和事务管理。


4. 持久层(DAO)与数据访问(JPA):通常使用Java Persistence API (JPA) 或 Hibernate等ORM工具,与关系型数据库(如MySQL、Oracle)进行交互,提供数据的持久化和事务支持。


5. 服务层(Service):作为业务逻辑的处理中心,封装和抽象了底层数据访问层,提供对外的接口,使得代码更加模块化,便于单元测试和维护。


6. 分布式组件:考虑到系统的扩展性和高可用性,可能涉及分布式缓存(Redis)、消息队列(RabbitMQ)、负载均衡(Nginx)等,以实现异步处理、数据分发等功能。


7. 安全性:通过Spring Security进行权限管理和身份验证,确保敏感数据的安全。同时,采用HTTPS加密通信,保护数据传输过程中的隐私。


8. 统计分析与报告:系统内置的数据分析模块,能生成各种报表,帮助企业管理人员做出决策。


综上所述,SSM订单智慧管理系统的架构设计旨在提供一个高效、稳定、可扩展的平台,以满足企业对订单管理、财务管理等多方面的自动化需求。

三、软件操作说明

3.1、系统登录


在浏览器中输入系统网址,打开登录界面后输入登录账号、登录密码、验证码即可登录。

3.2、工作台


工作台包含:帮助中心、财务报表管理、订单管理、发票管理、活动管理、积分管理、技术支持、客服管理、库存管理、商品管理、收货地址管理、统计分析、推广管理、退款管理、物流管理、消息管理、用户管理、优惠券管理,根据不同角色权限菜单展示会有所区别。

3.2.1、帮助中心


帮助中心管理功能主要字段信息包含:编码、问题ID、问题标题、问题描述、问题解答、问题类型、热门问题等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行帮助中心信息的管理。


帮助中心管理设置新增、编辑、删除、条件搜索、查看详情等操作,可按照页面提示进行操作执行,界面结构设计简单,操作流程简洁明了,可提升用户操作体验。

3.2.2、财务报表管理


管理管理功能主要字段信息包含:管理编码、报表ID、报表名称、报表类型、报表时间、报表状态、报表内容等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


系统为管理管理提供了全面支持,包括新增记录、编辑信息、删除条目、数据导出、条件检索及详情查看等功能。用户只需遵循页面清晰的操作指引,即可轻松完成各项任务。界面设计遵循极简原则,布局直观,交互流畅,旨在营造无负担的操作环境,显著提升用户的使用体验与工作效率。

3.2.3、订单管理


管理管理功能主要字段信息包含:管理编码、订单号、订单时间、订单金额、收货人、收货地址、联系电话等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


针对管理管理,系统精心设置了全方位功能模块,涵盖新增、编辑、删除、导出、条件检索以及查看详情等核心操作。用户在使用过程中,仅需紧密跟随页面内直观且详尽的操作提示,即可轻松驾驭各项流程。我们秉持化繁为简的理念,打造出简约明快的界面风格与逻辑清晰的操作流程,旨在让用户在高效管理数据,享受到愉悦、无压力的操作体验。

3.2.4、发票管理


管理管理功能主要字段信息包含:管理编码、订单号、发票抬头、开票金额、开票时间、开票状态等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


为实现对管理管理,系统精心配备了丰富的功能组件,包括新增、编辑、删除、导出、条件搜以及详情查看等实用操作。用户在操作过程中,只需遵循页面上清晰易懂的引导提示,即可顺畅地完成各项任务。我们注重用户体验,以简约而不失专业的界面设计,辅以直观且高效的流程布局,旨在助力用户在轻松管理数据同时,全面提升操作满意度与工作效率。

3.2.5、活动管理


管理管理功能主要字段信息包含:管理编码、活动ID、活动名称、活动时间、活动描述、参与条件、活动奖品等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


为满足管理管理的多元需求,系统配置了一系列操作功能:新增、编辑、删除、导出、搜索、详情。用户在实际操作中,仅需按照页面上直观且详尽的操作提示,即可轻松驾驭各项流程。系统界面设计简约清爽,操作逻辑清晰明了,旨在让用户在高效管理数据的同时,尽享流畅、无压力的操作体验,大幅提升工作效率与满意度。

3.2.6、积分管理


管理管理功能主要字段信息包含:管理编码、用户ID、积分来源、积分值、积分变动时间、积分使用记录等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


管理管理设置新增、编辑、删除、条件搜索、查看详情等操作,可按照页面提示进行操作执行,界面结构设计简单,操作流程简洁明了,可提升用户操作体验。

3.2.7、技术支持


技术支持管理功能主要字段信息包含:编码、技术支持ID、技术支持名称、技术支持邮箱、技术支持电话、技术支持状态等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行技术支持信息的管理。


系统为技术支持管理提供了全面支持,包括新增记录、编辑信息、删除条目、数据导出、条件检索及详情查看等功能。用户只需遵循页面清晰的操作指引,即可轻松完成各项任务。界面设计遵循极简原则,布局直观,交互流畅,旨在营造无负担的操作环境,显著提升用户的使用体验与工作效率。

3.2.8、客服管理


管理管理功能主要字段信息包含:管理编码、客服ID、客服姓名、客服电话、客服邮箱、客服状态等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


针对管理管理,系统精心设置了全方位功能模块,涵盖新增、编辑、删除、导出、条件检索以及查看详情等核心操作。用户在使用过程中,仅需紧密跟随页面内直观且详尽的操作提示,即可轻松驾驭各项流程。我们秉持化繁为简的理念,打造出简约明快的界面风格与逻辑清晰的操作流程,旨在让用户在高效管理数据,享受到愉悦、无压力的操作体验。

3.2.9、库存管理


管理管理功能主要字段信息包含:管理编码、商品ID、进货单号、进货时间、进货数量、进货单价、库存数量等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


为实现对管理管理,系统精心配备了丰富的功能组件,包括新增、编辑、删除、导出、条件搜以及详情查看等实用操作。用户在操作过程中,只需遵循页面上清晰易懂的引导提示,即可顺畅地完成各项任务。我们注重用户体验,以简约而不失专业的界面设计,辅以直观且高效的流程布局,旨在助力用户在轻松管理数据同时,全面提升操作满意度与工作效率。

3.2.10、商品管理


管理管理功能主要字段信息包含:管理编码、商品ID、商品名称、商品图片、商品描述、商品价格、库存量等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


为满足管理管理的多元需求,系统配置了一系列操作功能:新增、编辑、删除、导出、搜索、详情。用户在实际操作中,仅需按照页面上直观且详尽的操作提示,即可轻松驾驭各项流程。系统界面设计简约清爽,操作逻辑清晰明了,旨在让用户在高效管理数据的同时,尽享流畅、无压力的操作体验,大幅提升工作效率与满意度。

3.2.11、收货地址管理


管理管理功能主要字段信息包含:管理编码、用户ID、收货人、收货地址、联系电话、是否默认地址等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


管理管理设置新增、编辑、删除、条件搜索、查看详情等操作,可按照页面提示进行操作执行,界面结构设计简单,操作流程简洁明了,可提升用户操作体验。

3.2.12、统计分析


统计分析管理功能主要字段信息包含:编码、订单量、销售额、用户量、用户留存率、商品销售排行榜等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行统计分析信息的管理。


系统为统计分析管理提供了全面支持,包括新增记录、编辑信息、删除条目、数据导出、条件检索及详情查看等功能。用户只需遵循页面清晰的操作指引,即可轻松完成各项任务。界面设计遵循极简原则,布局直观,交互流畅,旨在营造无负担的操作环境,显著提升用户的使用体验与工作效率。

3.2.13、推广管理


管理管理功能主要字段信息包含:管理编码、推广ID、推广渠道、推广链接、注册量、下单量、成交金额等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


针对管理管理,系统精心设置了全方位功能模块,涵盖新增、编辑、删除、导出、条件检索以及查看详情等核心操作。用户在使用过程中,仅需紧密跟随页面内直观且详尽的操作提示,即可轻松驾驭各项流程。我们秉持化繁为简的理念,打造出简约明快的界面风格与逻辑清晰的操作流程,旨在让用户在高效管理数据,享受到愉悦、无压力的操作体验。

3.2.14、退款管理


管理管理功能主要字段信息包含:管理编码、订单号、退款原因、退款金额、退款时间、退款状态、退款处理人员等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


为实现对管理管理,系统精心配备了丰富的功能组件,包括新增、编辑、删除、导出、条件搜以及详情查看等实用操作。用户在操作过程中,只需遵循页面上清晰易懂的引导提示,即可顺畅地完成各项任务。我们注重用户体验,以简约而不失专业的界面设计,辅以直观且高效的流程布局,旨在助力用户在轻松管理数据同时,全面提升操作满意度与工作效率。

3.2.15、物流管理


管理管理功能主要字段信息包含:管理编码、物流公司、物流单号、运费、发货时间、收货时间、发货地址、收货地址等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


为满足管理管理的多元需求,系统配置了一系列操作功能:新增、编辑、删除、导出、搜索、详情。用户在实际操作中,仅需按照页面上直观且详尽的操作提示,即可轻松驾驭各项流程。系统界面设计简约清爽,操作逻辑清晰明了,旨在让用户在高效管理数据的同时,尽享流畅、无压力的操作体验,大幅提升工作效率与满意度。

3.2.16、消息管理


管理管理功能主要字段信息包含:管理编码、消息ID、消息类型、消息内容、接收者、发送时间、消息状态等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


管理管理设置新增、编辑、删除、条件搜索、查看详情等操作,可按照页面提示进行操作执行,界面结构设计简单,操作流程简洁明了,可提升用户操作体验。

3.2.17、用户管理


管理管理功能主要字段信息包含:管理编码、用户ID、用户名、密码、角色、邮箱、电话、状态等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


系统为管理管理提供了全面支持,包括新增记录、编辑信息、删除条目、数据导出、条件检索及详情查看等功能。用户只需遵循页面清晰的操作指引,即可轻松完成各项任务。界面设计遵循极简原则,布局直观,交互流畅,旨在营造无负担的操作环境,显著提升用户的使用体验与工作效率。

3.2.18、优惠券管理


管理管理功能主要字段信息包含:管理编码、优惠券ID、优惠券名称、优惠方式、使用条件、使用时间、使用范围、发放数量等。使用表格形式展示这些信息,方便用户查看和编辑,方便用户进行管理信息的管理。


针对管理管理,系统精心设置了全方位功能模块,涵盖新增、编辑、删除、导出、条件检索以及查看详情等核心操作。用户在使用过程中,仅需紧密跟随页面内直观且详尽的操作提示,即可轻松驾驭各项流程。我们秉持化繁为简的理念,打造出简约明快的界面风格与逻辑清晰的操作流程,旨在让用户在高效管理数据,享受到愉悦、无压力的操作体验。

四、注意事项


系统支持唯一登录,一个账号同时只能由一人使用。信息展示顺序如果特殊说明,按照排序索引值从大到小进行排序。数据删除之后,其关联的数据将不可用使用,或无法正常显示。内容状态一般为正常时,表示数据可正常使用操作,如果为异常或者未审核,则表示在关联数据调用时,不会显示。

态机简介:

状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。【规则的抽象】

有限状态机一般都有以下特点:

(1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态;

(2)事物拥有的状态总数是有限的;

(3)通过触发事物的某些行为,可以导致事物从一种状态过渡到另一种状态;

(4)事物状态变化是有规则的,A状态可以变换到B,B可以变换到C,A却不一定能变换到C;

(5)同一种行为,可以将事物从多种状态变成同种状态,但是不能从同种状态变成多种状态。

状态机这种描述客观世界的方式就是将事物抽象成若干状态,然后所有的事件和规则导致事物在这些状态中游走。最终使得事物“自圆其说”。

很多通信协议的开发都必须用到状态机;一个健壮的状态机可以让你的程序,不论发生何种突发事件都不会突然进入一个不可预知的程序分支。

  • 状态机示例:

四大概念:


状态(state)

一个状态机至少要包含两个状态。

分为:现态(源状态)、次态(目标状态)

状态可以理解为一种结果,一种稳态形式,没有扰动会保持不变的。

状态命名形式:

1.副词+动词;例如:待审批、待支付、待收货

这种命名方式体现了:状态机就是事件触发状态不断迁徙的本质。表达一种待触发的感觉。

2.动词+结果;例如:审批完成、支付完成

3.已+动词形式;例如:已发货、已付款

以上两种命名方式体现了:状态是一种结果或者稳态的本质。表达了一种已完成的感觉。

角色很多的时候,为了表示清晰,可以加上角色名:例如:待财务审批、主管批准

命名考虑从用户的理解的角度出发。



事件(event)

or

触发条件

又称为“条件”,就是某个操作动作的触发条件或者口令。当一个条件满足时,就会触发一个动作,或者执行一次状态迁徙

这个事件可以是外部调用、监听到消息、或者各种定时到期等触发的事件。

对于灯泡,“打开开关”就是一个事件。

条件命名形式:动词+结果;例如:支付成功、下单时间>5分钟


动作(action)

事件发生以后要执行动作。例如:事件=“打开开关指令”,动作=“开灯”。一般就对应一个函数。

条件满足后执行动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。

动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

那么如何区分“动作”和“状态”?

“动作”是不稳定的,即使没有条件的触发,“动作”一旦执行完毕就结束了;

而“状态”是相对稳定的,如果没有外部条件的触发,一个状态会一直持续下去。


变换(transition)

即从一个状态变化到另外一个状态

例如:“开灯过程”就是一个变化



状态机其他表达方式:

状态机的设计:

信息系统中有很多状态机,例如:业务订单的状态。

状态机的设计存在的问题:什么是状态?到底有多少个状态?要细分到什么程度?

  信息系统是现实世界的一种抽象和描述。而业务领域中那些已经发生的事件就是事实信息系统就是将这些事实以信息的形式存储到数据库中,即:信息就是一组事实

信息系统就是存储这些事实,对这些事实进行管理与追踪,进而起到提高工作效率的作用。

信息系统就是记录已经发生的事实,信息系统中的状态基本和事实匹配。即:标识某个事实的完成度。

业务系统,根据实际业务,具体会有哪些发生的事实需要记录,基本上这些事实就至少对应一个状态。需要记录的事实就是一种稳态,一种结果。

例如:【待支付】->【已支付】->【已收货】->【已评价】

这些都是系统需要记录的已发生的客观事实。而这些事实就对应了状态,而发生这些事实的事件就对应了触发状态机的转换的事件。

根据自己的业务实际进行分析,并画出状态图即可。

状态机实现方式:状态模式

下面是经典的自动贩卖机例子来说明状态模式的用法,状态图如下:

分析一个这个状态图:

a、包含4个状态(我们使用4个int型常量来表示)
b、包含3个暴露在外的方法(投币、退币、转动手柄、(发货动作是内部方法,售卖机未对外提供方法,售卖机自动调用))
c、我们需要处理每个状态下,用户都可以触发这三个动作。

我们可以做没有意义的事情,在【未投币】状态,试着退币,或者同时投币两枚,此时机器会提示我们不能这么做。


实现逻辑:

    任何一个可能的动作,我们都要检查,看看我们所处的状态和动作是否合适。

状态机使用if-else或switch实现

测试自动售卖机

使用if-else/switch的方式实现状态有如下问题:

  • 没有遵守【开闭】原则,没有【封装变化】,所以没有弹性,应对需求变更非常吃力。

   例如:现在增加一个状态。每个方法都需要添加if-else语句。

  • 状态如何转换看得不是很清楚,隐藏在if-else/switch逻辑中。

升级策略:

【封装变化】,局部化每个状态的行为,将每个状态的行为放到各自类中,每个状态只要实现自己的动作就可以了。

贩卖机只要将动作委托给代表当前状态的状态对象即可。


public interface State
{
    /**
     * 放钱
     */
    public void insertMoney();
    /**
     * 退钱
     */
    public void backMoney();
    /**
     * 转动曲柄
     */
    public void turnCrank();
    /**
     * 出商品
     */
    public void dispense();
}
public class NoMoneyState implements State
{
 
    private VendingMachine machine;
 
    public NoMoneyState(VendingMachine machine)
    {
        this.machine = machine;
        
    }
    
    @Override
    public void insertMoney()
    {
        System.out.println("投币成功");
        machine.setState(machine.getHasMoneyState());
    }
 
    @Override
    public void backMoney()
    {
        System.out.println("您未投币,想退钱?...");
    }
 
    @Override
    public void turnCrank()
    {
        System.out.println("您未投币,想拿东西么?...");
    }
 
    @Override
    public void dispense()
    {
        throw new IllegalStateException("非法状态!");
    }
 
}
public class HasMoneyState implements State
{
 
    private VendingMachine machine;
 
    public HasMoneyState(VendingMachine machine)
    {
        this.machine = machine;
    }
 
    @Override
    public void insertMoney()
    {
        System.out.println("您已经投过币了,无需再投....");
    }
 
    @Override
    public void backMoney()
    {
        System.out.println("退币成功");
            machine.setState(machine.getNoMoneyState());
    }
 
    @Override
    public void turnCrank()
    {
        System.out.println("你转动了手柄");
        machine.setState(machine.getSoldState());
    }
 
    @Override
    public void dispense()
    {
        throw new IllegalStateException("非法状态!");
    }
 
}
    
public class SoldOutState implements State
{
 
    private VendingMachine machine;
 
    public SoldOutState(VendingMachine machine)
    {
        this.machine = machine;
    }
 
    @Override
    public void insertMoney()
    {
        System.out.println("投币失败,商品已售罄");
    }
 
    @Override
    public void backMoney()
    {
        System.out.println("您未投币,想退钱么?...");
    }
 
    @Override
    public void turnCrank()
    {
        System.out.println("商品售罄,转动手柄也木有用");
    }
 
    @Override
    public void dispense()
    {
        throw new IllegalStateException("非法状态!");
    }
 
}
public class SoldState implements State
{
 
    private VendingMachine machine;
 
    public SoldState(VendingMachine machine)
    {
        this.machine = machine;
    }
 
    @Override
    public void insertMoney()
    {
        System.out.println("正在出货,请勿投币");
    }
 
    @Override
    public void backMoney()
    {
        System.out.println("正在出货,没有可退的钱");
    }
 
    @Override
    public void turnCrank()
    {
        System.out.println("正在出货,请勿重复转动手柄");
    }
 
    @Override
    public void dispense()
    {
        machine.releaseBall();
        if (machine.getCount() > 0)
        {
            machine.setState(machine.getNoMoneyState());
        } else
        {
            System.out.println("商品已经售罄");
            machine.setState(machine.getSoldOutState());
        }
    }
}
public class VendingMachine
{
    private State noMoneyState;
    private State hasMoneyState;
    private State soldState;
    private State soldOutState;
    private State winnerState ; 


    private int count = 0;
    private State currentState = noMoneyState;
 
    public VendingMachine(int count)
    {
        noMoneyState = new NoMoneyState(this);
        hasMoneyState = new HasMoneyState(this);
        soldState = new SoldState(this);
        soldOutState = new SoldOutState(this);
        winnerState = new WinnerState(this);
 
              if (count > 0)
             {
            this.count = count;
            currentState = noMoneyState;
             }
    }
 
       //将这些动作委托给当前状态.
    public void insertMoney()
    {
        currentState.insertMoney();
    }
 
    public void backMoney()
    {
        currentState.backMoney();
    }
       
        // 机器不用提供dispense动作,因为这是一个内部动作.用户不可以直 
        //接要求机器发放糖果.我们在状态对象的turnCrank()方法中调用 
        //dispense方法;

       //dispense无论如何,即使在nomoney状态也会被执行.
       //让不合法的情形下,dispense抛出异常处理。
    public void turnCrank()
    {
        currentState.turnCrank();
            currentState.dispense();
    }
 

    public void releaseBall()
    {
        System.out.println("发出一件商品...");
        if (count != 0)
        {
            count -= 1;
        }
    }
 
    public void setState(State state)
    {
        this.currentState = state;
    }
 
    //getter setter omitted ...
 
}

我们之前说过,if-else/switch实现方式没有弹性,那现在按照这种实现模式,需求变更修改起来会轻松点吗?

红色部分标记了我们的需求变更:当用户每次转动手柄的时候,有10%的几率赠送一瓶。

实现方式:

我们遵守了【开闭】原则,只要新建一个WinnerState的类即可。然后有限的修改has_money的转向即可。

为什么WinnerState要独立成一个状态,其实它和sold状态一模一样。我把代码写在SoldState中不行吗?

  • 第一个原因就是上面说的信息系统的本质就是记录【事实】,中奖是需要记录的事实,它应该是一个状态。
  • 第二个原因:【单一职责】问题,我们一个类的责任是明确的。

   如果sold需求变化不一定影响到winner代码实现,winner需求变化时,也不一定要修改sold,比如促销方案结束了,中奖概率变了等。

   如果他们的变化不是一定互相影响到彼此的,那我们就该将他们分离,即是【隔离变化】也是遵守【单一职责】的原则。


public class WinnerState implements State
{
 
    private VendingMachine machine;
 
    public WinnerState(VendingMachine machine)
    {
        this.machine = machine;
    }
 
    @Override
    public void insertMoney()
    {
        throw new IllegalStateException("非法状态");
    }
 
    @Override
    public void backMoney()
    {
        throw new IllegalStateException("非法状态");
    }
 
    @Override
    public void turnCrank()
    {
        throw new IllegalStateException("非法状态");
    }
 
    @Override
    public void dispense()
    {
        System.out.println("你中奖了,恭喜你,将得到2件商品");
        machine.releaseBall();
 
    if (machine.getCount() == 0)
    {
        System.out.println("商品已经售罄");
        machine.setState(machine.getSoldOutState());
    } else
    {
        machine.releaseBall();
        if (machine.getCount() > 0)
        {
            machine.setState(machine.getNoMoneyState());
        } else
        {
            System.out.println("商品已经售罄");
            machine.setState(machine.getSoldOutState());
        }
        
    }
 
    }
 
}
public class HasMoneyState implements State
{
 
    private VendingMachine machine;
    private Random random = new Random();
 
    public HasMoneyState(VendingMachine machine)
    {
        this.machine = machine;
    }
 
    @Override
    public void insertMoney()
    {
        System.out.println("您已经投过币了,无需再投....");
    }
 
    @Override
    public void backMoney()
    {
        System.out.println("退币成功");
 
    machine.setState(machine.getNoMoneyState());
    }
 
    @Override
    public void turnCrank()
    {
        System.out.println("你转动了手柄");
        int winner = random.nextInt(10);
        if (winner == 0 && machine.getCount() > 1)
        {
            machine.setState(machine.getWinnerState());
        } else
        {
            machine.setState(machine.getSoldState());
        }
    }
 
    @Override
    public void dispense()
    {
        throw new IllegalStateException("非法状态!");
    }
 
}

总结状态模式:

状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了他的类。

解释:

状态模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象。
所以行为会随着内部状态改变而改变。
我们通过组合简单引用不同状态对象来造成类改变的假象.


状态模式策略模式


1.行为封装的n个状态中,不同状态不用行为。

2.context的行为委托到不同状态中。

3.[当前状态]在n个状态中游走,context的行为也随之[当前状态]的改变而改变。

4.用户对context的状态改变浑然不知。

5.客户不会直接和state交互,只能通过context暴露的方法交互,state转换是context内部事情。

6.state可以是接口也可以是抽象类,取决于有没公共功能可以放进抽象类中。抽象类方便,因为可以后续加方法。

可以将重复代码放入抽象类中。例如:"你已投入25元,不能重复投" 这种通用代码放入抽象类中。

7.context可以决定状态流转,如果这个状态流转是固定的,就适合放在context中进行。但是如果状态流转是动态的就适合放在状态中进行。

例如通过商品的剩余数目来决定流向[已售完]或[等待投币],这个时候放在状态类中,因为dispense要根据状态判断流转。

这个写法决定了,有新需求时候,你是改context还是改state类。

8.可以共享所有的state对象,但是需要修改context的时候时候,需要handler中传入context引用

1.context主动指定需要组合的策略对象是哪一个。

2.可以在启动的时候通过工厂动态指定具体是哪个策略对象,但是没有在策略对象之间游走,即:只组合了一个策略对象。

3.策略作为继承之外一种弹性替代方案。因为继承导致子类继承不适用的方法,且每个类都要维护,策略模式通过不同对象组合来改变行为。

4.策略模式聚焦的是互换的算法来创建业务。



状态机典型应用:订单状态控制

建表语句

如上图所示:

一种典型的订单设计。业务订单和支付退款订单组合,他们分别有自己的状态机。

  • 业务订单状态机负责业务逻辑,并和支付退款状态机联动。
  • 一切以业务状态机为主。例如:业务状态已经【关单】,此时收到支付成功通知,需要进行退款
  • 每个状态有自己的过期时间。异常订单的捞取通过过期时间判断。

状态机模式实现订单状态机:

日常开发过程中,状态机模式应用场景之一的就是订单模型中的状态控制。但是区别于状态模式的点有以下几个:

  • 状态模式,所有的操作都在内存。而订单状态机是要落库的。为了防止订单的并发操作,更新订单的时候需要使用乐观锁机制。
  • 状态模式的状态对象是新建状态机的时候初始化进去的。在实际开发中,状态对象要复用,被spring管理。
  • 而订单状态机对象对应了一条数据库中实体的订单,是要每次从数据库中查出来的即时新建对象,所以必须将该新建的订单状态机对象传入到状态对象中。使用状态对象处理该订单状态机对象。

以支付订单为例:

/*
   Title: PaymentInfo Description:
  支付订单状态机
   该类不可被spring管理,需要new出来,一个类就对应一条数据库中支付订单记录
   本文来自博客园,作者:wanglifeng,转载请注明原文链接:https://www.cnblogs.com/wanglifeng717/p/16214122.html
   
   @author wanglifeng
 */


public class PaymentStateMachine {

    // 数据库中当前支付订单实体
    private SapoPayment payment;

    // 当前状态
    private PaymentState currentState;

    // 需要更新入库的支付订单实体。与payment属性配合,payment为当前数据库中订单实体,用于乐观锁的前置内容校验。
    private SapoPayment paymentForUpdate;

    /* 将最新内容(含状态)更新入库,并当前状态机状态 */
    public void updateStateMachine() {

        // 从Spring容器中获取操作数据的dao
        SapoDao dao = SpringUtil.getBean(SapoDao.class);

        // 更新数据库,乐观锁机制:带前置内容数据校验,其中payment为前置内容,paymentForUpdate为要更新的内容,如果更新结果=0,说明该订单被其他线程修改过。抛异常,放弃此次修改。
        dao.updateSapoPaymentByNull(paymentForUpdate, payment);

        // 记录订单操作流水
        dao.insertSapoOrderStatusLog(SapoOrderStatusLog.getInstance().setOrderId(paymentForUpdate.getId())
                .setOrderType(SapoOrderStatusLog.ORDER_TYPE_PAYMENT).setStatus(paymentForUpdate.getStatus()));

        // 更新当前PaymentStateMachine状态机
        this.setPayment(paymentForUpdate);
        this.setCurrentState(paymentForUpdate.getStatus());
    }

    // 通过条件获取一个支付订单PaymentStateMachine实体
    public static PaymentStateMachine getInstance(SapoPayment sapoPaymentForQuery) {
        // 1.从spring容器中获取dao;
        SapoDao dao = SpringUtil.getBean(SapoDao.class);

        // 2.查出该支付订单
        SapoPayment paymentResult = dao.getSapoPayment(sapoPaymentForQuery);

        // 3.初始化订单状态机
        PaymentStateMachine paymentStateMachine = new PaymentStateMachine();
        paymentStateMachine.setPayment(paymentResult);
        paymentStateMachine.setCurrentState(paymentResult.getStatus());
        paymentStateMachine.setPaymentForUpdate(SapoPayment.getInstance(paymentResult));

        return paymentStateMachine;
    }

    // 设置当前状态机的状态。输入数据库中status字段,映射成对应的状态类实体。
    public void setCurrentState(Integer status) {

        PaymentState currentState = null;

        // status数字,映射成对应的状态类实体
        if (SapoPayment.STATUS_APPLY.equals(status)) {
            currentState = SpringUtil.getBean(PaymentStateApply.class);
        } else if (SapoPayment.STATUS_WAIT_PAY.equals(status)) {
            currentState = SpringUtil.getBean(PaymentStateWaitPay.class);
        } else if (SapoPayment.STATUS_PAY_FINISH.equals(status)) {
            currentState = SpringUtil.getBean(PaymentStatePayFinish.class);
        } else if (SapoPayment.STATUS_FAIL.equals(status)) {
            currentState = SpringUtil.getBean(PaymentStateFail.class);
        } else if (SapoPayment.STATUS_CANCEL.equals(status)) {
            currentState = SpringUtil.getBean(PaymentStateCancel.class);
        } else {
            throw new BusinessException(ResultInfo.SYS_INNER_ERROR.getCode(),
                    "status not in state machine ,status: " + status);
        }

        this.currentState = currentState;
    }

    // TODO 待实现,申请支付订单
    public void apply() {
        // 委托给当前状态执行,将当前订单状态机对象传进去,使用状态对象处理订单
        currentState.apply(this);
    }

    // TODO 待实现,通知支付结果
    public void resultNotify() {
        // 委托给当前状态执行
        currentState.resultNotify(this);
    }

    // TODO 同步给当前状态执行
    public void sync() {
        // 委托给当前状态执行
        currentState.sync(this);
    }

    // 取消订单
    public void cancel() {
        // 委托给当前状态执行
        currentState.cancel(this);
    }


}


public  interface PaymentState {

    public void apply(PaymentStateMachine paymentStateMachine);

    public void resultNotify(PaymentStateMachine paymentStateMachine);
    
    public void sync(PaymentStateMachine paymentStateMachine);
    
    public void cancel(PaymentStateMachine paymentStateMachine);

}
@Service
public class PaymentStateApply extends BaseLogger implements PaymentState {

    @Autowired
    FmPayClientService fmPayClientService;

    @Autowired
    SapoDao dao;

    @Autowired
    private JacksonComponent jacksonComponent;

    public void apply(PaymentStateMachine paymentStateMachine) {

       

    }

    public void sync(PaymentStateMachine paymentStateMachine) {

    }

    public void resultNotify(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void cancel(PaymentStateMachine paymentStateMachine) {
        
        SapoPayment sapoPaymentForUpdate = paymentStateMachine.getPaymentForUpdate();
        sapoPaymentForUpdate.setStatus(SapoPayment.STATUS_CANCEL);
        sapoPaymentForUpdate.setExpireTime(null);
        
        paymentStateMachine.updateStateMachine();
        
        

    }

}
@Service
public class PaymentStateCancel extends BaseLogger implements PaymentState {

    public void apply(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void resultNotify(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void sync(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void cancel(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

}
@Service
public class PaymentStateFail extends BaseLogger implements PaymentState {

    public void apply(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void resultNotify(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void sync(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void cancel(PaymentStateMachine paymentStateMachine) {
        throw new BusinessException(ResultInfo.SYS_INNER_ERROR.getCode(), "fail status can not cancel");

    }

}
@Service
public class PaymentStatePayFinish extends BaseLogger implements PaymentState {

    public void apply(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void resultNotify(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void sync(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void cancel(PaymentStateMachine paymentStateMachine) {
        throw new BusinessException(ResultInfo.SYS_INNER_ERROR.getCode(), "payfinish status can not cancel");

    }

}
@Service
public class PaymentStateWaitPay extends BaseLogger implements PaymentState {

    @Autowired
    FmPayClientService fmPayClientService;

    @Autowired
    SapoDao dao;

    @Autowired
    private JacksonComponent jacksonComponent;

    public void payResultNotify() {
        // TODO implement here
    }

    public void apply(PaymentStateMachine paymentStateMachine) {
        throw new BusinessException(ResultInfo.SYS_INNER_ERROR.getCode(),
                "applyPayPlatform not match payment state machine,currentStatus:"
                        + paymentStateMachine.getPayment().getStatus());

    }

    public void sync(PaymentStateMachine paymentStateMachine) {


        // TODO 过期去统一支付查询

        String payStatus = queryPayResultResponse.getPayStatus();

        // 1:初始化输入 2:支付中 3:支付成功 4:支付失败 5:撤销
        if (QueryPayResultResponse.PAY_STATUS_INIT.equals(payStatus)) {
            throw new BusinessException(ResultInfo.SYS_INNER_ERROR.getCode(),
                    "FMpay queryPay return init status ,we are waitpay");
        }

        if (QueryPayResultResponse.PAY_STATUS_ING.equals(payStatus)) {
            return;
        }

        SapoPayment sapoPaymentForUpdate = paymentStateMachine.getPaymentForUpdate();

        if (QueryPayResultResponse.PAY_STATUS_CANCEL.equals(payStatus)) {
            sapoPaymentForUpdate.setStatus(SapoPayment.STATUS_CANCEL);

        } else if (QueryPayResultResponse.PAY_STATUS_FAIL.equals(payStatus)) {
            sapoPaymentForUpdate.setStatus(SapoPayment.STATUS_FAIL);

        } else if (QueryPayResultResponse.PAY_STATUS_SUCCESS.equals(payStatus)) {
            sapoPaymentForUpdate.setStatus(SapoPayment.STATUS_PAY_FINISH);

        }
        sapoPaymentForUpdate.setExpireTime(null);

        paymentStateMachine.updateStateMachine();

    }

    public void resultNotify(PaymentStateMachine paymentStateMachine) {
        // TODO Auto-generated method stub

    }

    public void cancel(PaymentStateMachine paymentStateMachine) {
        throw new BusinessException(ResultInfo.SYS_INNER_ERROR.getCode(), "wait pay status can not cancel");

    }

}

文章来自https://www.cnblogs.com/wanglifeng717/p/16214122.html