Schauen wir uns diese PDF-Beispiele als Ausgangspunkt an.
http://en.wikipedia.org/wiki/Single_responsibility_principle
Das Prinzip der Einzelverantwortung sieht vor, dass ein Objekt nur ein Ziel haben sollte. Behalte dies im Kopf.
http://en.wikipedia.org/wiki/Separation_of_concerns
Das Prinzip der Trennung von Interessen besagt, dass Klassen keine überlappenden Funktionen haben sollten.
Wenn Sie sich diese beiden ansehen, schlagen sie vor, dass Logik nur dann in eine Klasse aufgenommen werden sollte, wenn sie sinnvoll ist, und nur dann, wenn diese Klasse dafür verantwortlich ist.
In Ihrem PDF-Beispiel lautet die Frage: Wer ist für den Druck verantwortlich? Was macht Sinn?
Erstes Code-Snippet:
Pdf pdf = new Pdf();
pdf.Print();
Das ist nicht gut. Ein PDF-Dokument wird nicht gedruckt. Es wird gedruckt von ... ta da! .. einem Drucker. Ihr zweites Code-Snippet ist also viel besser:
Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);
Das macht Sinn. Ein PDF-Drucker druckt ein PDF-Dokument. Besser noch, ein Drucker sollte kein PDF-Drucker oder ein Fotodrucker sein. Es sollte nur ein Drucker sein, der in der Lage ist, die an ihn gesendeten Daten so gut wie möglich zu drucken.
Pdf pdf = new Pdf();
Printer printer = new Printer();
printer.Print(pdf);
So ist das einfach. Setzen Sie Methoden dort ein, wo sie sinnvoll sind. Offensichtlich ist es nicht immer so einfach. Nehmen Sie zum Beispiel Ihre Länderstatistik:
Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();
Ihre Sorge ist , dass es sein könnte n Anzahl von Statistiken, und dass sie nicht in einem Land Klasse sein. Das ist wahr. Wenn Ihr Modell jedoch nur diese bestimmte Statistik benötigt, ist dieses Modellierungsbeispiel möglicherweise in Ordnung.
In diesem Fall können Sie logischerweise sagen, dass ein Land in der Lage sein sollte, seine eigenen Statistiken zu erstellen, die für Ihr Modell und die vorliegenden Anforderungen spezifisch sind.
Und darin liegt die Sache: Was sind Ihre Anforderungen? Ihre Anforderungen bestimmen die Art und Weise, wie Sie die Welt modellieren, den Kontext, in dem diese Anforderungen erfüllt werden sollen.
Wenn Sie tatsächlich eine Vielzahl / variable Anzahl von Statistiken haben, ist Ihr zweites Beispiel sinnvoller:
Country m = new Country("Mexico");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(m);
Besser noch, haben Sie eine abstrakte Superklasse oder Schnittstelle namens Statistik, die ein Land als Parameter verwendet:
interface StatisticsCalculator // or a pure abstract class if doing C++
{
double getStatistics(Country country); // or a pure virtual function if in C++
}
Klasse DebtToGDPRatioStatisticsCalculator implementiert StatisticsCalculator ....
Klasse InfantMortalityStatisticsCalculator implementiert StatisticsCalculator ...
Und so weiter und so fort. Was zu Folgendem führt: Verallgemeinerung, Delegation, Abstraktion. Die statistische Erfassung wird an bestimmte Instanzen delegiert , die eine bestimmte Abstraktion verallgemeinern (eine Statistiksammlungs-API).
Ich weiß nicht, ob dies Ihre Frage zu 100% beantwortet. Schließlich haben wir keine unfehlbaren Modelle, die auf unantastbaren Gesetzen beruhen (wie es die EE-Leute tun). Alles, was Sie tun können, ist Dinge zu formulieren, wenn sie sinnvoll sind. Und das ist eine technische Entscheidung, die Sie treffen müssen. Das Beste, was Sie tun können, ist, sich mit den OO-Prinzipien (und den Prinzipien der guten Softwaremodellierung im Allgemeinen) wirklich vertraut zu machen.