出発点としてPDFの例を取り上げて、これを見てみましょう。
http://en.wikipedia.org/wiki/Single_responsibility_principle
単一責任の原則は、オブジェクトにはただ1つの目的を持たせることを提案しています。これを覚えておいてください。
http://en.wikipedia.org/wiki/Separation_of_concerns
懸念の分離の原則は、クラスに重複する機能があってはならないことを示しています。
これら2つを見ると、理にかなっている場合にのみ、そのクラスがそれを行う責任がある場合にのみ、ロジックがクラスに入るべきであると示唆しています。
さて、あなたのPDFの例では、誰が印刷を担当しているのでしょうか?何が理にかなっていますか?
最初のコードスニペット:
Pdf pdf = new Pdf();
pdf.Print();
これは良くない。PDFドキュメントはそれ自体を印刷しません。それは... ta da!...プリンターによって印刷されます。したがって、2番目のコードスニペットははるかに優れています。
Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);
意味あり。PDFプリンターはPDFドキュメントを印刷します。さらに良いことに、プリンターはPDFプリンターや写真プリンターであってはなりません。それは、送信されたものを最高の能力で印刷できるプリンターでなければなりません。
Pdf pdf = new Pdf();
Printer printer = new Printer();
printer.Print(pdf);
それは簡単です。メソッドを意味のある場所に配置します。明らかに、それは必ずしもそれほど単純ではありません。あなたの国の統計を例にとります:
Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();
あなたの懸念は、統計がn個あるかもしれず、それらがCountryクラスにあるべきではないということです。それは本当です。ただし、モデルがその特定の統計のみを必要とする場合、このモデリングの例は実際には問題ありません。
この場合、国はモデルと手元の要件に固有の独自の統計を計算できるべきであるとかなり論理的に言うことができます。
そしてそこにあるのは、あなたの要件は何ですか?要件は、これらの要件が満たされる世界、コンテキストをモデル化する方法を推進します。
実際に多数/可変の統計情報がある場合、2番目の例はより意味があります。
Country m = new Country("Mexico");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(m);
さらに良いことに、国をパラメーターとする統計と呼ばれる抽象スーパークラスまたはインターフェースを用意します。
interface StatisticsCalculator // or a pure abstract class if doing C++
{
double getStatistics(Country country); // or a pure virtual function if in C++
}
クラスDebtToGDPRatioStatisticsCalculatorはStatisticsCalculatorを実装します....
クラスInfantMortalityStatisticsCalculatorはStatisticsCalculatorを実装します...
などなど。これは、一般化、委任、抽象化につながります。統計収集は、特定の抽象化(統計収集API)を一般化する特定のインスタンスに委任されます。
これがあなたの質問に100%答えるかどうかはわかりません。結局、(EEの人々のように)不可侵の法律に基づいた絶対的なモデルはありません。あなたができることは、それらが理にかなっていることを置くことだけです。そして、それはあなたがする必要がある工学上の決定です。最善の方法は、オブジェクト指向の原則(および一般的な優れたソフトウェアモデリングの原則)に精通することです。