Thiết kế: Phương thức đối tượng và phương thức của lớp riêng biệt lấy đối tượng làm tham số?


14

Ví dụ, tốt hơn là làm:

Pdf pdf = new Pdf();
pdf.Print();

hoặc là:

Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);

Một vi dụ khac:

Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();

hoặc là:

Country m = new Country("Mexico");
Country us = new Country("US");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(us);
double mRatio = ds.GetDebtToGDPRatio(m);    

Mối quan tâm của tôi trong ví dụ trước là có những số liệu thống kê vô tận (nhưng giả sử chỉ 10) bạn có thể muốn biết về một quốc gia; tất cả họ thuộc về đối tượng đất nước?

ví dụ

Country m = new Country("Mexico");
double ratio = m.GetGDPToMedianIncomeRatio();

Đây là các tỷ lệ đơn giản nhưng cho phép các số liệu thống kê đủ phức tạp để đảm bảo một phương pháp.

Đâu là ranh giới giữa các hoạt động nội tại với một đối tượng so với các hoạt động có thể được thực hiện trên một đối tượng nhưng không phải là một phần của nó?

Câu trả lời:


16

Lấy ví dụ PDF của bạn làm điểm bắt đầu, hãy xem xét điều này.

http://en.wikipedia.org/wiki/Single_responsibility_principl

Nguyên tắc trách nhiệm duy nhất cho thấy rằng một đối tượng nên có một và chỉ một mục tiêu. Giữ nó trong tâm trí.

http://en.wikipedia.org/wiki/Separation_of_concerns

Nguyên tắc phân tách mối quan tâm cho chúng ta biết rằng các lớp không nên có chức năng chồng chéo.

Khi bạn nhìn vào hai cái này, chúng gợi ý rằng logic chỉ nên đi trong một lớp nếu nó có ý nghĩa, chỉ khi lớp đó chịu trách nhiệm thực hiện điều đó.

Bây giờ, trong ví dụ PDF của bạn, câu hỏi là, ai chịu trách nhiệm in? Điều gì có ý nghĩa?

Đoạn mã đầu tiên:

Pdf pdf = new Pdf();
pdf.Print();

Điều này không tốt. Một tài liệu PDF không tự in. Nó được in bởi ... ta da! .. một máy in. Vì vậy, đoạn mã thứ hai của bạn tốt hơn nhiều:

Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);

Điều này thật ý nghĩa. Máy in Pdf in tài liệu pdf. Tốt hơn hết, máy in không nên là máy in PDF hoặc máy in ảnh. Nó chỉ nên là một máy in có khả năng in những thứ được gửi đến nó với khả năng tốt nhất của nó.

Pdf pdf = new Pdf();
Printer printer = new Printer();
printer.Print(pdf);

Thật đơn giản. Đặt phương pháp nơi chúng có ý nghĩa. Rõ ràng, nó không phải lúc nào cũng đơn giản. Lấy số liệu thống kê quốc gia của bạn làm ví dụ:

Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();

Mối quan tâm của bạn là có thể có n số thống kê và chúng không nên thuộc lớp Quốc gia. Điều đó đúng. Tuy nhiên, nếu mô hình của bạn chỉ gọi cho thống kê cụ thể đó, ví dụ mô hình này có thể thực sự ổn.

Trong trường hợp này, bạn có thể nói khá logic rằng một quốc gia sẽ có thể tính toán số liệu thống kê của riêng mình, cụ thể cho mô hình của bạn và các yêu cầu trong tay.

Và điều đó nằm ở chỗ: yêu cầu của bạn là gì? Yêu cầu của bạn sẽ thúc đẩy cách bạn mô hình hóa thế giới, bối cảnh, trong đó những yêu cầu này được thỏa mãn.

Nếu bạn thực sự có số liệu thống kê vô số / biến, thì ví dụ thứ hai của bạn có ý nghĩa hơn:

Country m = new Country("Mexico");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(m);

Tốt hơn nữa, có một siêu lớp trừu tượng hoặc giao diện được gọi là Thống kê lấy một quốc gia làm tham số:

interface StatisticsCalculator // or a pure abstract class if doing C++
{
   double getStatistics(Country country); // or a pure virtual function if in C++
}

lớp DebtToGDPRatioStatisticCalculator thực hiện StatisticsCalculator ....

