Có nhiều kế thừa vi phạm Nguyên tắc trách nhiệm duy nhất?


18

Nếu bạn có một lớp kế thừa từ hai lớp riêng biệt, điều này không có nghĩa là lớp con của bạn tự động thực hiện (ít nhất) 2 thứ, một lớp từ mỗi siêu lớp?

Tôi tin rằng không có sự khác biệt nếu bạn có nhiều kế thừa giao diện.

Chỉnh sửa: Để rõ ràng, tôi tin rằng nếu phân lớp nhiều lớp vi phạm SRP, thì việc triển khai nhiều giao diện (không đánh dấu hoặc giao diện cơ bản (ví dụ so sánh)) cũng vi phạm SRP.


Nói rõ hơn, bạn cũng tin rằng việc thực hiện nhiều giao diện vi phạm SRP?

Tôi tin rằng nếu phân lớp nhiều lớp vi phạm SRP, thì việc thực hiện nhiều giao diện (không đánh dấu) cũng vi phạm SRP.
m3th0dman

Tôi sẽ nêu lên câu hỏi này, nhưng bạn đã đưa ý kiến ​​của bạn vào câu hỏi mà tôi không đồng ý.
Nicole

1
@NickC: Tôi chưa nói ý kiến ​​của tôi (bạn nên đọc nhận xét trên); Tôi sẽ chỉnh sửa câu hỏi để làm cho nó rõ ràng hơn.
m3th0dman

1
@NickC Tôi không có ý kiến, đó là lý do tại sao tôi hỏi. Tôi chỉ nói rằng hai cái này có liên quan (kế thừa giao diện và kế thừa lớp); nếu nó vi phạm quyền thừa kế lớp thì nó cũng vi phạm quyền thừa kế giao diện, nếu nó không vi phạm cho cái kia thì nó cũng không vi phạm cho cái kia. Và tôi không quan tâm đến việc bỏ phiếu lên ...
m3th0dman

Câu trả lời:


17

Theo nghĩa rất hẹp, câu trả lời là "Có": giả sử rằng các lớp cơ sở hoặc giao diện của bạn được thiết kế cho một mục đích duy nhất, kế thừa cả hai sẽ tạo ra một lớp có nhiều trách nhiệm. Tuy nhiên, đó có phải là "một điều xấu" hay không phụ thuộc vào bản chất của các lớp hoặc giao diện mà bạn đang kế thừa.

Bạn có thể phân vùng các lớp và giao diện của mình thành hai nhóm chính - những nhóm giải quyết sự phức tạp thiết yếu của hệ thống của bạn và các nhóm giải quyết sự phức tạp tình cờ của nó. Nếu kế thừa từ nhiều hơn một "lớp phức tạp thiết yếu", thì đó là điều xấu; nếu bạn kế thừa từ một lớp "thiết yếu" và một hoặc nhiều lớp "tình cờ" thì không sao.

Ví dụ: trong hệ thống thanh toán, bạn có thể có các lớp để thể hiện hóa đơn và chu kỳ thanh toán (chúng giải quyết sự phức tạp cần thiết) và các lớp cho các đối tượng vẫn tồn tại (chúng giải quyết sự phức tạp ngẫu nhiên). Nếu bạn thừa hưởng như thế này

class BillingCycleInvoice : public BillingCycle, public Invoice {
};

đó là xấu: bạn BillingCycleInvoicecó một trách nhiệm hỗn hợp vì nó liên quan đến sự phức tạp thiết yếu của hệ thống.

Mặt khác, nếu bạn thừa hưởng như thế này

class PersistentInvoice : public Invoice, public PersistentObject {
};

Lớp học của bạn vẫn ổn: về mặt kỹ thuật, nó phục vụ hai mối quan tâm cùng một lúc, nhưng vì chỉ một trong số đó là điều cần thiết, bạn có thể xóa bỏ việc thừa kế một điều tình cờ là "chi phí kinh doanh".


3
Ví dụ thứ hai của bạn rất giống với những gì sẽ là mối quan tâm xuyên suốt trong lập trình hướng theo khía cạnh. Điều này nói rằng các đối tượng của bạn đôi khi cần phải thực hiện mọi việc (như ghi nhật ký, kiểm tra kiểm soát truy cập hoặc duy trì) không phải là trọng tâm cốt lõi của chúng và bạn có thể làm điều đó với nhiều kế thừa. Đó là một cách sử dụng công cụ thích hợp.

Đơn giản nhất là nếu việc thực hiện một giao diện mới đòi hỏi phải hoàn thành chức năng của lớp thì không. Nhưng nếu thêm trách nhiệm mới Thực hiện giao diện với một số lớp khác thì việc phụ thuộc sẽ không bao giờ vi phạm SRP
Ramankingdom

9

