Tôi đã thừa hưởng một cơ sở mã gần đây có một số người vi phạm Liskov chính trong đó. Trong các lớp học quan trọng. Điều này đã gây cho tôi những nỗi đau rất lớn. Hãy để tôi giải thích tại sao.
Tôi có Class A
, mà bắt nguồn từ Class B
. Class A
và Class B
chia sẻ một loạt các thuộc tính Class A
ghi đè với việc thực hiện riêng của nó. Đặt hoặc nhận một thuộc Class A
tính có tác dụng khác với cài đặt hoặc nhận chính xác cùng một thuộc tính Class B
.
public Class A
{
public virtual string Name
{
get; set;
}
}
Class B : A
{
public override string Name
{
get
{
return TranslateName(base.Name);
}
set
{
base.Name = value;
FunctionWithSideEffects();
}
}
}
Đặt sang một bên thực tế rằng đây là một cách cực kỳ khủng khiếp để dịch trong .NET, có một số vấn đề khác với mã này.
Trong trường hợp Name
này được sử dụng như một chỉ mục và một biến điều khiển luồng ở một số nơi. Các lớp trên được rải rác khắp codebase ở cả dạng thô và dẫn xuất của chúng. Vi phạm nguyên tắc thay thế Liskov trong trường hợp này có nghĩa là tôi cần biết ngữ cảnh của mỗi lệnh gọi đến từng hàm lấy lớp cơ sở.
Mã này sử dụng các đối tượng của cả hai Class A
và Class B
vì vậy tôi không thể đơn giản tạo ra sự Class A
trừu tượng để buộc mọi người sử dụng Class B
.
Có một số chức năng tiện ích rất hữu ích hoạt động Class A
và các chức năng tiện ích rất hữu ích khác hoạt động Class B
. Lý tưởng nhất là tôi muốn có thể sử dụng bất kỳ chức năng tiện ích nào có thể hoạt động Class A
trên Class B
. Nhiều chức năng Class B
có thể dễ dàng thực hiện Class A
nếu không vi phạm LSP.
Điều tồi tệ nhất ở đây là trường hợp cụ thể này thực sự khó tái cấu trúc vì toàn bộ ứng dụng bản lề trên hai lớp này, hoạt động trên cả hai lớp và sẽ phá vỡ hàng trăm cách nếu tôi thay đổi điều này (mà tôi sẽ làm dù sao).
Những gì tôi sẽ phải làm để khắc phục điều này là tạo một thuộc NameTranslated
tính, đây sẽ là Class B
phiên bản của Name
tài sản và rất, rất cẩn thận thay đổi mọi tham chiếu đến thuộc tính dẫn xuất Name
để sử dụng thuộc NameTranslated
tính mới của tôi . Tuy nhiên, thậm chí một trong những tham chiếu này sai toàn bộ ứng dụng có thể nổ tung.
Cho rằng codebase không có các bài kiểm tra đơn vị xung quanh nó, điều này khá gần với kịch bản nguy hiểm nhất mà nhà phát triển có thể gặp phải. Nếu tôi không thay đổi vi phạm, tôi phải tiêu tốn một lượng lớn năng lượng tinh thần để theo dõi loại đối tượng nào đang được vận hành trong mỗi phương pháp và nếu tôi khắc phục vi phạm, tôi có thể làm cho toàn bộ sản phẩm phát nổ vào thời điểm không phù hợp.