Thật khó để thiết lập các thực tiễn tốt nhất cho một cái gì đó "linh hoạt" hoặc trừu tượng như một DTO. Về cơ bản, DTO chỉ là đối tượng để truyền dữ liệu nhưng tùy thuộc vào điểm đến hoặc lý do chuyển, bạn có thể muốn áp dụng các "thực tiễn tốt nhất" khác nhau.
Tôi khuyên bạn nên đọc Mô hình kiến trúc ứng dụng doanh nghiệp của Martin Fowler . Có cả một chương dành riêng cho các mẫu, trong đó các DTO có được một phần thực sự chi tiết.
Ban đầu, chúng được "thiết kế" để sử dụng trong các cuộc gọi từ xa đắt tiền, nơi bạn có thể sẽ cần rất nhiều dữ liệu từ các phần khác nhau trong logic của bạn; DTO sẽ thực hiện chuyển dữ liệu trong một cuộc gọi.
Theo tác giả, DTOs không có ý định sử dụng trong môi trường địa phương, nhưng một số người đã tìm thấy cách sử dụng chúng. Thông thường chúng được sử dụng để thu thập thông tin từ các POCO khác nhau thành một thực thể duy nhất cho GUI, API hoặc các lớp khác nhau.
Bây giờ, với tính kế thừa, việc sử dụng lại mã giống như một tác dụng phụ của kế thừa hơn là mục tiêu chính của nó; thành phần, mặt khác, được thực hiện với việc sử dụng lại mã làm mục tiêu chính.
Một số người khuyên nên sử dụng thành phần và kế thừa cùng nhau, sử dụng điểm mạnh của cả hai và cố gắng giảm thiểu điểm yếu của họ. Sau đây là một phần của quy trình tinh thần của tôi khi chọn hoặc tạo DTO mới hoặc bất kỳ lớp / đối tượng mới nào cho vấn đề đó:
- Tôi sử dụng sự kế thừa với các DTO bên trong cùng một lớp hoặc cùng một bối cảnh. Một DTO sẽ không bao giờ thừa kế từ POCO, BLL DTO sẽ không bao giờ thừa kế từ DAL DTO, v.v.
- Nếu tôi thấy mình đang cố gắng giấu một trường khỏi DTO, tôi sẽ cấu trúc lại và có thể sử dụng bố cục thay thế.
- Nếu rất ít trường khác nhau từ một DTO cơ sở là tất cả những gì tôi cần, tôi sẽ đặt chúng vào một DTO phổ quát. DTO phổ quát chỉ được sử dụng trong nội bộ.
- Một POCO / DTO cơ sở gần như sẽ không bao giờ được sử dụng cho bất kỳ logic nào, theo cách đó, cơ sở chỉ trả lời cho các nhu cầu của con cái nó. Nếu tôi cần sử dụng cơ sở, tôi sẽ tránh thêm bất kỳ lĩnh vực mới nào mà con của nó sẽ không bao giờ sử dụng.
Một số trong số chúng có thể không phải là thực tiễn "tốt nhất", chúng hoạt động khá tốt cho các dự án tôi đang thực hiện nhưng bạn cần nhớ rằng không có kích thước nào phù hợp với tất cả. Trong trường hợp DTO phổ quát, bạn nên cẩn thận, chữ ký phương thức của tôi trông như thế này:
public void DoSomething(BaseDTO base) {
//Some code
}
Nếu bất kỳ phương thức nào cần DTO riêng, tôi sẽ thực hiện kế thừa và thường thì thay đổi duy nhất tôi cần thực hiện là tham số, mặc dù đôi khi tôi cần đào sâu hơn cho các trường hợp cụ thể.
Từ ý kiến của bạn tôi nhận thấy rằng bạn đang sử dụng các DTO lồng nhau. Nếu các DTO lồng nhau của bạn chỉ bao gồm một danh sách các DTO khác, tôi nghĩ điều tốt nhất để làm là mở danh sách.
Tùy thuộc vào lượng dữ liệu bạn cần hiển thị hoặc để làm việc, có thể là một ý tưởng tốt để tạo các DTO mới giới hạn dữ liệu; ví dụ: nếu UserDTO của bạn có nhiều trường và bạn chỉ cần 1 hoặc 2, thì tốt hơn là có DTO chỉ với các trường đó. Xác định lớp, bối cảnh, cách sử dụng và tiện ích của DTO sẽ giúp ích rất nhiều khi thiết kế nó.