概要:
状態パターン(State)は、オブジェクトの内部状態が変化した際にその振る舞いを変更できるようにする設計パターンです。このパターンにより、オブジェクトがまるでクラス自体を変更したかのように振る舞うことが可能になります。
適用シーン:
-
オブジェクトの状態を表す条件分岐が複雑で、複数の操作に同じ条件構造が含まれている場合。このパターンは、状態の判断ロジックを各状態を表すクラスに分散させることで、状態の変化に応じた振る舞いを実現します。
-
オブジェクトの動作が現在の状態に依存し、実行時に即座に状態に応じた振る舞いを変更する必要がある場合。
クラス図:
コード例:
- 現在の状態を管理するConcreteStateのインスタンスを持つコンテキスト
/// <summary><br></br> /// 現在の状態を管理するConcreteStateのインスタンスを持つコンテキスト<br></br> /// </summary><br></br> class StatusHolder<br></br> {<br></br> private Status currentStatus;<br></br> /// <summary><br></br> /// コンテキストの初期状態を設定<br></br> /// </summary><br></br> /// <param name="status"></param><br></br> public StatusHolder(Status status) <br></br> {<br></br> this.currentStatus = status;<br></br> }<br></br> /// <summary><br></br> /// 状態を取得・設定するプロパティ<br></br> /// </summary><br></br> public Status CurrentStatus <br></br> {<br></br> get { return currentStatus; }<br></br> set <br></br> {<br></br> currentStatus = value;<br></br> Console.WriteLine("現在の状態:" + currentStatus.GetType().Name);<br></br> }<br></br> }<br></br> /// <summary><br></br> /// リクエスト処理と次の状態への遷移<br></br> /// </summary><br></br> public void Execute() <br></br> {<br></br> currentStatus.Process(this);<br></br> }<br></br> }
- 抽象状態クラス
/// <summary><br></br> /// 抽象状態クラス。各サブクラスはコンテキストの状態に応じた処理を実装<br></br> /// </summary><br></br> abstract class Status<br></br> {<br></br> public abstract void Process(StatusHolder holder);<br></br> }
- 具体的な状態クラス
class StatusA : Status<br></br> {<br></br> public override void Process(StatusHolder holder)<br></br> {<br></br> // 状態Aから状態Bへ遷移<br></br> holder.CurrentStatus = new StatusB();<br></br> }<br></br> }
class StatusB : Status<br></br> {<br></br> public override void Process(StatusHolder holder)<br></br> {<br></br> // 状態Bから状態Aへ遷移<br></br> holder.CurrentStatus = new StatusA();<br></br> }<br></br> }
応用例:ユーザー会員ステータス管理
View Code ``` class UserAccount { private AccountStatus _currentStatus; private string _username; // コンストラクタ public UserAccount(string username) { // 新規アカウントは「基本」ステータスをデフォルト this._username = username; this._currentStatus = new BasicStatus(0.0, this); } // プロパティ public double Balance { get { return _currentStatus.Balance; } } public AccountStatus Status { get { return _currentStatus; } set { _currentStatus = value; } } public void AddFunds(double amount) { _currentStatus.AddFunds(amount); Console.WriteLine("入金 {0:C} --- ", amount); Console.WriteLine(" 残高 = {0:C}", this.Balance); Console.WriteLine(" ステータス = {0}", this.Status.GetType().Name); Console.WriteLine(""); } public void WithdrawFunds(double amount) { _currentStatus.WithdrawFunds(amount); Console.WriteLine("出金 {0:C} --- ", amount); Console.WriteLine(" 残高 = {0:C}", this.Balance); Console.WriteLine(" ステータス = {0}\n", this.Status.GetType().Name); } public void CalculateRewards() { _currentStatus.CalculateRewards(); Console.WriteLine("報酬計算 --- "); Console.WriteLine(" 残高 = {0:C}", this.Balance); Console.WriteLine(" ステータス = {0}\n", this.Status.GetType().Name); } } /// /// 状態を表す抽象クラス /// abstract class AccountStatus { protected UserAccount account; protected double balance; protected double rewardRate; protected double lowerLimit; protected double upperLimit; // プロパティ public UserAccount Account { get { return account; } set { account = value; } } public double Balance { get { return balance; } set { balance = value; } } public abstract void AddFunds(double amount); public abstract void WithdrawFunds(double amount); public abstract void CalculateRewards(); } /// /// 具体的な状態クラス(基本) /// class BasicStatus : AccountStatus { private double _fee; // コンストラクタ public BasicStatus(AccountStatus status) { this.balance = status.Balance; this.account = status.Account; Initialize(); } private void Initialize() { // データソースから読み込むべき値 rewardRate = 0.0; lowerLimit = 0.0; upperLimit = 1000.0; _fee = 15.00; } public override void AddFunds(double amount) { balance += amount; CheckTransition(); } public override void WithdrawFunds(double amount) { amount = amount - _fee; Console.WriteLine("残高不足による引き出し不可!"); } public override void CalculateRewards() { // 報酬なし } private void CheckTransition() { if (balance > upperLimit) { account.Status = new PremiumStatus(this); } } } /// /// 具体的な状態クラス(プレミアム) /// class PremiumStatus : AccountStatus { // オーバーロードされたコンストラクタ public PremiumStatus(AccountStatus status) : this(status.Balance, status.Account) { } public PremiumStatus(double balance, UserAccount account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { // データベースから読み込むべき値 rewardRate = 0.05; lowerLimit = 1000.0; upperLimit = 10000000.0; } public override void AddFunds(double amount) { balance += amount; CheckTransition(); } public override void WithdrawFunds(double amount) { balance -= amount; CheckTransition(); } public override void CalculateRewards() { balance += rewardRate * balance; CheckTransition(); } private void CheckTransition() { if (balance < lowerLimit) { account.Status = new BasicStatus(this); } else if (balance > upperLimit) { account.Status = new EliteStatus(this); } } } /// /// 具体的な状態クラス(エリート) /// class EliteStatus : AccountStatus { // オーバーロードされたコンストラクタ public EliteStatus(AccountStatus status) : this(status.Balance, status.Account) { } public EliteStatus(double balance, UserAccount account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { // データベースから読み込むべき値 rewardRate = 0.10; lowerLimit = 10000.0; upperLimit = 100000000.0; } public override void AddFunds(double amount) { balance += amount; CheckTransition(); } public override void WithdrawFunds(double amount) { balance -= amount; CheckTransition(); } public override void CalculateRewards() { balance += rewardRate * balance; CheckTransition(); } private void CheckTransition() { if (balance < lowerLimit) { account.Status = new PremiumStatus(this); } } } /// /// 状態パターンのデモンストレーション /// static void DemonstrateStateBehavior() { // 新規アカウント作成 UserAccount account = new UserAccount("田中太郎"); // 金融取引の実施 account.AddFunds(500.0); account.AddFunds(300.0); account.AddFunds(550.0); account.CalculateRewards(); account.WithdrawFunds(2000.00); account.WithdrawFunds(1100.00); // ユーザー入力待ち Console.ReadKey(); }
**まとめ:**
状態クラスの主な目的は、膨大な条件分岐を簡略化し、状態ごとの処理を明確に分離することです。