الگوی State

در الگوی state، رفتاری که یک object دارد بسته به وضعیت آن متغیر است و به عبارتی رفتار object، تابعی از وضعیت آن است. الگوی stateبرای مثال یک کلاس order را به عنوان context در نظر بگیرید که رفتاری برای اضافه کردن order item دارد. در نظر بگیرید که order یک مجموعه وضعیتی دارد که روی رفتارهای آن تاثیر گذار است. بنابراین conditional statementهایی داریم که وضعیت object را چک می کنند و کاری را انجام می دهند. public class Order { public OrderState State { get; set; } public void AddItem(OrderItem item) { if (State == OrderState.Draft) // add item to list of items else // throw an error } public void Cancel() { if (State != OrderState.Shipped) State = OrderState.Cancelled; else // throw an error } } public enum OrderState { Draft, Confirmed, Shipped, Cancelled, }در الگوی state، آبجکتی تحت عنوان state وجود دارد که در جایگاه abstract قرار دارد و دارای concrete classهایی می باشد. در ادامه رفتارهایی که بسته به state متفاوت هستند را در قالب یک hierarchy مدل می کنیم و در context از آن استفاده می کنیم.public abstract class OrderState { public abstract bool CanModify(); } internal class Confirmed : OrderState { public override bool CanModify() => false; } internal class Draft : OrderState { public override bool CanModify() => true; } internal class Cancelled : OrderState { public override bool CanModify() => false; }public class Order { public OrderState State { get; set; } public void AddItem(OrderItem item) { if (State.CanModify()) // add item to list of items else // throw an error } public void Cancel() { if (this.state.CanCancel()) this.state = new Cancelled(); } }به طور کلی، context درخواست هایی که state-specific هستند را به concrete state پاس می دهد در حالی که آن concrete state را نمی شناسد. ممکن است در مواردی نیاز داشته باشیم که context، خودش را نیز پاس دهد و concrete stateها می توانند از دیتای context استفاده کنند.نکته ای که وجود دارد، client درگیر مساله stateها نمی شود و تنها context را می بیند. زمانی که در state pattern رفتارهای وابسته به state را وارد یک hierarchy دیگر می کنید، این امکان فراهم می شود که اضافه کردن stateها و transitionهای جدید براحتی اتفاق بیافتد.موضوع دیگری که وجود دارد، بسته به نوع implementation، اگر stateهای ما state less باشند، می توانیم از طریق الگوی flyweight آنها را share کنیم. مساله ای که وجود دارد این است که چه کسی مسئول state transition است؟ به طور کلی دو رویکرد وجود دارد. transition از طریق context انجام شود و یا از طریق state hierarchy انجام شود. موضوعی که وجود دارد، زمانی که state transition را وارد context می کنیم، فرض می کنیم که تا حد زیادی این state transitionها ثابت هستند و context بر state hierarchy آگاه است. وجود state transition در context مساله را ساده می کند اما دانش استفاده از state transitionها را نیز به context اضافه می کند.نکته ای که در پاس دادن context به state وجود دارد این است که تصمیم گیری state transition با چه کسی باشد و اینکه چه کسی آن را انجام دهد، دو موضوع متفاوت هستند. نکته ای که باید به آن توجه کنیم این است، ایده تغییر state بیرون از context مساله encapsulation را نقض می کند. برای حفظ encapsulation، می توانیم تصمیم گیری state transition را به state hierarchy واگذار کنیم و تغییر در context انجام شود.به طور خلاصه، رفتار وابسته به state در سطح پیاده سازی را به عنوان variability در نظر می گیریم و رفتار وابسته به state در سطح abstract و زمانی که استفاده می شود را به عنوان commonality در نظر می گیریم.