Trả lời muộn nhưng tôi không thể cưỡng lại.
Là hầu hết các lớp vào Y tốt hay chống mẫu?
Trong hầu hết các trường hợp, hầu hết các quy tắc, được áp dụng mà không cần suy nghĩ, hầu hết sẽ sai lầm khủng khiếp (bao gồm cả quy tắc này).
Hãy để tôi kể cho bạn một câu chuyện về sự ra đời của một vật thể giữa sự hỗn loạn của một số quy tắc thủ tục đúng đắn, nhanh chóng và bẩn thỉu đã xảy ra, không phải do thiết kế, mà là tuyệt vọng.
Thực tập sinh của tôi và tôi đang lập trình cặp để nhanh chóng tạo ra một số mã vứt đi để cạo trang web. Chúng tôi hoàn toàn không có lý do để mong đợi mã này sẽ tồn tại lâu, vì vậy chúng tôi chỉ cần đập ra một cái gì đó hoạt động. Chúng tôi lấy toàn bộ trang dưới dạng một chuỗi và cắt ra những thứ chúng tôi cần theo cách dễ vỡ nhất đến mức bạn có thể tưởng tượng. Đừng phán xét. Nó hoạt động.
Bây giờ trong khi làm điều này, tôi đã tạo ra một số phương thức tĩnh để thực hiện việc băm nhỏ. Thực tập sinh của tôi đã tạo ra một lớp DTO rất giống với bạn CatData
.
Khi tôi lần đầu tiên nhìn vào DTO, nó đã làm tôi khó chịu. Những năm thiệt hại mà Java đã gây ra cho bộ não của tôi khiến tôi phải giật mình ở các lĩnh vực công cộng. Nhưng chúng tôi đã làm việc trong C #. C # không cần các getters và setters sớm để bảo vệ quyền của bạn để làm cho dữ liệu không thay đổi hoặc được gói gọn sau đó. Không cần thay đổi giao diện, bạn có thể thêm chúng bất cứ khi nào bạn muốn. Có lẽ chỉ để bạn có thể thiết lập một điểm dừng. Tất cả mà không nói với khách hàng của bạn một điều về nó. Yea C #. Boo Java.
Vì vậy, tôi giữ lưỡi của tôi. Tôi quan sát khi anh ta sử dụng các phương thức tĩnh của tôi để khởi tạo thứ này trước khi sử dụng nó. Chúng tôi có khoảng 14 người trong số họ. Đó là, xấu xí, nhưng chúng tôi không có lý do để quan tâm.
Sau đó, chúng tôi cần nó ở những nơi khác. Chúng tôi thấy mình muốn sao chép và dán mã. 14 dòng khởi tạo đang được ném xung quanh. Nó đã bắt đầu đau đớn. Anh ngập ngừng và hỏi tôi ý kiến.
Tôi miễn cưỡng hỏi, "bạn sẽ xem xét một đối tượng?"
Anh nhìn lại DTO của mình và bối rối bối rối. "Đó là một đối tượng".
"Tôi có nghĩa là một đối tượng thực sự"
"Huh?"
"Hãy để tôi chỉ cho bạn một cái gì đó. Bạn quyết định xem nó có hữu ích không"
Tôi đã chọn một tên mới và nhanh chóng lấy ra một cái gì đó trông giống như thế này:
public class Cat{
CatData(string catPage) {
this.catPage = catPage
}
private readonly string catPage;
public string name() { return chop("name prefix", "name suffix"); }
public string weight() { return chop("weight prefix", "weight suffix"); }
public string image() { return chop("image prefix", "image suffix"); }
private string chop(string prefix, string suffix) {
int start = catPage.indexOf(prefix) + prefix.Length;
int end = catPage.indexOf(suffix);
int length = end - start;
return catPage.Substring(start, length);
}
}
Điều này không làm gì các phương thức tĩnh chưa làm. Nhưng bây giờ tôi đã hút 14 phương thức tĩnh vào một lớp nơi chúng có thể ở một mình với dữ liệu mà chúng làm việc.
Tôi đã không ép buộc thực tập sinh của tôi sử dụng nó. Tôi chỉ cung cấp nó và để anh ta quyết định nếu anh ta muốn gắn bó với các phương thức tĩnh. Tôi về nhà nghĩ rằng anh ta có thể dính vào những gì anh ta đã làm việc. Ngày hôm sau tôi thấy anh ta đang sử dụng nó ở một loạt nơi. Nó tuyên bố phần còn lại của mã vẫn còn xấu xí và mang tính thủ tục, nhưng sự phức tạp này giờ đã bị ẩn khỏi chúng ta đằng sau một đối tượng. Nó đã tốt hơn một chút.
Bây giờ chắc chắn mỗi khi bạn truy cập nó là một công việc hợp lý. Một DTO là một giá trị lưu trữ nhanh đẹp. Tôi lo lắng về điều đó nhưng nhận ra rằng tôi có thể thêm bộ nhớ đệm nếu chúng tôi cần mà không cần chạm vào bất kỳ mã nào đang sử dụng. Vì vậy, tôi sẽ không làm phiền cho đến khi chúng tôi quan tâm.
Tôi có nói bạn nên luôn luôn bám sát các đối tượng OO trên DTO không? Không. DTO tỏa sáng khi bạn cần vượt qua một ranh giới ngăn bạn khỏi các phương pháp di chuyển. DTO có vị trí của họ.
Nhưng các đối tượng OO cũng vậy. Tìm hiểu làm thế nào để sử dụng cả hai công cụ. Tìm hiểu những gì từng chi phí. Tìm hiểu để cho vấn đề, tình hình và thực tập quyết định. Giáo điều không phải là bạn của bạn ở đây.
Vì câu trả lời của tôi đã quá dài một cách nực cười, hãy để tôi không cho bạn hiểu về một số quan niệm sai lầm với việc xem xét mã của bạn.
Ví dụ, một lớp thường có các thành viên và phương thức của lớp, ví dụ:
public class Cat{
private String name;
private int weight;
private Image image;
public void printInfo(){
System.out.println("Name:"+this.name+",weight:"+this.weight);
}
public void draw(){
//some draw code which uses this.image
}
}
Nhà xây dựng của bạn ở đâu? Điều này không cho tôi thấy đủ để biết nó có hữu ích không.
Nhưng sau khi đọc về nguyên tắc trách nhiệm đơn và nguyên tắc đóng mở, tôi thích tách một lớp thành DTO và lớp trình trợ giúp chỉ với các phương thức tĩnh, ví dụ:
public class CatData{
public String name;
public int weight;
public Image image;
}
public class CatMethods{
public static void printInfo(Cat cat){
System.out.println("Name:"+cat.name+",weight:"+cat.weight);
}
public static void draw(Cat cat){
//some draw code which uses cat.image
}
}
Tôi nghĩ rằng nó phù hợp với nguyên tắc trách nhiệm duy nhất bởi vì bây giờ trách nhiệm của CatData là chỉ giữ dữ liệu, không quan tâm đến các phương thức (cũng đối với CatMethods).
Bạn có thể làm nhiều điều ngớ ngẩn nhân danh Nguyên tắc Trách nhiệm duy nhất. Tôi có thể lập luận rằng Cat String và Cat ints nên được tách ra. Các phương thức vẽ và Hình ảnh đó đều phải có lớp riêng. Rằng chương trình đang chạy của bạn là một trách nhiệm duy nhất nên bạn chỉ nên có một lớp. : P
Đối với tôi, cách tốt nhất để tuân theo Nguyên tắc Trách nhiệm duy nhất là tìm ra một sự trừu tượng hóa tốt cho phép bạn đặt sự phức tạp vào một hộp để bạn có thể che giấu nó. Nếu bạn có thể đặt cho nó một cái tên hay khiến mọi người không khỏi ngạc nhiên bởi những gì họ tìm thấy khi họ nhìn vào bên trong thì bạn đã theo dõi nó khá tốt. Mong đợi nó sẽ ra lệnh nhiều quyết định hơn thì đó là yêu cầu rắc rối. Thành thật mà nói, cả hai danh sách mã của bạn đều làm như vậy nên tôi không hiểu tại sao SRP lại quan trọng ở đây.
Và nó cũng phù hợp với nguyên tắc đóng mở vì thêm các phương thức mới không cần thay đổi lớp CatData.
Ồ không. Nguyên tắc đóng mở không phải là về việc thêm các phương thức mới. Đó là về việc có thể thay đổi việc thực hiện các phương thức cũ và không phải chỉnh sửa gì cả. Không có gì sử dụng bạn và không phải phương pháp cũ của bạn. Thay vào đó bạn viết một số mã mới ở một nơi khác. Một số hình thức đa hình sẽ làm điều đó độc đáo. Đừng thấy điều đó ở đây.
Câu hỏi của tôi là, nó là một mô hình tốt hay chống?
Làm thế nào tôi nên biết? Hãy nhìn, làm một trong hai cách có lợi ích và chi phí. Khi bạn tách mã khỏi dữ liệu, bạn có thể thay đổi mà không phải biên dịch lại mã khác. Có lẽ đó là rất quan trọng đối với bạn. Có lẽ nó chỉ làm cho mã của bạn trở nên phức tạp vô nghĩa.
Nếu nó làm cho bạn cảm thấy tốt hơn thì bạn không ở xa thứ mà Martin Fowler gọi là một đối tượng tham số . Bạn không phải chỉ đưa người nguyên thủy vào đối tượng của bạn.
Những gì tôi muốn bạn làm là phát triển ý thức về cách thực hiện sự tách biệt của bạn, hoặc không, theo phong cách mã hóa. Bởi vì tin hay không bạn không bị buộc phải chọn một phong cách. Bạn chỉ cần sống với sự lựa chọn của bạn.