允許物件在內部狀態改變時改變行為,物件彷彿修改了它的類別。
用戶消費達標升級:普通 → 銀 → 金 → 鑽,不同等級享不同折扣。若在 User.BuyBook 內用 if-else 判斷等級計算折扣,問題三點:
引入 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 // Context
{
private UserLevel _userLevel;
public UserLevel UserLevel { get { return _userLevel; } set { _userLevel = value; } }
private string _userName;
private double _paidMoney;
public double PaidMoney { get { return _paidMoney; } }
public User(string userName)
{
_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 realAmount = _userLevel.CalcRealAmount(amount);
Console.WriteLine("You only paid $" + realAmount + " for this book.");
_paidMoney += realAmount;
_userLevel.StateCheck();
}
}
abstract class UserLevel // State
{
protected User _user;
public UserLevel(User user) { _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);
}
}
}
StateCheckUser) 僅負責協調:顯示資訊 → 委派計算 → 累計金額 → 觸發檢查
NormalUser (95%) --> SilverUser (90%) --> GoldUser (80%) --> DiamondUser (70%)
↑ 1000 ↑ 2000 ↑ 5000 (終態)