Kế thừa sai


12

Tôi có một số mã trong đó một mô hình thừa kế tốt đã xuống dốc và tôi đang cố gắng để hiểu tại sao và làm thế nào để sửa nó. Về cơ bản, hãy tưởng tượng bạn có một hệ thống phân cấp Zoo:

class Animal  
class Parrot : Animal 
class Elephant : Animal 
class Cow : Animal

Vân vân.

Bạn có các phương thức eat (), run (), v.v. và tất cả đều tốt. Rồi một ngày nọ có người đến và nói - lớp CageBuilder của chúng tôi hoạt động rất tốt và sử dụng động vật. weight () và Animal.height (), ngoại trừ Bison châu Phi mới quá mạnh và có thể phá vỡ bức tường, vì vậy tôi sẽ thêm vào thêm một thuộc tính cho lớp Animal - isAfricanBizon () và sử dụng nó khi chọn vật liệu và chỉ ghi đè lên nó cho lớp AfricanBizon. Người tiếp theo đến và làm một cái gì đó tương tự và điều tiếp theo bạn biết bạn có tất cả các thuộc tính này cụ thể cho một số tập hợp con của hệ thống phân cấp vào lớp cơ sở.

Cách tốt để cải thiện / cấu trúc lại mã như vậy là gì? Một cách khác ở đây sẽ là chỉ sử dụng Dynamic_casts để kiểm tra các loại nhưng điều đó làm tắc nghẽn người gọi và thêm một loạt các if-then-other ở khắp mọi nơi. Bạn có thể có các giao diện cụ thể hơn ở đây nhưng nếu tất cả những gì bạn có là tham chiếu lớp cơ sở cũng không giúp được gì nhiều. Bất cứ một đề nghị nào khác? Ví dụ?

Cảm ơn!


@James: sau đó bạn sẽ phải viết trình phân tích cú pháp bằng tay. : S
Matteo Italia

5
Rõ ràng đây là một trường hợp yêu cầu vô lý của khách hàng. Không có bò rừng ở Châu Phi. Bạn không thể thiết kế các mô hình đối tượng không có kết nối với thực tế. Trừ khi thực tế đó được tạo ra bởi bàn tay đầy đô la. Mà giải quyết vấn đề.
Hans Passant

