2010-09-10 36 views
9

Bạn vẽ đường kẻ ở đâu khi di chuyển các hàm hoạt động trên dữ liệu vào lớp chứa dữ liệu đó? Ví dụ, hãy tưởng tượng bạn có một lớp đơn giản lưu trữ một mô tả về thời tiết, với các biến cho nhiệt độ, độ ẩm, tốc độ và hướng gió, và thời gian đo được thực hiện. Bây giờ hãy tưởng tượng bạn có một đối tượng của lớp này và bạn muốn truyền nó cho người khác - một quá trình khác, một máy khác, bất cứ điều gì. Bạn có đặt mã để truyền đối tượng vào chính đối tượng đó không - ví dụ, bằng cách thêm phương thức Send (destination-type) vào lớp dữ liệu đơn giản? Hay bạn giữ loại tính năng này trong các lớp riêng biệt có thể gửi và nhận bất kỳ thứ gì qua phương tiện - cho dù đó là kết nối mạng, tệp i/o, comms liên kết hoặc bất kỳ điều gì tương tự?Đối tượng tự gửi - ý tưởng hay?

Bản năng đường ruột của tôi là giữ cho các lớp dữ liệu của tôi đơn giản và quấn chúng lại khi tôi muốn truyền chúng - trong các lớp nối tiếp và trình bày lớp người gửi và người nhận bằng giao diện đơn giản mà họ hiểu. Cách thay thế có vẻ là đặt tất cả mọi thứ bao gồm bồn rửa nhà bếp vào các lớp dữ liệu đơn giản - mọi chức năng có thể hoạt động trên dữ liệu đó, tuy nhiên gián tiếp. Tóm lại, mã xử lý lỗi mạng dường như không thuộc về tôi trong một lớp dữ liệu đơn giản.

Điều này có vẻ hiển nhiên đối với tôi, nhưng tôi tiếp tục thấy các nhà phát triển đặt phương thức Send() lên lớp học của họ. Họ thậm chí còn tự mình nói với các lớp thông báo về Send(), điều này có vẻ phản đối rất cao đối với tôi; nếu tôi viết một bức thư trên một tờ giấy, tôi không nói cho tờ giấy tự gửi đi. Tôi quấn lá thư trong một phong bì và đưa nó cho người đưa thư, bởi vì anh ta có một chiếc xe tải và một tấm bản đồ. Mọi người nghĩ sao?

+0

