Chỉ vì một hệ thống phức tạp không có nghĩa là bạn phải làm cho nó phức tạp . Nếu bạn có một lớp có quá nhiều phụ thuộc (hoặc Cộng tác viên) như thế này:
public class MyAwesomeClass {
public class MyAwesomeClass(IDependency1 _d1, IDependency2 _d2, ... , IDependency20 _d20) {
// Assign it all
}
}
... Sau đó, nó trở nên quá phức tạp và bạn không thực sự theo dõi SRP , phải không? Tôi cá là nếu bạn viết ra những gì MyAwesomeClass
trên thẻ CRC thì nó sẽ không vừa với thẻ chỉ mục hoặc bạn phải viết bằng những chữ cái không thể đọc được.
Những gì bạn có ở đây là các chàng trai của bạn chỉ tuân theo Nguyên tắc phân chia giao diện thay vào đó và có thể đã đưa nó đến một thái cực nhưng đó là một câu chuyện hoàn toàn khác. Bạn có thể lập luận rằng các phụ thuộc là các đối tượng miền (xảy ra) tuy nhiên có một lớp xử lý 20 đối tượng miền cùng một lúc sẽ kéo dài nó quá xa.
TDD sẽ cung cấp cho bạn một chỉ số tốt về mức độ của một lớp học. Nói thẳng ra; nếu một phương thức kiểm tra có mã thiết lập cần mãi mãi để viết (ngay cả khi bạn cấu trúc lại các bài kiểm tra) thì MyAwesomeClass
có lẽ bạn có quá nhiều việc phải làm.
Vậy làm thế nào để bạn giải quyết câu hỏi hóc búa này? Bạn chuyển trách nhiệm sang các lớp khác. Có một số bước bạn có thể thực hiện trên một lớp có vấn đề này:
- Xác định tất cả các hành động (hoặc trách nhiệm) mà lớp của bạn thực hiện với các phụ thuộc của nó.
- Nhóm các hành động theo phụ thuộc liên quan chặt chẽ.
- Tái tổ chức! Tức là tái cấu trúc từng hành động được xác định thành các lớp mới hoặc (quan trọng hơn).
Một ví dụ trừu tượng về tái cấu trúc trách nhiệm
Hãy C
là một lớp mà có một số phụ thuộc D1
, D2
, D3
, D4
mà bạn cần phải cấu trúc lại để sử dụng ít hơn. Khi chúng tôi xác định phương thức nào C
gọi vào các phụ thuộc, chúng tôi có thể tạo một danh sách đơn giản về nó:
D1
- performA(D2)
,performB()
D2
- performD(D1)
D3
- performE()
D4
- performF(D3)
Nhìn vào danh sách chúng ta có thể thấy điều đó D1
và D2
có liên quan với nhau vì lớp học cần chúng cùng nhau bằng cách nào đó. Chúng ta cũng có thể thấy D4
nhu cầu đó D3
. Vì vậy, chúng tôi có hai nhóm:
Group 1
- D1
<->D2
Group 2
- D4
->D3
Các nhóm là một chỉ báo rằng lớp hiện có hai trách nhiệm.
Group 1
- Một để xử lý việc gọi hai đối tượng cần nhau. Có lẽ bạn có thể để lớp của mình C
loại bỏ nhu cầu xử lý cả hai phụ thuộc và thay vào đó một trong số họ xử lý các cuộc gọi đó. Trong nhóm này, rõ ràng D1
có thể có một tài liệu tham khảo D2
.
Group 2
- Trách nhiệm khác cần một đối tượng để gọi một đối tượng khác. Không thể D4
xử lý D3
thay vì lớp học của bạn? Sau đó, chúng ta có thể loại bỏ D3
khỏi lớp C
bằng cách D4
thực hiện các cuộc gọi thay thế.
Đừng lấy câu trả lời của tôi như đặt trong đá vì ví dụ này rất trừu tượng và đưa ra rất nhiều giả định. Tôi khá chắc chắn có nhiều cách để cấu trúc lại điều này, nhưng ít nhất các bước có thể giúp bạn có được một quy trình nào đó để di chuyển các trách nhiệm xung quanh thay vì chia tách các lớp.
Biên tập:
Trong số các ý kiến @Emmad Karem nói:
"Nếu lớp của bạn có 20 tham số trong hàm tạo, có vẻ như nhóm của bạn không biết SRP là gì. Nếu bạn có một lớp chỉ có một thứ, làm thế nào nó có 20 phụ thuộc?" - Tôi nghĩ rằng Nếu bạn có một lớp Khách hàng, không có gì lạ khi có 20 tham số trong hàm tạo.
Đúng là các đối tượng DAO có xu hướng có rất nhiều tham số, mà bạn phải đặt trong hàm tạo của mình và các tham số thường là các kiểu đơn giản như chuỗi. Tuy nhiên, trong ví dụ về một Customer
lớp, bạn vẫn có thể nhóm các thuộc tính của nó bên trong các lớp khác để làm cho mọi thứ đơn giản hơn. Chẳng hạn như có một Address
lớp với các đường phố và một Zipcode
lớp có chứa mã zip và cũng sẽ xử lý logic nghiệp vụ như xác thực dữ liệu:
public class Address {
private String street1;
//...
private Zipcode zipcode;
// easy to extend
public bool isValid() {
return zipcode.isValid();
}
}
public class Zipcode {
private string zipcode;
public bool isValid() {
// return regex match that zipcode contains numbers
}
}
Điều này được thảo luận thêm trong bài đăng trên blog "Không bao giờ, không bao giờ, không bao giờ sử dụng Chuỗi trong Java (hoặc ít nhất là thường xuyên)" . Thay thế cho việc sử dụng các hàm tạo hoặc các phương thức tĩnh để làm cho các đối tượng phụ dễ tạo hơn, bạn có thể sử dụng một mẫu xây dựng chất lỏng .