c# - 减少状态模式中的耦合

标签 c# design-patterns .net-4.0 coupling state-pattern

我有一个银行账户计划。每个帐户可以处于初始状态或受信任帐户状态(目前)。将来可能会添加新的状态。如果处于初始状态,则不支付利息。但如果处于受信任账户状态,则支付 9% 的利息。

以下代码有效。但 ChangeState() 方法中存在紧密耦合。 InitialAccountState 需要知道 TrustedAccountedState 的存在。如果我们添加一个名为 VeteranAccountedState 的新状态,则 ChangeState() 方法需要在 InitialAccountState 类中重写。

减少这种耦合的最佳 .Net 4.0 方法是什么?

状态模式

The state pattern allows a object's state to change at any given moment which actually alters its behavior.

当状态改变的顺序是预先定义的时,耦合在状态模式中不是问题。例如,交通信号灯总是从绿色-黄色-红色变化。在这种情况下,耦合不是问题——绿色确信下一步总是处于黄色状态。请参阅Analysis Of State Machine Pattern

抽象状态

abstract class AccountState
    {
        // Properties
        public BankAccount Account { get; set; }
        public double Balance { get; set; }

        protected double interest;
        protected double lowerLimit;
        protected double upperLimit;

        public abstract void Deposit(double amount);
        public abstract void PayInterest();
    }

混凝土

  class InitialAccountState : AccountState
    {
        public InitialAccountState(AccountState state) :this(state.Balance, state.Account)
        {

        }

        public InitialAccountState(double balance, BankAccount account)
        {
            this.Balance = balance;
            this.Account = account;
            Initialize();
        }

        private void Initialize()
        {
            lowerLimit = 0.0;
            upperLimit = 1000.0;
        }

        public override void Deposit(double amount)
        {
            Balance += amount;
            ChangeState();
        }

        public override void PayInterest()
        {
            throw new Exception("No Interest Allowed");
        }

        private void ChangeState()
        {
            if (Balance > upperLimit)
            {
                Account.State = new TrustedAccountedState(this);
            }
        }
    }

    class TrustedAccountedState : AccountState
    {
        public TrustedAccountedState(AccountState state): this(state.Balance, state.Account)
        {
        }

        public TrustedAccountedState(double balance, BankAccount account)
        {
            this.Balance = balance;
            this.Account = account;
            Initialize();
        }

        private void Initialize()
        {
            interest = 0.05;
            lowerLimit = 1000.0;
            upperLimit = 10000000.0;
        }

        public override void Deposit(double amount)
        {
            Balance += amount;
            ChangeState();
        }

        public override void PayInterest()
        {
            Balance += interest * Balance;
            ChangeState();
        }

        private void ChangeState()
        {
            if (Balance < lowerLimit)
            {
                Account.State = new InitialAccountState(this);
            }
        }
    }

上下文

  class BankAccount
    {
        // Properties
        public AccountState State { get; set; }

        public double Balance
        {
            get { return State.Balance; }
        }


        // Constructor
        public BankAccount(string owner)
        {
            this.State = new InitialAccountState(0.0, this);
        }

        public void Deposit(double amount)
        {
            State.Deposit(amount);

            Console.WriteLine("Deposited {0:C} --- ", amount);
            Console.WriteLine(" Balance = {0:C}", this.Balance);
            Console.WriteLine(" Status = {0}", this.State.GetType().Name);
            Console.WriteLine("");
        }

        public void PayInterest()
        {
            State.PayInterest();
            Console.WriteLine("INTEREST PAID --- ");
            Console.WriteLine(" Balance = {0:C}", this.Balance);
            Console.WriteLine(" Status = {0}\n", this.State.GetType().Name);
        }
    }

客户端

class Program
    {
        static void Main(string[] args)
        {
            BankAccount account = new BankAccount("Jim Johnson");

            account.Deposit(500.0);
            account.Deposit(300.0);
            account.Deposit(550.0);
            account.PayInterest();

            Console.ReadKey();
        }
}

引用文献

  1. Analysis Of State Machine Pattern
  2. Is the State Design pattern scalable ?
  3. State Design Pattern
  4. Implementing the Specification Pattern in .NET
  5. Is the Specification Pattern obsolete?
  6. Specification pattern in C#
  7. Specifications in C# 3.0
  8. LINQ Expression Trees and the Specification Pattern

最佳答案

我会将状态更改重构为另一个类,例如服务类,其职责是了解如何更改状态,从而反转依赖关系并消除状态之间的紧密耦合。 所以我会更改抽象类,以便可以访问 protected 属性。

