利用シナリオ
ステートモード: オブジェクトの状態の変化に伴ってオブジェクトの動作が変化する場合、複数の判定条件を切り離し、動作の変化をカプセル化するため、オブジェクト動作インターフェイスを提供する抽象状態クラスを定義できます。特定の状態関連の動作は、そのサブクラスによって実装されます。
Strategy モード: 「戦略」という言葉はアルゴリズムに相当します。アルゴリズムを実際のシステムで動的に指定する必要があり、相互に置き換えることができる場合、アルゴリズムの呼び出しインターフェイスを抽象化できます。アルゴリズムは特定の戦略ロールによって実装されており、リスコフ置換原則に従って実装するには、親クラスが出現するあらゆる場所をそのサブクラスに置き換えることができ、これはビジネス ニーズを満たします。
比較
どちらも親クラスの標準呼び出しインターフェイスを抽象化していますが、特定の動作はサブクラスによって実装され、環境オブジェクトには親への参照も含まれています。クラスですが、これら 2 つのモードのアプリケーション シナリオはまったく異なります。例: ATM にお金を引き出しに行った場合、口座が凍結されている場合は、正常にお金を引き出すことができません。ここで、銀行口座には、凍結と凍結解除という少なくとも 2 つのステータスがあります。このようなビジネス ソリューションを解決するために戦略パターンを使用することは考えられないでしょう。もう 1 つの例は、ショッピング モールの割引です。さまざまな割引戦略があります。子供向けの商品は 30% オフ、高齢者の商品は 50% オフです。この問題は状態モードとは関係ありません。ここの商品には高齢者向けの商品があるとは言えません。状態と子状態です!
ATM 引き出しケース分析
設計された役割: レジ担当者、アカウント、ATM 機。
ユースケース図
わかりやすくするために、出金のユースケースを分析してみましょう。
基本イベント パス
(1) 引き出し者は銀行カードを挿入し、パスワードを入力します;
(2) 引き出しを選択します操作して出金金額を入力します;
(3) お金を引き出すために現金の引き出しを待ちます。
この使用例では、引き出し者のアカウントが凍結されている場合、オプションのイベント パスが発生し、引き出しの使用例は終了します。
主要なビジネス要件は、ユーザーがお金を引き出すという事実であるため、ドメイン モデリングは、引き出し者と引き出し者を識別する 2 つのクラスから開始できます。引き出し者にはお金を引き出すというユースケースがあるだけではないことを考慮して、引き出しをトランザクションに一般化します。
モデリング
ユースケースの実現
撤回: 基本的なイベント パスの実現。
洗練されたドメイン モデル
ATMSystem 境界オブジェクトは、ユーザーとの対話を担当するコントローラー (ユーザーと対話するための ATM 操作インターフェイス) としてここで紹介されています。 ). Trade は、ユーザー トランザクションの処理を担当するクラスです。
引き出し者は銀行カードを挿入し、パスワードを入力します。ATMSystem は、口座情報を確認するメッセージを取引トランザクション クラスに渡す責任があります。取引は、渡された口座パスワードに基づいてユーザーが存在するかどうかを確認し、その後、処理完了メッセージを ATMSystem に渡し、境界オブジェクトがユーザーに反映されます。
分析モデルのいくつかのクラス
##出金設計——申請ステータス モード アカウントのステータスは凍結ステータスに分けられますおよびアクティベーションステータス。アカウントはアクティブ化されている場合は取引を行うことができますが、凍結されている場合は取引を行うことができません。アカウント認証時には現在のアカウントのステータスが返される必要がありますが、アカウントが凍結されている場合は、出金操作を実行すると直接エラー メッセージが返されます。状態図は次のように表されます: 出金申請状態モード構造図: アカウント検証段階、アカウントが凍結状態の場合は、DeadAccount に直接戻ってすべてのトランザクションを拒否します。それ以外の場合は、ActiveAccount に戻って後続のトランザクションを処理します。 回路図コード: 実装を簡単にするため、境界オブジェクト ATMSystem はここでは省略されています。 ユーザーアカウント情報抽象クラス////// 用户账号信息 /// public abstract class Account { ////// 账号 /// private string account; ////// 密码 /// private string pwd; public abstract decimal getBalance(decimal d); }
////// 冻结账户类 /// public class DeadAccount:Account { public override decimal getBalance(decimal d) { return 0; } }
激活账户类
////// 激活账户类 /// public class ActiveAccount:Account { public override decimal getBalance(decimal d) { return d; } }
交易类
////// 交易类 负责用户交易处理的类 /// public class Trade { ////// 保存用户账号信息 /// 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; } ////// 商业逻辑 取款 /// /// ///public decimal GetBalance(decimal d) { return this.account.getBalance(d); } }
用户类
////// 取款人 /// public class User { ////// 用户账号信息 /// private Account account; ////// 交易处理类 /// private Trade trade; public User(Account a, Trade t) { this.account = a; tthis.trade = t; } ////// 用户登录类 /// public void Login() { trade.VolidateLogin(account); } ////// 取款 /// /// ///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折等,张三去购物为了一双运动鞋、一件秋装、一瓶洗发水。。。,张三买完东西回家,心想今天自己总共“赚”了多少钱?
案例分析:商家对于商品打折可能有很多策略,这里使用策略模式,封装商品打折策略,这样以便以后扩展了打折策略,不用去修改原来的代码,具有很好的灵活性。
模式涉及的角色:
抽象策略角色:通常由一个接口或者抽象实现;
具体策略角色:包装了相关的算法和行为;
环境角色:包含抽象策略角色的引用,最终供用户使用。
商品折扣案例设计图
顾客购物涉及到的角色有:购物车、商品、收银台、抽象策略角色和具体策略角色。
购物车:是摆放商品的容器,提供添加和删除操作;
商品:商品实体,有类型,商品名、价格等属性;
收银台:负责收钱,主要是计算顾客购买所有商品的价格和折扣总额;
抽象策略角色:提供折扣策略接口。
具体策略角色:实现具体折扣算法。
商品折扣示意代码:
////// 具体商品类 /// public class goods { ////// 商品类型 /// public string Type { set; get; } ////// 商品名称 /// public string Name { get; set; } ////// 商品价格 /// public decimal Price { get; set; } }
抽象策略角色
////// 抽象策略接口 /// public interface IDiscountStrategy { decimal GetDiscount(goods g); }
具体策略角色
////// 秋装打折策略 /// public class AutumnDressDiscountStrategy:IDiscountStrategy { #region IDiscountStrategy Members public decimal GetDiscount(goods g) { return (decimal)0.9 * g.Price; } #endregion } ////// 运动鞋打折策略 /// public class SportShoesDiscountStrategy:IDiscountStrategy { #region IDiscountStrategy Members public decimal GetDiscount(goods g) { return g.Price * (decimal)0.8; } #endregion }
购物车
///
ログイン後にコピー
|
收银台角色
////// 收银台 /// public class CashierDesk { ////// 购物车 /// private ShoppingCar shoppingCar; ////// 策略字典 /// private Dictionarystrategies; public CashierDesk(ShoppingCar sc, Dictionary s) { this.shoppingCar = sc; this.strategies = s; } /// /// 获得所有商品的价格 /// ///public decimal GetTotalPrice() { return shoppingCar.GoodsList.Sum(p => p.Price); } /// /// 获得所有商品的总的折扣 /// ///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(); DictionarydiscountD = new Dictionary (); //向购物车中加入商品 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 中国語 Web サイトの他の関連記事を参照してください。