class InfantMortalityStatisticCalculator thực hiện StatisticsCalculator ...

Và vân vân. Điều này dẫn đến những điều sau đây: khái quát hóa, ủy thác, trừu tượng. Thu thập thống kê được ủy quyền cho các trường hợp cụ thể khái quát một sự trừu tượng hóa cụ thể (API thu thập số liệu thống kê).

Tôi không biết nếu điều này trả lời câu hỏi của bạn 100%. Rốt cuộc, chúng ta không có những mô hình không thể sai lầm dựa trên luật bất khả xâm phạm (như những người EE làm.) Tất cả những gì bạn có thể làm là đặt mọi thứ theo ý nghĩa của chúng. Và đó là một quyết định kỹ thuật bạn cần phải đưa ra. Điều tốt nhất để làm là thực sự làm quen với các nguyên tắc OO (và các nguyên tắc mô hình hóa phần mềm tốt nói chung.)


1
+1 cho Giao diện StatisticsCalculator (và sử dụng Mẫu chiến lược tiếp theo). Và câu trả lời cũng được suy nghĩ thấu đáo
edwardsmatt

3
không đủ thời gian để giải mã triệt để điều này vào lúc này, nhưng phải chỉ ra rằng lớp Máy in sẽ trở thành lớp Thần theo thời gian, kết hợp chặt chẽ với tất cả các loại lớp tài liệu. Pdf.Print sẽ thích hợp hơn - nhưng tất cả phụ thuộc vào cách bạn xác định 'trách nhiệm duy nhất' ;-)
Steven A. Lowe

@Steve - những gì bạn đang đề xuất là một ý tưởng khủng khiếp (có Pdf triển khai print ()). Nó không phản ánh cách in được thực hiện trong cuộc sống thực. Mọi hệ điều hành và API in mà tôi biết đều cung cấp một bản tóm tắt cho Printer. Nhìn vào danh sách máy in trong máy XP / Vista của bạn (hoặc dưới / var / spool hoặc tương đương trong * nix.) Mỗi ​​ứng dụng tuần tự hóa một đối tượng tài liệu cho một trong các máy in của nó. Không có máy in Word, hoặc Máy in văn bản hoặc máy in PDF. Chỉ có máy in dành riêng cho thiết bị in và không dành riêng cho loại tài liệu.
luis.espinal

2
+1 Tôi thích nó Tôi đang suy nghĩ về những gì bạn đã nói .. @Steve và luis: Tôi nghĩ phần còn thiếu của cuộc tranh luận về các đối tượng của Chúa là một đối tượng Máy in chung nên chấp nhận một vài định dạng chuẩn như ASCII hoặc bitmap (mặc dù pdf có lẽ cũng hợp lý) và trách nhiệm của một số lớp 3 là chuyển đổi một loại tài liệu cụ thể (giả sử tài liệu từ ms) sang một trong các định dạng chuẩn này.
Người dùng

2
Dường như với tôi, có lẽ PDF có thể tự hiển thị trên giao diện Canvas hoặc thành đối tượng Hình ảnh có thể được xử lý bởi đối tượng Máy in.
Winston Ewert

4

Tôi nghĩ không chắc chắn là tốt hơn so với người khác. Sử dụng pdf.Print () chặt chẽ hơn, nhưng có lớp PdfPrinter có thể tốt hơn nếu:

  • Bạn cần quản lý phiên bản của máy in
  • Có một loạt các tùy chọn và hành động sẽ làm giảm độ phức tạp của pdf.Print (...) (ví dụ như hủy in, định dạng bổ sung, v.v.)

Tôi sẽ không bị treo lên nó nếu không.


một câu trả lời hay, thiết thực; thời gian sẽ cho biết điều này cần phát triển như thế nào
Steven A. Lowe

1
Gợi ý ngắn gọn là xem xét cả logic và dữ liệu khi áp dụng SRP, để quyết định xem chúng tôi có hối tiếc không khi tách chúng ra sớm hơn. Vấn đề với việc lưu trữ cài đặt trên mỗi máy in trong Pdflớp là chúng không được lưu trữ cùng nhau - Pdfđược lưu trữ trong một tệp nhưng cài đặt trên mỗi máy in nên được lưu trữ với hồ sơ người dùng / máy.
rwong
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.