Khi nào nên sử dụng tính kế thừa, khi nào nên sử dụng 'chỉ là trường boolean'?


18

Trong ứng dụng Rails của chúng tôi, chúng tôi đang thêm thông báo. Một số trong số này là blocking: Chúng ngăn chặn tiến trình của bất kỳ tài nguyên nào chúng được thêm vào, bởi vì một số thông tin về tài nguyên đó bị thiếu.

Các thông báo khác là thông báo đơn giản, và chỉ cung cấp thông tin.

Hôm nay tôi đã có một cuộc thảo luận với một lập trình viên khác trong nhóm của chúng tôi. Tôi đã tạo cấu trúc thừa kế như thế này:

nhập mô tả hình ảnh ở đây

Tuy nhiên, anh ta muốn tôi chỉ thêm blockingvào như một phương thức trả về boolean trên mỗi Thông báo và chỉ định danh sách các lớp con đang chặn bên trong lớp cha Thông báo.

Sự khác biệt giữa các phương pháp này không lớn lắm; Theo cách tiếp cận của tôi, người ta không phải chỉ định danh sách này, giữ cho lớp gốc sạch hơn. Mặt khác, logic đặc biệt xảy ra Notification::Blockingngay bây giờ cũng không lớn lắm.

Loại trừu tượng nào phù hợp hơn cho vấn đề này?


11
Một lớp cha mẹ không bao giờ nên biết về nó. Tại sao bạn cần giữ một danh sách các lớp con?
coteyr

Làm thế nào họ được thêm vào một tài nguyên và làm thế nào để họ ngăn chặn tiến trình của nó?
null

3
Tại sao bạn cần rất nhiều lớp thông báo? Âm thanh với tôi như bạn có thể tạo một lớp thông báo, sau đó để dữ liệu điều khiển các hành động thay vì các loại dữ liệu.
Đã xem

1
@Trisped: đúng, nếu bạn thấy mình chuyển một khía cạnh của hành vi vào lớp cơ sở với một danh sách đầy đủ các trường hợp, thì hãy can đảm thuyết phục bạn, thừa nhận rằng bạn không thực sự thiết kế một lớp cơ sở có thể sử dụng để tùy chỉnh bằng cách mở rộng và di chuyển tất cả các hành vi vào lớp cơ sở!
Steve Jessop

Câu trả lời:


35

Bạn muốn tránh các lớp cơ sở biết về các lớp dẫn xuất. Nó giới thiệu khớp nối chặt chẽ và là một vấn đề đau đầu về bảo trì vì bạn phải nhớ thêm vào danh sách mỗi khi bạn tạo một lớp dẫn xuất mới.

Nó cũng sẽ ngăn bạn có thể đưa lớp Thông báo vào gói / lắp ráp có thể tái sử dụng nếu bạn muốn sử dụng lớp này trong nhiều dự án.

Nếu bạn thực sự muốn sử dụng một lớp cơ sở duy nhất, một cách khác để giải quyết điều này là thêm một thuộc tính ảo hoặc phương thức IsBlocking trên lớp Thông báo cơ sở. Các lớp dẫn xuất sau đó có thể ghi đè lên đó để trả về đúng hoặc sai. Bạn sẽ có một giải pháp lớp duy nhất mà không có lớp cơ sở biết về các lớp dẫn xuất.


3
Điều này. Đưa ra quyết định ở một nơi. Đừng phân tán kiến ​​thức về các lớp chặn giữa lớp và danh sách.
candied_orange

Đây là công việc tôi làm, hoạt động rất tốt và rất có thể tái sử dụng.
coteyr

13

và chỉ định danh sách các lớp con đang chặn bên trong lớp cha Thông báo.

Điều đó trông rất đặc biệt và là một mùi mã đặc biệt.

Tôi sẽ cung cấp các lớp con nếu bạn có sự khác biệt về hành vi giữa các lớp và bạn muốn xử lý tất cả các thông báo này theo cùng một cách (nghĩa là sử dụng đa hình ).


1
Tôi nghĩ rằng "hành vi" là chìa khóa ở đây: khi đó chỉ là dữ liệu, trường phải là một phân biệt đối xử đầy đủ. Hành vi là lý do tốt hơn để sử dụng đa hình tuy nhiên người ta phải luôn luôn xem xét độ phức tạp bảo trì khi tạo cấu trúc phân cấp thừa kế. Đọc en.wikipedia.org/wiki/Cysis_over_inherribution
cottsak

7

Ngược lại với các câu trả lời hiện có, tôi sẽ đề xuất rằng thuộc tính boolean là tùy chọn tốt nhất nếu chế độ được sử dụng bắt buộc phải được thay đổi động (ví dụ: thông qua tệp cấu hình cung cấp danh sách các loại sẽ bị chặn và cái nào không).

Điều đó nói rằng, một thiết kế tốt hơn ngay cả trong tình huống này có thể là sử dụng một đối tượng Trang trí.


1

Tôi sẽ nói rằng nó phụ thuộc vào mức độ đặc biệt khác của thông báo chặn, mặc dù suy nghĩ đầu tiên của tôi là đi với "cả hai":

class Notification
 virtual Boolean Blocking{get return false;}

class BlockingNotification inherits Notification
 virtual overrides Boolean Blocking{get return true;}

Bằng cách đó, bạn có thể sử dụng n.Blockinghoặc n is BlockingNotification(tất cả bằng mã giả), mặc dù, nếu bạn sẽ cho phép một lớp thực hiện một Blockinggiá trị nhạy cảm theo ngữ cảnh , khi bạn phải kiểm tra giá trị đó mỗi lần, BlockingNotificationlớp sẽ trở thành ít hữu ích.

Trong mọi trường hợp, tôi đồng ý với các câu trả lời khác mà bạn không muốn triển khai lớp cơ sở Blockingphải biết về các lớp dẫn xuất.


0

Thay vì tạo hai lớp cơ sở và nhiều phiên bản của mỗi lớp, hãy tạo một lớp thông báo bằng một bool để cho biết liệu thông báo có bị chặn hay không và bất kỳ thông tin nào khác cần thiết để truyền thông báo đến người dùng.

Điều này cho phép bạn sử dụng một bộ mã để xử lý và trình bày thông báo và giảm độ phức tạp của mã.

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.