允許對象在內部狀態改變時改變行為,彷彿修改了其類別。
網路書店會員制度:消費達標升級銀/金會員,不同等級享不同折扣。若在 User.BuyBook 中用條件判斷等級折扣,問題:
引入 State 模式,將對象與狀態分離,狀態轉換與行為交由具體狀態類處理。
using System;
using System.Collections.Generic;
using System.Text;
namespace StateExample
{
class Program
{
static void Main(string[] args)
{
User user = new User("zhuye");
user.BuyBook(2000);
user.BuyBook(2000);
user.BuyBook(2000);
user.BuyBook(2000);
}
}
class User
{
public UserLevel UserLevel { get; set; }
string userName;
double paidMoney;
public double PaidMoney => paidMoney;
public User(string userName)
{
this.userName = userName;
paidMoney = 0;
UserLevel = new NormalUser(this);
}
public void BuyBook(double amount)
{
Console.WriteLine($"Hello {userName}, You have paid ${paidMoney}, You Level is {UserLevel.GetType().Name}.");
double real = UserLevel.CalcRealAmount(amount);
Console.WriteLine($"You only paid ${real} for this book.");
paidMoney += real;
UserLevel.StateCheck();
}
}
abstract class UserLevel
{
protected User user;
public UserLevel(User user) { this.user = user; }
public abstract void StateCheck();
public abstract double CalcRealAmount(double amount);
}
class DiamondUser : UserLevel
{
public DiamondUser(User user) : base(user) { }
public override double CalcRealAmount(double amount) => amount * 0.7;
public override void StateCheck() { } // 最高級無上遷
}
class GoldUser : UserLevel
{
public GoldUser(User user) : base(user) { }
public override double CalcRealAmount(double amount) => amount * 0.8;
public override void StateCheck() { if (user.PaidMoney > 5000) user.UserLevel = new DiamondUser(user); }
}
class SilverUser : UserLevel
{
public SilverUser(User user) : base(user) { }
public override double CalcRealAmount(double amount) => amount * 0.9;
public override void StateCheck() { if (user.PaidMoney > 2000) user.UserLevel = new GoldUser(user); }
}
class NormalUser : UserLevel
{
public NormalUser(User user) : base(user) { }
public override double CalcRealAmount(double amount) => amount * 0.95;
public override void StateCheck() { if (user.PaidMoney > 1000) user.UserLevel = new SilverUser(user); }
}
}
UserLevel 實例,對外提供 BuyBook。CalcRealAmount、StateCheck),持有 Context 參考以便修改其狀態。StateCheck),形成有序鏈,僅前後狀態產生依賴。若移除 DiamondUser,GoldUser 的 StateCheck 留空即可;未來新增只需改 GoldUser。