Bạn có thể quan tâm đến một câu hỏi liên quan: [Có phải là quy ước tốt cho một lớp để tự thực hiện các chức năng không?] (Http://stackoverflow.com/q/3105692/240733) – stakx

+0

Nhờ tất cả những người đã trả lời - điều này là câu hỏi đầu tiên của tôi về SO, và đó là một trải nghiệm rất tích cực. – bythescruff

Trả lời

8

Có logic để thực hiện với chính mục tải trọng: tốc độ gió hiện là gì?

Có logic để giải thích dữ liệu đó: chúng tôi có thể gắn tàu này ngay bây giờ không?

Có logic để làm với quyết định gửi tải trọng ở đâu đó: oh đây là giá trị thời tiết mới, một số nội dung trên đó quan tâm.

Sau đó, nội dung mạng thực tế.

Tải trọng có thể cần phải có khả năng tuần tự hóa và tự giải phóng chính nó. Tôi không thấy rằng bất kỳ phần còn lại nào là mối quan tâm của trọng tải. Phải có một vị trí tốt hơn cho Send(). Không ít nhất là vì bạn có thể chọn gửi một số đối tượng tải trọng cùng một lúc và không thể gửi tất cả chúng cho nhau.

5

Tôi đã đi qua lại về loại câu hỏi thiết kế này nhiều lần trong sự nghiệp của mình. Ngay bây giờ, tôi là nơi bạn dường như, chủ yếu là bởi vì tôi làm rất nhiều SOA trong cuộc sống hiện tại của tôi, và cuối cùng tôi đã viết rất nhiều các clases tồn tại chỉ để được tuần tự hóa vào và ra khỏi nhiều các định dạng dây, chủ yếu liên quan đến XML và JSON.

Khi bạn chuyển sang thế giới "dịch vụ", các lớp thường chỉ là biểu diễn dữ liệu được gửi qua lại. Do đó, tôi phân chia các lớp của tôi thành hai nhóm logic, "các lớp chứa dữ liệu" và "các lớp học làm công cụ". Tôi không biết nếu tôi là người duy nhất làm điều này, nhưng đó là nơi tôi đang ở.

6

Đó không phải là một câu hỏi đơn giản. Tôi đã thực hiện các dự án sử dụng cả hai phương pháp tiếp cận và tổng thể tôi đã hạnh phúc hơn khi làm việc với phương pháp "mô hình thông minh", nơi mô hình biết rất nhiều về cách làm việc với dữ liệu riêng của nó.

Một trong những nguyên tắc dẫn đến đóng gói tốt là "nói, đừng hỏi" - nếu bạn đang yêu cầu lớp làm điều gì đó cho chính nó, thì không ai ngoại trừ chính lớp đó cần biết chi tiết biểu diễn nội bộ của lớp. Đó chắc chắn là một điều tốt.Ngoài ra, tôi thấy rằng việc đưa logic vào chính lớp thường dẫn đến việc sử dụng lại mã dễ dàng hơn - khi người khác sử dụng lớp đó, họ sẽ nhanh chóng phát hiện ra rằng nó đã biết cách thực hiện một hoạt động cụ thể.

Tuy nhiên, tôi không muốn điều đó dẫn đến phá vỡ ranh giới giữa các lớp ứng dụng của tôi. Tôi không muốn một đối tượng kinh doanh biết làm thế nào để đại diện cho chính nó như HTML - đó là một mối quan tâm trình bày. Vì vậy, trong trường hợp này, tôi sẽ nói rằng các lớp nên biết làm thế nào để đại diện cho chính nó trong một số cách kinh điển, nhưng nó không nên biết về công cụ mạng. Chức năng gửi thực tế phải thuộc về một dịch vụ.

+0

bài đăng tuyệt vời! +1. – Armstrongest

+0

Khi bạn nói, "các lớp nên biết làm thế nào để đại diện cho chính nó trong một số cách kinh điển", bạn có nghĩa là một số cách kinh điển KHÁC rằng đó là tài sản? – Mark

+0

@Mark - Tôi không chắc chắn. Nó có thể có ý nghĩa đối với một lớp để biết làm thế nào để tuần tự hóa nó thành XML, ví dụ, nhưng trong thế giới thực, tôi thường thấy rằng tôi cần các biểu diễn XML hơi khác nhau cho các tình huống khác nhau, và điều đó có vẻ giống như một vấn đề trình bày. –

2

Câu trả lời ngắn gọn là phụ thuộc vào những tác động hạ lưu mà bạn muốn giải quyết.

Nói chung khi có hai cách để làm điều gì đó thường có nghĩa là cả hai cách đều có giá trị của chúng. Một số ví dụ mùa xuân đến tâm trí (SQL vs NoSQL, tự động vs truyền dẫn sử dụng, thay thế vs trực tiếp hiện tại, phía khách hàng vs phía máy chủ, vv). Kết quả của việc này là ràng buộc của bạn để có được rất nhiều người ở cả hai bên với ý kiến ​​có công đức.

Vì vậy, câu hỏi bạn đặt ra là khi một đối tượng có thể thao tác dữ liệu của riêng mình và khi nào tôi cần tách nó ra.

Cá nhân tôi muốn giữ cho các cấu trúc dữ liệu có thể đơn giản có trách nhiệm chính là giữ cho dữ liệu nhất quán. Trách nhiệm thao tác hoặc sử dụng dữ liệu này sẽ là trách nhiệm của các lớp khác. Điều này có xu hướng giúp tôi tách biệt chính sách và triển khai. Ví dụ: nếu tôi muốn triển khai chính sách lưu vào bộ nhớ cache, tôi chỉ phải truy cập vào lớp nhận dữ liệu chứ không phải đối tượng lưu trữ hoặc thao tác dữ liệu.

Mặt khác, điều này làm cho API trở nên khó sử dụng hơn vì nó không phải lúc nào cũng rõ ràng ở đâu. Điều này cũng tạo ra khả năng chính sách tương tự được tạo ở nhiều vị trí (và mỗi lớp kết thúc bằng cách thực hiện một số bộ đệm)

Ví dụ: nếu các phương thức String như Split và Join và Substring không dễ tìm thấy trong lớp String và thay vào đó một nơi nào đó giống như một lớp Parse giả thuyết có khả năng là trước khi tôi tìm thấy lớp Parse giả thuyết này, tôi đã viết nhiều phiên bản crappy của những phương pháp đó. Một ví dụ thực tế về điều này là khi mọi người viết các phương pháp giống hệt với các phương thức trong lớp Toán vì họ không biết về nó.

Cuối cùng, nếu bạn không muốn đối phó với tác động hạ lưu thay đổi cách thức, phương thức Gửi có thể yêu cầu truy cập nhiều lớp, sau đó di chuyển nó bên ngoài của các lớp.

Nếu bạn không muốn đối phó với những người vô tình triển khai phương thức Gửi của riêng họ và bạn không muốn củng cố nó mọi lúc thì tốt hơn là đặt bên trong lớp học.

Các vấn đề liên quan