SRP là một hướng dẫn để tránh các lớp thần, điều này rất tệ, nhưng nó cũng có thể được thực hiện theo đúng nghĩa đen và một dự án bắt đầu với hàng tấn các lớp không thể thực hiện bất cứ điều gì mà không cần kết hợp một chút. Nhiều kế thừa / nhiều giao diện có thể là một dấu hiệu mà một lớp đang trở nên quá lớn, nhưng nó cũng có thể là một dấu hiệu cho thấy sự tập trung của bạn quá chi tiết cho nhiệm vụ trong tay và giải pháp của bạn được thiết kế quá mức, hoặc nó có thể đơn giản là một cách hoàn hảo trường hợp sử dụng hợp lệ cho nhiều thừa kế và lo lắng của bạn là không có cơ sở.

Thiết kế phần mềm là nghệ thuật nhiều như khoa học, nó là một hành động cân bằng của nhiều lợi ích cạnh tranh. Chúng tôi có các quy tắc để giúp tránh những điều chúng tôi biết là đi xa theo một hướng gây ra vấn đề, nhưng những quy tắc đó có thể dễ dàng đưa chúng tôi đến một nơi tồi tệ hoặc tồi tệ hơn những gì chúng tôi đang cố gắng tránh ở nơi đầu tiên.


4

Một chút nào đó. Hãy tập trung vào nguyên tắc chính cho SRP:

Một lớp chỉ nên có một lý do để thay đổi.

Nhiều kế thừa không ép buộc điều này, nhưng có xu hướng dẫn đến nó. Nếu lớp ghi đè hoặc thực hiện các lớp cơ sở của nó, đó có xu hướng là lý do nhiều hơn để nó thay đổi. Theo cách này, giao diện nhiều kế thừa có xu hướng rắc rối hơn so với kế thừa lớp. Nếu hai lớp được kế thừa nhưng không bị ghi đè, thì lý do để thay đổi tồn tại trong các lớp cơ sở không phải là lớp mới.

Những nơi mà nhiều kế thừa không vi phạm SRP là khi tất cả ngoại trừ một trong các loại cơ sở không phải là thứ mà lớp đang thực hiện, nhưng hoạt động như một đặc điểm mà lớp xảy ra. Xem xét IDisposabletrong C #. Những thứ chỉ dùng một lần không có hai trách nhiệm, giao diện chỉ hoạt động như một khung nhìn vào các lớp có chung đặc điểm nhưng có trách nhiệm khác nhau.


2

Không theo ý kiến ​​của tôi. Đối với tôi, một trách nhiệm duy nhất là "mô hình người dùng ứng dụng của tôi". Tôi có thể cần phân phối dữ liệu đó qua dịch vụ web và lưu trữ dữ liệu đó trong cơ sở dữ liệu quan hệ. Tôi có thể cung cấp chức năng đó bằng cách kế thừa một vài lớp hỗn hợp.

Điều đó không có nghĩa là lớp học có ba trách nhiệm. Điều đó có nghĩa là một phần trách nhiệm mô hình hóa người dùng đòi hỏi phải hỗ trợ tuần tự hóa và kiên trì.


2

Không có gì. Trong Java, bạn có thể có một giao diện đại diện cho một số loại đối tượng miền - ví dụ như một Foo. Nó có thể cần phải được so sánh với các đối tượng Foo khác, và do đó, nó thực hiện So sánh (với logic so sánh được đưa ra ngoài trong một lớp So sánh); có thể là đối tượng này cũng cần phải được tuần tự hóa, để nó có thể được vận chuyển qua mạng; và nó có thể cần phải được Clonizable. Do đó, lớp thực hiện ba giao diện nhưng không có logic nào bên trong để hỗ trợ chúng ngoài giao diện được Foo hỗ trợ.

Điều đó nói rằng, thật ngớ ngẩn khi đưa SRP đến mức cực đoan. Nếu một lớp định nghĩa nhiều hơn một phương thức, nó có vi phạm SRP không? Tất cả các Đối tượng Java đều có phương thức toString () và phương thức bằng (Object), có nghĩa là MỌI đối tượng trong Java chịu trách nhiệm cho cả sự bình đẳng và tự đại diện. Đó có phải là một điều xấu?


1

Tôi đoán nó phụ thuộc vào cách bạn xác định trách nhiệm. Trong ví dụ iostream cổ điển, nó không vi phạm SRP. IOstream chịu trách nhiệm quản lý một luồng hai chiều.

Sau khi bạn hết trách nhiệm nguyên thủy, bạn chuyển sang trách nhiệm cấp cao chung hơn, sau tất cả, làm thế nào để bạn xác định trách nhiệm của điểm vào chính của bạn? Trách nhiệm của nó phải là 'trở thành điểm vào chính' chứ không phải 'mọi thứ mà ứng dụng của tôi làm' nếu không thì không thể vi phạm SRP và tạo ra một ứng dụng.

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.