首页 Java java教程 java设计模式中的策略模式与状态模式实例分析

java设计模式中的策略模式与状态模式实例分析

Apr 17, 2023 pm 08:10 PM
java

使用场景

状态模式:当对象的行为随对象的状态的改变而改变时,我们为了解耦多重判断条件,封装行为的变化,可以定义一个抽象的状态类,提供对象行为接口。具体与状态相关的行为,由它的子类去实现。

策略模式:“策略”二字等同于算法,当现实系统中需要对算法动态指定,并且可以互相替换,可以抽象出算法的调用接口,具体的算法实现由具体的策略角色去实现,根据里氏替换原则,任何出现父类的地方都可以使用它的子类去替换,这样符合我们的业务需求。

比较

虽然两者都是抽象出父类规范调用接口,具体的行为由子类实现,环境对象同时包含父类的引用,但是这两者模式应用的场景完全不同。例如:你去ATM机取款,如果你的账户处于冻结状态,就不能正常取款。这里你的银行账户至少有两个状态就是冻结与非冻结。这样的业务解决方案你应该不会想到用策略模式去解决。又如商场打折,有很多打折的策略,儿童用品打7折,老人用品打5折,这个问题不会跟状态模式扯上关系吧,这里商品你不能说有老人状态和儿童状态!

ATM取款案例分析

设计到的角色:取款人、账户、ATM机。

用例图

这边简单起见,就分析取款用例。

java设计模式中的策略模式与状态模式实例分析

基本事件路径

(1) 取款人插入银行卡,输入密码;

(2) 选择取款操作,输入取款金额;

(3) 等待出钞,取款。

在这个用例中,如果取款人账户已冻结,就发生一个可选事件路径,取款用例就被终止。

关键的业务需求是用户取款事实,所以领域建模可以从标识取款和取款人这两个类开始。这边考虑到取款人不仅有取款这个用例,我们将取款泛化成交易。

建模

java设计模式中的策略模式与状态模式实例分析

用例实化

取款:基本事件路径的实化。

java设计模式中的策略模式与状态模式实例分析

细化领域模型

这边引入了ATMSystem这个边界对象作为控制器负责与用户交互(与用户交互的ATM操作界面),Trade是负责处理用户交易的类。

取款人插入银行卡输入密码,ATMSystem负责将验证账户信息的消息传递给Trade交易类,Trade根据传过来的账户密码验证用户是否存在,然后将处理结束的消息传递给ATMSystem这个边界对象反映给用户。

分析模型中的一些类

java设计模式中的策略模式与状态模式实例分析

取款设计——应用状态模式

账户的状态分为冻结状态和激活状态。账户在激活的状态下可以进行交易,而在冻结状态下不能做任何交易。在账户验证的时候,应该返回当前账户的状态,如果账户处于冻结状态,当取款人进行取款操作的时候直接返回错误提示信息。状态图表示如下:

java设计模式中的策略模式与状态模式实例分析

取款应用状态模式结构图:

java设计模式中的策略模式与状态模式实例分析

在验证账户阶段,如果账户处于冻结状态,则直接返回DeadAccount谢绝一切交易,否则返回ActiveAccount处理后面的交易。

示意代码:

这边为了简单实现,省去了ATMSystem这个边界对象。

用户账号信息抽象类

/// <summary> /// 用户账号信息 /// </summary> public abstract class Account {     /// <summary>     /// 账号     /// </summary>     private string account;     /// <summary>     /// 密码     /// </summary>     private string pwd;     public abstract decimal getBalance(decimal d); }
登录后复制

冻结账号类

/// <summary> /// 冻结账户类 /// </summary> public class DeadAccount:Account {       public override decimal getBalance(decimal d)     {         return 0;     } }
登录后复制

激活账户类

/// <summary> /// 激活账户类 /// </summary> public class ActiveAccount:Account {     public override decimal getBalance(decimal d)     {         return d;     } }
登录后复制

交易类

/// <summary> /// 交易类 负责用户交易处理的类 /// </summary> public class Trade {     /// <summary>     /// 保存用户账号信息     /// </summary>     private Account account;     public Account VolidateLogin(Account a)     {                    //query the database to validate the user exists         //For Example         this.account = new DeadAccount();         return this.account;     }       /// <summary>     /// 商业逻辑 取款     /// </summary>     /// <param name="d"></param>     /// <returns></returns>     public decimal GetBalance(decimal d)     {         return this.account.getBalance(d);     }  }
登录后复制

