2012-04-04 38 views
5

Chúng tôi thường sử dụng các bảng liệt kê đơn giản để thể hiện trạng thái trên các thực thể của chúng tôi. Vấn đề xảy ra khi chúng tôi giới thiệu hành vi phụ thuộc phần lớn vào trạng thái hoặc nơi chuyển đổi trạng thái phải tuân thủ các quy tắc kinh doanh nhất định.Mẫu trạng thái và thiết kế điều khiển tên miền

Lấy ví dụ sau đây (có sử dụng một điều tra để đại diện cho nhà nước):

public class Vacancy { 

    private VacancyState currentState; 

    public void Approve() { 
     if (CanBeApproved()) { 
      currentState.Approve(); 
     } 
    } 

    public bool CanBeApproved() { 
     return currentState == VacancyState.Unapproved 
      || currentState == VacancyState.Removed 
    } 

    private enum VacancyState { 
     Unapproved, 
     Approved, 
     Rejected, 
     Completed, 
     Removed 
    } 
} 

Bạn có thể thấy rằng lớp này sẽ sớm trở nên khá dài dòng như chúng ta thêm phương pháp để chối, Hoàn thành, Di chuyển, vv

Thay vào đó chúng ta có thể giới thiệu mô hình nhà nước, cho phép chúng tôi để đóng gói mỗi tiểu bang như một đối tượng:

public abstract class VacancyState { 

    protected Vacancy vacancy; 

    public VacancyState(Vacancy vacancy) { 
     this.vacancy = vacancy; 
    } 

    public abstract void Approve(); 
    // public abstract void Unapprove(); 
    // public abstract void Reject(); 
    // etc. 

    public virtual bool CanApprove() { 
     return false; 
    } 
} 

public abstract class UnapprovedState : VacancyState { 

    public UnapprovedState(vacancy) : base(vacancy) { } 

    public override void Approve() { 
     vacancy.State = new ApprovedState(vacancy); 
    } 

    public override bool CanApprove() { 
     return true; 
    } 
} 

Điều này làm cho nó dễ dàng để chuyển betwee n bang, thực hiện logic trên cơ sở về tình trạng hiện tại hoặc thêm trạng thái mới nếu chúng ta cần phải:

// transition state 
vacancy.State.Approve(); 

// conditional 
model.ShowRejectButton = vacancy.State.CanReject(); 

đóng gói này có vẻ sạch hơn, nhưng nếu có đủ các quốc gia, những cũng có thể trở nên rất tiết. Tôi đọc Greg Young's post on State Pattern Misuse đề xuất sử dụng đa hình thay vì (vì vậy tôi sẽ có các lớp ApprovedVacancy, UnapprovedVacancy vv), nhưng không thể thấy cách này sẽ giúp tôi.

Tôi có nên ủy quyền chuyển tiếp trạng thái như vậy sang dịch vụ miền hoặc việc tôi sử dụng mẫu trạng thái trong tình huống này có đúng không?

Trả lời

5

Để trả lời câu hỏi của bạn, bạn không nên ủy quyền điều này cho dịch vụ miền và việc bạn sử dụng mẫu Nhà nước gần như chính xác.

Để xây dựng, trách nhiệm duy trì trạng thái của đối tượng thuộc về đối tượng đó, vì vậy việc chuyển hạng này thành dịch vụ miền dẫn đến mô hình thiếu máu. Đó không phải là để nói rằng trách nhiệm của sửa đổi nhà nước không thể được ủy nhiệm thông qua việc sử dụng các mẫu khác, nhưng điều này nên được minh bạch cho người tiêu dùng của đối tượng.

Điều này dẫn tôi đến việc bạn sử dụng mẫu trạng thái. Đối với hầu hết các phần, bạn đang sử dụng đúng mẫu. Một phần mà bạn đi lạc một chút là trong các vi phạm Luật của Demeter của bạn. Người tiêu dùng của đối tượng của bạn không nên tiếp cận đối tượng và phương thức gọi của bạn trên trạng thái của nó (ví dụ như vacancy.State.CanReject()), nhưng đối tượng của bạn nên ủy nhiệm cuộc gọi này đến đối tượng State (ví dụ vacancy.CanReject() - > bool CanReject() {return _state.CanReject();}). Người tiêu dùng của đối tượng của bạn không cần phải biết rằng bạn thậm chí còn sử dụng mẫu trạng thái.

Để nhận xét về bài viết bạn đã tham chiếu, mẫu trạng thái dựa trên tính đa hình vì nó tạo điều kiện cho cơ chế. Các đối tượng đóng gói một thực hiện Nhà nước có thể ủy thác một cuộc gọi đến bất kỳ thực hiện hiện đang được giao cho dù đó là một cái gì đó mà không làm gì, ném một ngoại lệ, hoặc thực hiện một số hành động. Ngoài ra, trong khi chắc chắn có thể gây ra vi phạm Nguyên tắc thay thế Liskov bằng cách sử dụng mẫu trạng thái (hoặc bất kỳ mẫu nào khác), điều này không được xác định bởi thực tế là đối tượng có thể ném ngoại lệ hay không, nhưng bằng cách sửa đổi đối tượng có thể được làm bằng ánh sáng của mã hiện có (đọc this để thảo luận thêm).

+0

nếu người tiêu dùng không nên thay đổi trạng thái trực tiếp chắc chắn điều này có nghĩa là tôi sẽ kết thúc bằng một phương pháp cho mỗi chuyển đổi trạng thái trên thực thể của tôi. Vì vậy, những gì tôi thực sự đạt được ở đây? –

+2

Bạn nhận được đóng gói và sự vắng mặt của một loạt các tuyên bố nếu :) Đây là những lợi ích chính thức: 1. Nó địa phương hóa hành vi nhà nước cụ thể và hành vi phân vùng cho các tiểu bang khác nhau. 2. Nó làm cho trạng thái chuyển tiếp rõ ràng. 3. Các đối tượng nhà nước có thể được chia sẻ. –

+0

Cảm ơn.Một câu hỏi cuối cùng - chúng tôi đang kiên trì Vị ​​trí tuyển dụng vào một cửa hàng tài liệu (RavenDB). Bạn có gợi ý sử dụng để tải đối tượng trạng thái có liên quan hay chỉ lưu trữ toàn bộ đối tượng trạng thái –

Các vấn đề liên quan