abstract class AccountState
{
    // Properties
    public BankAccount Account { get; set; }
    public double Balance { get; set; }

    internal double interest;
    internal double lowerLimit;
    internal double upperLimit;

    public abstract void Deposit(double amount);
    public abstract void PayInterest();
}

添加 StateChanger 类...

public class StateChanger(){
   public AccountState ChangeState(AccountState state){
       if((state is InitialAccountState) && (state.Balance > state.upperLimit)){
           return new TrustedAccountedState(state);
       }
       if((state is TrustedAccountedState) && (state.Balance < state.lowerLimit))
       {
           return new InitialAccountState(state);
       }
       return state;
   }
}

从 AccountState 类中删除依赖项

class InitialAccountState : AccountState
{
    public InitialAccountState(AccountState state) :this(state.Balance, state.Account)
    {

    }

    public InitialAccountState(double balance, BankAccount account)
    {
        this.Balance = balance;
        this.Account = account;
        Initialize();
    }

    private void Initialize()
    {
        lowerLimit = 0.0;
        upperLimit = 1000.0;
    }

    public override void Deposit(double amount)
    {
        Balance += amount;
    }

    public override void PayInterest()
    {
        throw new Exception("No Interest Allowed");
    }

}

class TrustedAccountedState : AccountState
{
    public TrustedAccountedState(AccountState state): this(state.Balance, state.Account)
    {
    }

    public TrustedAccountedState(double balance, BankAccount account)
    {
        this.Balance = balance;
        this.Account = account;
        Initialize();
    }

    private void Initialize()
    {
        interest = 0.05;
        lowerLimit = 1000.0;
        upperLimit = 10000000.0;
    }

    public override void Deposit(double amount)
    {
        Balance += amount;
    }

    public override void PayInterest()
    {
        Balance += interest * Balance;
    }

}

然后你的 BackAccount 类就像一个 Controller ,看起来像

    class BankAccount
    {

    // Properties
    public AccountState State { get; set; }
    private StateChanger stateChanger;

    public double Balance
    {
        get { return State.Balance; }
    }


    // Constructor
    public BankAccount(string owner,StateChanger stateChanger)
    {
        this.State = new InitialAccountState(0.0, this);
        this.stateChanger = stateChanger;
    }

    public void Deposit(double amount)
    {
        State.Deposit(amount);
        State = stateChanger.ChangeState(State);

        Console.WriteLine("Deposited {0:C} --- ", amount);
        Console.WriteLine(" Balance = {0:C}", this.Balance);
        Console.WriteLine(" Status = {0}", this.State.GetType().Name);
        Console.WriteLine("");
    }

    public void PayInterest()
    {
        State.PayInterest();
        State = stateChanger.ChangeState(State);        
        Console.WriteLine("INTEREST PAID --- ");
        Console.WriteLine(" Balance = {0:C}", this.Balance);
        Console.WriteLine(" Status = {0}\n", this.State.GetType().Name);
    }
}

主要

    class Program
    {
        static void Main(string[] args)
        {
            StateChanger stateChanger = new StateChanger();
            BankAccount account = new BankAccount("Jim Johnson",stateChanger);

            account.Deposit(500.0);
            account.Deposit(300.0);
            account.Deposit(550.0);
            account.PayInterest();

            Console.ReadKey();
        }
}

通过分离管理状态的关注点,AccountState 类彼此解耦,现在如果您需要添加更多状态,则只需更新 1 个类。这样,AccountState 类就不需要保留状态,而只需定义行为,即如果您的帐户处于给定状态,则 Deposit 或 PayInterest 应该如何表现。您仍然可以在状态转换器类中使用规范模式。

关于c# - 减少状态模式中的耦合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21332730/

相关文章:

java - 我应该如何将新的 View 组件绑定(bind)到 GWT 的 MVP 模式中的演示者?

wcf - 哦问题: applying same logic to 2 similar objects

c# - 对于 C#,是否可以在泛型类的实例声明中指定类型约束?

javascript - 将大型 json 发送到服务器的最佳模式是什么

c# - 将同一文件从多个线程复制到多个目的地

javascript - jQuery 方法教程

wcf - 如何枚举所有当前正在执行的 WCF 操作?

c# - 使用 ClickOnce 设置文件关联

.net - 在 WCF 中使用 x-www-form-urlencoded 内容类型

c# - 你如何用响应式扩展扇出 observables