Maison >Java >javaDidacticiel >Exemple d'analyse du modèle de stratégie et du modèle d'état dans les modèles de conception Java
Scénarios d'utilisation
Modèle d'état : lorsque le comportement d'un objet change avec le changement de l'état de l'objet, afin de découpler plusieurs conditions de jugement et d'encapsuler les changements de comportement, nous pouvons définir une classe d'état abstraite pour fournir un comportement d'objet interface. Des comportements spécifiques liés à l'état sont implémentés par ses sous-classes.
Modèle de stratégie : le mot « stratégie » est équivalent à algorithme. Lorsque les algorithmes doivent être spécifiés dynamiquement dans le système réel et peuvent être remplacés les uns par les autres, l'interface d'appel de l'algorithme peut être abstraite. L'implémentation spécifique de l'algorithme est implémentée. par des rôles stratégiques spécifiques. Selon le principe de substitution de Liskov, partout où une classe parent apparaît, sa sous-classe peut être utilisée pour la remplacer, ce qui répond à nos besoins commerciaux.
Comparaison
Bien que les deux fassent abstraction de l'interface d'appel standard de la classe parent, le comportement spécifique est implémenté par la sous-classe et l'objet d'environnement contient également des références à la classe parent, les scénarios d'application des deux modèles sont complètement différents . Par exemple : Si vous vous rendez à un distributeur automatique pour retirer de l’argent, si votre compte est gelé, vous ne pouvez pas retirer d’argent normalement. Ici, votre compte bancaire a au moins deux statuts : gelé et dégelé. Vous ne penseriez pas à utiliser le modèle de stratégie pour résoudre une telle solution commerciale. Un autre exemple est celui des réductions dans les centres commerciaux. Il existe de nombreuses stratégies de réduction sur les produits pour enfants et sur les produits pour personnes âgées. Ce problème n'est pas lié au mode d'État. un État et un État enfant !
Analyse des cas de retrait aux distributeurs automatiques
Rôles conçus : caissier, compte, distributeur automatique.
Diagramme de cas d'utilisation
Par souci de simplicité, analysons le cas d'utilisation du retrait.
Parcours de base de l'événement
(1) Le retraiteur insère la carte bancaire et saisit le mot de passe
(2) Sélectionne l'opération de retrait et saisit le montant du retrait
(3) Attend que l'argent soit reçu ; émis et retire de l’argent.
Dans ce cas d'utilisation, si le compte du retrait a été gelé, un chemin d'événement facultatif se produit et le cas d'utilisation du retrait est terminé.
L'exigence commerciale clé est le fait que l'utilisateur retire de l'argent, la modélisation de domaine peut donc partir des deux classes qui identifient le retrait et la personne qui retire. Tenant compte du fait que le retraiteur n’a pas seulement pour cas d’usage de retirer de l’argent, nous généralisons le retrait en transaction.
Modélisation
Réalisation de cas d'utilisation
Retrait : Réalisation du parcours événementiel de base.
Modèle de domaine raffiné
L'objet limite ATMSystem est présenté ici en tant que contrôleur responsable de l'interaction avec les utilisateurs (l'interface d'opération ATM qui interagit avec les utilisateurs), et Trade est la classe responsable du traitement des transactions des utilisateurs.
Le retraiteur insère la carte bancaire et saisit le mot de passe. ATMSystem se charge de transmettre le message pour vérifier les informations du compte à la classe de transaction Trade vérifie si l'utilisateur existe en fonction du mot de passe du compte transmis, puis transmet le message traité. à l'objet limite ATMSystem pour refléter l'utilisateur.
Quelques classes dans le modèle d'analyse
Conception du retrait - mode statut de la demande
Le statut du compte est divisé en statut gelé et statut activé. Le compte peut effectuer des transactions lorsqu'il est activé, mais ne peut effectuer aucune transaction lorsqu'il est gelé. Lors de la vérification du compte, l'état du compte courant doit être renvoyé. Si le compte est gelé, un message d'erreur sera renvoyé directement lors de l'opération de retrait. Le diagramme de statut est représenté comme suit :
Schéma de structure du mode de statut de la demande de retrait :
Lors de l'étape de vérification du compte, si le compte est gelé, il reviendra directement à DeadAccount pour refuser toutes les transactions, sinon il reviendra à ActiveAccount pour traiter les transactions ultérieures.
Code schématique :
Pour une implémentation simple, l'objet limite ATMSystem est omis ici.
Classe abstraite d'informations sur le compte utilisateur
/// <summary> /// 用户账号信息 /// </summary> public abstract class Account { /// <summary> /// 账号 /// </summary> private string account; /// <summary> /// 密码 /// </summary> private string pwd; public abstract decimal getBalance(decimal d); }
Classe de compte gelé
/// <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折等,张三去购物为了一双运动鞋、一件秋装、一瓶洗发水。。。,张三买完东西回家,心想今天自己总共“赚”了多少钱?
案例分析:商家对于商品打折可能有很多策略,这里使用策略模式,封装商品打折策略,这样以便以后扩展了打折策略,不用去修改原来的代码,具有很好的灵活性。
模式涉及的角色:
抽象策略角色:通常由一个接口或者抽象实现;
具体策略角色:包装了相关的算法和行为;
环境角色:包含抽象策略角色的引用,最终供用户使用。
商品折扣案例设计图
顾客购物涉及到的角色有:购物车、商品、收银台、抽象策略角色和具体策略角色。
购物车:是摆放商品的容器,提供添加和删除操作;
商品:商品实体,有类型,商品名、价格等属性;
收银台:负责收钱,主要是计算顾客购买所有商品的价格和折扣总额;
抽象策略角色:提供折扣策略接口。
具体策略角色:实现具体折扣算法。
商品折扣示意代码:
/// <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(); } }
策略模式优点与缺点:
优点
封装了算法不稳定性,易于以后业务策略的扩展。
缺点
每种策略对应于一个具体策略角色类,会增加系统需要维护的类的数量。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!