Trong loạt bài đăng trên blog này , Eric Lippert mô tả một vấn đề trong thiết kế hướng đối tượng bằng cách sử dụng thuật sĩ và chiến binh làm ví dụ, trong đó:
abstract class Weapon { }
sealed class Staff : Weapon { }
sealed class Sword : Weapon { }
abstract class Player
{
public Weapon Weapon { get; set; }
}
sealed class Wizard : Player { }
sealed class Warrior : Player { }
và sau đó thêm một vài quy tắc:
- Một chiến binh chỉ có thể sử dụng một thanh kiếm.
- Một thuật sĩ chỉ có thể sử dụng một nhân viên.
Sau đó, anh ta tiếp tục chứng minh các vấn đề bạn gặp phải nếu bạn cố thực thi các quy tắc này bằng hệ thống loại C # (ví dụ: làm cho Wizard
lớp chịu trách nhiệm đảm bảo rằng một trình hướng dẫn chỉ có thể sử dụng một nhân viên). Bạn vi phạm Nguyên tắc thay thế Liskov, ngoại lệ rủi ro trong thời gian chạy hoặc kết thúc bằng mã khó gia hạn.
Giải pháp mà anh ta đưa ra là không có xác nhận nào được thực hiện bởi lớp Người chơi. Nó chỉ được sử dụng để theo dõi trạng thái. Sau đó, thay vì cho người chơi một vũ khí bằng cách:
player.Weapon = new Sword();
trạng thái được sửa đổi bởi Command
s và theo Rule
s:
... Chúng tôi tạo ra một
Command
đối tượng được gọi làWield
có hai đối tượng trạng thái trò chơi, aPlayer
và aWeapon
. Khi người dùng đưa ra lệnh cho hệ thống, thuật sĩ này sẽ sử dụng thanh kiếm đó, khi đó lệnh đó được đánh giá trong bối cảnh của một tập hợpRule
s, tạo ra một chuỗiEffect
s. Chúng ta có mộtRule
câu nói rằng khi người chơi cố gắng sử dụng vũ khí, thì hiệu quả là vũ khí hiện có, nếu có, bị rơi và vũ khí mới trở thành vũ khí của người chơi. Chúng tôi có một quy tắc khác củng cố quy tắc đầu tiên, đó là các hiệu ứng của quy tắc đầu tiên không áp dụng khi thuật sĩ cố gắng sử dụng thanh kiếm.
Tôi thích ý tưởng này về nguyên tắc, nhưng có một mối quan tâm về cách nó có thể được sử dụng trong thực tế.
Dường như không có gì ngăn cản nhà phát triển phá vỡ các Commands
và Rule
chỉ bằng cách đặt Weapon
trên a Player
. Tài Weapon
sản cần phải được truy cập bằng Wield
lệnh, vì vậy nó không thể được thực hiện private set
.
Vì vậy, những gì làm ngăn chặn một nhà phát triển từ việc này? Có phải họ chỉ cần nhớ không?