用户类

/// <summary> /// 取款人 /// </summary> public class User {     /// <summary>     /// 用户账号信息     /// </summary>     private Account account;     /// <summary>     /// 交易处理类     /// </summary>     private Trade trade;       public User(Account a, Trade t)     {         this.account = a;         tthis.trade = t;     }     /// <summary>     /// 用户登录类     /// </summary>     public void Login()     {         trade.VolidateLogin(account);     }       /// <summary>     /// 取款     /// </summary>     /// <param name="d"></param>     /// <returns></returns>     public decimal GetBalance(decimal d)     {         return trade.GetBalance(d);     } }
登录后复制

客户端代码

class Client     {         static void Main(string[] args)         {             //开始用户取款,默认是激活账户             ActiveAccount aa = new ActiveAccount();             Trade t = new Trade();             User u = new User(aa,t);             //先登录,后取款             u.Login();             Console.WriteLine(u.GetBalance(100));             Console.ReadLine();         }     }
登录后复制

用户必须先登录(插入银行卡,输入密码,点确定),才能选择取款业务(选择取款)。登录之后,返回的账号对象作为trade类成员,当进行取款业务的时候直接引用该账号成员获得取款信息。如果该账号属于冻结账号,则直接返回0。否则返回取款的值。

商品折扣案例

案例描述:某家超市国庆节为了促销,某些类商品打折,比如运动鞋打8折、秋装打9折等,张三去购物为了一双运动鞋、一件秋装、一瓶洗发水。。。,张三买完东西回家,心想今天自己总共“赚”了多少钱?

案例分析:商家对于商品打折可能有很多策略,这里使用策略模式,封装商品打折策略,这样以便以后扩展了打折策略,不用去修改原来的代码,具有很好的灵活性。

模式涉及的角色:

抽象策略角色:通常由一个接口或者抽象实现;

具体策略角色:包装了相关的算法和行为;

环境角色:包含抽象策略角色的引用,最终供用户使用。

商品折扣案例设计图

java设计模式中的策略模式与状态模式实例分析

顾客购物涉及到的角色有:购物车、商品、收银台、抽象策略角色和具体策略角色。

购物车:是摆放商品的容器,提供添加和删除操作;

商品:商品实体,有类型,商品名、价格等属性;

收银台:负责收钱,主要是计算顾客购买所有商品的价格和折扣总额;

抽象策略角色:提供折扣策略接口。

具体策略角色:实现具体折扣算法。

商品折扣示意代码:

/// <summary> /// 具体商品类 /// </summary> public class goods {     /// <summary>     /// 商品类型     /// </summary>     public string Type     {         set;         get;     }       /// <summary>     /// 商品名称     /// </summary>     public string Name     {         get;         set;     }         /// <summary>     /// 商品价格     /// </summary>     public decimal Price     {         get;         set;     }   }
登录后复制

抽象策略角色

/// <summary> /// 抽象策略接口 /// </summary> public interface IDiscountStrategy {     decimal GetDiscount(goods g); }
登录后复制

具体策略角色

/// <summary> /// 秋装打折策略 /// </summary> public class AutumnDressDiscountStrategy:IDiscountStrategy {     #region IDiscountStrategy Members       public decimal GetDiscount(goods g)     {         return (decimal)0.9 * g.Price;     }       #endregion }     /// <summary> /// 运动鞋打折策略 /// </summary> public class SportShoesDiscountStrategy:IDiscountStrategy {     #region IDiscountStrategy Members       public decimal GetDiscount(goods g)     {         return g.Price * (decimal)0.8;     }       #endregion }
登录后复制

购物车

 

/// <summary> /// 购物车类 负责商品的维护 /// </summary> public class ShoppingCar {     private List<goods> goodsList=new List<goods>();       /// <summary>     /// 将商品加入到购物车     /// </summary>     /// <param name="g"></param>     public void AddGoods(goods g)     {         goodsList.Add(g);     }       /// <summary>     /// 将商品从购物车当中移除     /// </summary>     /// <param name="g"></param>     public void RemoveGoods(goods g)     {         goodsList.Remove(g);     }       public List<goods> GoodsList     {         get         {             return goodsList;         }     }   }
登录后复制

收银台角色

/// <summary> /// 收银台 /// </summary> public class CashierDesk {     /// <summary>     /// 购物车     /// </summary>     private ShoppingCar shoppingCar;     /// <summary>     /// 策略字典     /// </summary>     private Dictionary<string, IDiscountStrategy> strategies;       public CashierDesk(ShoppingCar sc, Dictionary<string, IDiscountStrategy> s)     {         this.shoppingCar = sc;         this.strategies = s;     }       /// <summary>     /// 获得所有商品的价格     /// </summary>     /// <returns></returns>     public decimal GetTotalPrice()     {         return shoppingCar.GoodsList.Sum(p => p.Price);     }       /// <summary>     /// 获得所有商品的总的折扣     /// </summary>     /// <returns></returns>     public decimal GetTotalDiscount()     {         decimal sum = 0;         IDiscountStrategy idiscountStrategy;         foreach (goods g in shoppingCar.GoodsList)         {             idiscountStrategy=strategies.SingleOrDefault(p => p.Key == g.Type).Value;             if (idiscountStrategy != null)             {                 sum += idiscountStrategy.GetDiscount(g);             }         }         return sum;     } }
登录后复制

客户端代码

class Client     {         static void Main(string[] args)         {             ShoppingCar sc = new ShoppingCar();             Dictionary<string, IDiscountStrategy> discountD = new Dictionary<string, IDiscountStrategy>();             //向购物车中加入商品             sc.AddGoods(new goods {Name="NIKE鞋 ",Price=100,Type="运动鞋" });             sc.AddGoods(new goods { Name = "秋装", Price = 200, Type = "秋装" });             sc.AddGoods(new goods { Name = "苹果", Price = 300, Type = "水果" });             //配置折扣策略             discountD.Add("运动鞋", new SportShoesDiscountStrategy());             discountD.Add("秋装", new AutumnDressDiscountStrategy());             CashierDesk cd = new CashierDesk(sc, discountD);             //得到所有商品总价             Console.WriteLine(cd.GetTotalPrice());             //得到所有商品折扣价             Console.WriteLine(cd.GetTotalDiscount());               Console.ReadLine();         }     }
登录后复制

策略模式优点与缺点:

优点

封装了算法不稳定性,易于以后业务策略的扩展。

缺点

每种策略对应于一个具体策略角色类,会增加系统需要维护的类的数量。

以上是java设计模式中的策略模式与状态模式实例分析的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java 中的完美数 Java 中的完美数 Aug 30, 2024 pm 04:28 PM

Java 完美数指南。这里我们讨论定义,如何在 Java 中检查完美数?,示例和代码实现。

Java 中的随机数生成器 Java 中的随机数生成器 Aug 30, 2024 pm 04:27 PM

Java 随机数生成器指南。在这里,我们通过示例讨论 Java 中的函数,并通过示例讨论两个不同的生成器。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。这里我们通过示例讨论简介、如何使用weka java、平台类型和优点。

Java 中的史密斯数 Java 中的史密斯数 Aug 30, 2024 pm 04:28 PM

Java 史密斯数指南。这里我们讨论定义,如何在Java中检查史密斯号?带有代码实现的示例。

Java Spring 面试题 Java Spring 面试题 Aug 30, 2024 pm 04:29 PM

在本文中,我们保留了最常被问到的 Java Spring 面试问题及其详细答案。这样你就可以顺利通过面试。

突破或从Java 8流返回? 突破或从Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

Java 中的时间戳至今 Java 中的时间戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的时间戳到日期指南。这里我们还结合示例讨论了介绍以及如何在java中将时间戳转换为日期。

创造未来:面向零基础的 Java 编程 创造未来:面向零基础的 Java 编程 Oct 13, 2024 pm 01:32 PM

Java是热门编程语言,适合初学者和经验丰富的开发者学习。本教程从基础概念出发,逐步深入讲解高级主题。安装Java开发工具包后,可通过创建简单的“Hello,World!”程序实践编程。理解代码后,使用命令提示符编译并运行程序,控制台上将输出“Hello,World!”。学习Java开启了编程之旅,随着掌握程度加深,可创建更复杂的应用程序。

See all articles