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.)