Trước hết, rắn không phải là ONE nguyên tắc, nó tượng trưng cho 5 nguyên tắc khác nhau:
- SRP (Single Trách nhiệm Nguyên tắc): lớp học của bạn nên chỉ có một trách nhiệm rõ ràng;
- OCP (Nguyên tắc đóng mở): lớp học của bạn phải mở để gia hạn nhưng đóng để sửa đổi;
- LSP (Nguyên tắc thay thế của Liskov): hướng dẫn này hướng dẫn bạn quyết định có sử dụng mối quan hệ thừa kế giữa lớp
A
và B
hay không. Thừa kế là phù hợp bất cứ khi nào tất cả các đối tượng của một lớp dẫn xuất B
có thể được thay thế bằng các đối tượng của lớp cha mẹ của chúng A
mà không mất bất kỳ tính năng nào;
- ISP (Nguyên tắc phân đoạn giao diện): tuyên bố rằng không khách hàng nào bị buộc phải phụ thuộc vào các phương pháp không sử dụng;
- DIP (Dependency Injection/Inversion): tuyên bố rằng các mô-đun cấp cao không nên phụ thuộc vào các mô-đun cấp thấp.
Các nguyên tắc này là hướng dẫn, nhưng điều đó không có nghĩa là bạn phải sử dụng chúng một cách nghiêm ngặt mọi lúc.
Từ mô tả của bạn, tôi có thể thấy khó khăn chính của bạn là suy nghĩ OO. Bạn vẫn đang suy nghĩ về cách làm thế nào để thực hiện mọi việc và đây là một suy nghĩ thủ tục . Nhưng trong OOP, điều quan trọng hơn là quyết định người sẽ làm những việc này.
Suy nghĩ về DI, sử dụng ví dụ của bạn, chúng ta hãy xem kịch bản của bạn:
public class AttendanceService {
// other stuff...
public boolean scanEmployeeId() {
// The scanning is made by an barcode reader on employee's name tag
}
}
vấn đề là gì đây?
Trước tiên, mã này vi phạm SRP: Điều gì xảy ra nếu quá trình xác thực thay đổi? Nếu công ty quyết định rằng thẻ tên là không an toàn và cài đặt một hệ thống nhận dạng sinh trắc học? Vâng, ở đây có một lý do để lớp của bạn thay đổi, nhưng lớp này không chỉ làm xác thực, nó còn làm những thứ khác, vì vậy, sẽ có một lý do khác để nó thay đổi. SRP nói rằng các lớp của bạn chỉ nên có MỘT lý do để thay đổi.
Nó cũng vi phạm OCP: Điều gì sẽ xảy ra nếu có phương thức xác thực khác có sẵn và tôi muốn có thể sử dụng như tôi muốn? Tôi không thể. Để thay đổi phương thức xác thực, tôi phải sửa đổi lớp.
Nó vi phạm ISP: Tại sao một đối tượng ServiceAttendance
có một phương pháp để xác thực người lao động nếu nó chỉ cần cung cấp tham gia dịch vụ?
Hãy cải thiện nó một chút:
public class BarCodeAuth {
public boolean authenticate() {
// Authenticates...
}
}
public class AttendanceService {
private BarCodeAuth auth;
public AttendanceClass() {
this.auth = new BarCodeAuth();
}
public void doOperation() {
if(this.auth.authenticate()) {
// do stuff..
}
}
}
Bây giờ đó là một chút tốt hơn. Chúng tôi đã giải quyết được vấn đề với SRP và ISP, nhưng nếu bạn nghĩ tốt hơn, nó vẫn vi phạm OCP và bây giờ vi phạm DIP. Vấn đề là AttendanceService
được kết hợp chặt chẽ với BarCodeAuth
. Tôi vẫn không thể thay đổi phương thức xác thực mà không cần chạm vào AttendanceService
.
Bây giờ chúng ta hãy áp dụng OCP và DIP với nhau:
public interface AuthMethod {
public boolean authenticate();
}
public class BarCodeAuth implements AuthMethod {
public boolean authenticate() {
// Authenticates...
}
}
public class BiometricAuth implements AuthMethod {
public boolean authenticate() {
// Authenticates...
}
}
public class FooBarAuth implements AuthMethod {
public boolean authenticate() {
// Authenticates...
}
}
public class AttendanceClass {
private AuthMethod auth;
public AttendanceClass(AuthMethod auth) {
this.auth = auth;
}
public void doOperation() {
if(this.auth.authenticate()) {
// do stuff..
}
}
}
Bây giờ tôi có thể làm:
new AttendanceClass(new BarCordeAuth());
new AttendanceClass(new BiometricAuth());
Để thay đổi hành vi, tôi không cần phải chạm vào lớp. Nếu một số phương thức xác thực khác xuất hiện, tôi chỉ cần triển khai nó, tôn trọng giao diện và sẵn sàng sử dụng (hãy nhớ OCP?). Điều này là do tôi đang sử dụng DIP trên ServiceAttendance
. Mặc dù nó cần một phương thức xác thực, nó không phải là khả năng của nó để tạo ra một phương thức xác thực. Trong hành động, đối với đối tượng này, nó không quan trọng phương pháp xác thực, nó chỉ cần biết nếu người gọi (người dùng) là hoặc không được phép làm những gì anh ta đang cố gắng làm.
Đây là tất cả về DIP là: các thành phần của bạn phải phụ thuộc vào trừu tượng, không triển khai.
RẮN là từ viết tắt của nhiều nguyên tắc. Bạn phải hiểu chúng trước rồi thử áp dụng chúng khi bạn viết mã. Công thức nấu ăn không thực sự tồn tại, bạn sẽ không nhận được từng bước làm thế nào để làm công cụ hoặc người nào khác sẽ không có nhu cầu cho các nhà phát triển con người. Mỗi ứng dụng và vấn đề đều có những thách thức và bối cảnh độc đáo, những gì làm việc trong một trường hợp có thể không hoạt động trong các trường hợp khác. – MikeSW
Câu hỏi này có vẻ quá rộng để được trả lời hiệu quả. – anotherdave
Hàng loạt các vids tốt trên SOLID có thể được tìm thấy ở đây: [DimeCasts.net] (http://dimecasts.net/Casts/ByTag/SOLID%20Principle) – PositiveGuy