1
Ăn hết bò rừng? [Tôi đã đăng bài này trước đây nhưng vì lý do nào đó đã bị xóa, có lẽ là do những kẻ
ngốc

Có phải CageBuilder cần đẳng cấp riêng? Điều gì xảy ra nếu có một phương thức MakeCage mặc định, có thể được ghi đè bởi mỗi lớp riêng lẻ.
Công việc

1
Bạn đề cập đến if-then-other lộn xộn như một nhược điểm đối với người gọi nhưng ngay khi người gọi bắt đầu sử dụng isAfricanBizon (), họ sẽ tự động làm lộn xộn mã với if-then-other. Vì vậy, đó là sự lộn xộn giữa if-then-other với isAfricanBizon () hoặc if-then-other với sự biến đổi động.
davidk01

Câu trả lời:


13

Có vẻ như vấn đề là thay vì triển khai RequestConcittleWall (), họ đã triển khai một lệnh gọi IsAfricanBison (), và sau đó di chuyển logic về việc liệu bức tường có nên thay đổi ngoài phạm vi của lớp hay không. Các lớp học của bạn nên phơi bày hành vi và yêu cầu, không phải danh tính; người tiêu dùng của bạn thuộc các lớp này nên làm việc từ những gì họ được nói, không dựa trên những gì họ đang nói.


1
-1: Chỉ nói những gì không nên làm. OP đã biết rằng đây là một ý tưởng tồi, do đó, câu hỏi.
Steven Evers

12

isAfricanBizon () không chung chung. Giả sử bạn mở rộng trang trại động vật của mình bằng một hyppopotamus cũng quá mạnh nhưng việc trở lại đúng từ isAfricanBizon () để có hiệu quả phù hợp sẽ chỉ là ngớ ngẩn.

bạn luôn muốn thêm các phương thức vào giao diện trả lời câu hỏi cụ thể, trong trường hợp này nó sẽ giống như thế mạnh ()


+1: Mọi người khác dường như đang phá vỡ mô hình khái niệm của lớp (chỉ gói gọn các thuộc tính của các loại động vật khác nhau), để chứa đựng trường hợp sử dụng cụ thể này. Một strengthphương pháp có thể được truy vấn bằng cách material.canHold(animal), cho phép một cách rõ ràng để hỗ trợ các loại vật liệu khác nhau hơn ConcreteWall.
Aidan Cully

Tôi thích cách tiếp cận thuộc tính độ mạnh () tốt hơn đề xuất của RequestConcittleWall () của người khác vì nó linh hoạt hơn để cho phép các yêu cầu trong tương lai. Đối với người mới bắt đầu, hãy làm cho lớp CageBuilder quyết định vật liệu nào đủ mạnh và sau đó bạn có thể dễ dàng mở rộng lớp bằng vật liệu mới.
jhocking

3

Tôi nghĩ vấn đề của bạn là thế này: bạn có nhiều khách hàng khác nhau của thư viện chỉ quan tâm đến một tập hợp con của hệ thống phân cấp nhưng được truyền một con trỏ / tham chiếu đến lớp cơ sở. Trên thực tế, đó là vấn đề mà Dynamic_cast <> đang có để giải quyết.

Đây là vấn đề thiết kế của các máy khách để giảm thiểu việc sử dụng Dynamic_cast <>; họ nên sử dụng nó để xác định xem đối tượng có cần xử lý đặc biệt hay không và nếu có thì tất cả các thao tác trên tham chiếu được chọn xuống.

Nếu bạn có các bộ sưu tập chức năng loại "hỗn hợp" áp dụng cho một số phân cấp phụ riêng biệt, bạn có thể muốn sử dụng mẫu giao diện mà Java và C # sử dụng; có một lớp cơ sở ảo là một lớp ảo thuần và sử dụng động_cast <> để xác định xem một cá thể có cung cấp triển khai cho nó không.


1

Một điều bạn có thể làm là thay thế việc kiểm tra loại rõ ràng như isAfricanBison()kiểm tra các thuộc tính bạn thực sự quan tâm, tức là isTooStrong().


1
isTooStrong () để làm gì? Bạn đang thêm mã cụ thể lồng vào lớp động vật.
Steven Evers

1

Động vật không nên quan tâm đến các bức tường bê tông. Có lẽ bạn có thể thể hiện nó với các giá trị đơn giản.

class Animal {
public:
  virtual ~Animal() {}
  virtual size_t height() const = 0;
  virtual size_t weight() const = 0;
  virtual bool isStrong() const = 0;
};

Cage *CreateCageFromSQL(Animal &a);
Cage *CreateCageFromOrangePeelsAndSticks(Animal &a);

Tôi nghi ngờ rằng điều đó không khả thi mặc dù. Đó là vấn đề với các ví dụ đồ chơi, mặc dù.

Tôi sẽ không bao giờ muốn xem RequestConcittleWalls () hoặc các dòng và dòng của các con trỏ động ở bất kỳ tỷ lệ nào.

Đây thường là một giải pháp rẻ tiền . Thật dễ dàng để duy trì và khái niệm hóa. Và thực sự, vấn đề nói rằng nó gắn liền với loại động vật nào.

class Animal {
public:
  virtual ~Animal() {}
  virtual CageBuilder *getCageBuilder() = 0;
};

Điều này cũng không ngăn cản bạn sử dụng mã được chia sẻ, chỉ gây ô nhiễm cho Động vật một chút.

Nhưng cách lồng được xây dựng có thể là một chính sách của một số hệ thống khác và có thể bạn có nhiều hơn một loại người xây dựng lồng cho mỗi con vật. Có rất nhiều sự kết hợp kỳ lạ và hấp dẫn mà bạn có thể nghĩ ra.

Tôi đã sử dụng Thiết kế dựa trên thành phần để kết thúc tốt đẹp, vấn đề chính với nó là nó có thể gây rắc rối khi quyền sở hữu của Animal được chia sẻ. Làm thế nào để tránh ném vào kẻ hủy diệt là điểm đau.

Double Dispatch là một lựa chọn khác, mặc dù tôi luôn luôn thận trọng để nhảy vào nó.

Ngoài ra, thật khó để đoán vấn đề.


0

Vâng chắc chắn tất cả các động vật có tài sản vốn có của attemptEscape(). Trong khi một số phương pháp có thể đặt ra một falsekết quả trong tất cả các kịch bản trong khi các phương pháp khác có thể có cơ hội dựa trên các phỏng đoán về các đặc điểm nội tại khác của chúng như sizeweight. Sau đó, chắc chắn đến một lúc nào đó attemptEscape()trở nên tầm thường vì nó chắc chắn sẽ trở lạitrue .

Tôi sợ rằng tôi hoàn toàn không hiểu câu hỏi của bạn mặc dù ... tất cả các loài động vật đều có hành động và đặc điểm liên quan. Những người cụ thể cho động vật nên được giới thiệu ở nơi phù hợp. Cố gắng liên hệ trực tiếp Bison với Vẹt không phải là một thiết lập kế thừa tốt và thực sự không phải là một vấn đề trong một thiết kế phù hợp.


-1

Một lựa chọn khác là sử dụng một nhà máy tạo ra các lồng thích hợp cho từng con vật. Tôi nghĩ rằng điều này có thể tốt hơn trong trường hợp điều kiện rất khác nhau đối với mỗi người trong số họ. Nhưng nếu nó chỉ là một điều kiện thì RequiresConcreteWall()phương pháp được đề cập ở trên sẽ làm điều đó.


-1

làm thế nào về recommendCageType () như được đặt trong RequestConcittleWall ()


-2

Tại sao không làm một cái gì đó như thế này

class Animals { /***/ } class HeavyAnimals{} : Animals //The basic class for animals like the African Bison

Với lớp HeavyAnimals, bạn có thể tạo lớp Bison châu Phi bằng cách mở rộng lớp HeavyAnimals.

Vì vậy, bây giờ bạn là lớp cha mẹ (Động vật) có thể được sử dụng để tạo lớp cơ sở khác như lớp HeavyAnimal có thể được sử dụng để tạo lớp Bison Châu Phi và các Động vật nặng khác. Vì vậy, với Bison Châu Phi, giờ đây bạn có quyền truy cập vào các phương thức và tài sản của lớp Thú (đây là cơ sở cho tất cả các loài động vật) và truy cập vào lớp HeavyAnimals (đây là cơ sở cho Động vật nặng)


2
Điều đó có thể hoạt động như một hỗn hợp hoặc đặc điểm, nhưng chắc chắn không phải là một lớp con. Đây chỉ là cầu xin cho nhiều thừa kế vào lần tới khi cần một tài sản khác.
Ordous
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.