web-dev-qa-db-ja.com

設計:オブジェクトメソッドと、オブジェクトをパラメーターとして使用する別のクラスのメソッドの比較

たとえば、次のようにした方がよいでしょう。

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

または:

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

もう一つの例:

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

または:

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

最後の例で私が懸念しているのは、国について知りたい可能性のある統計が無限にある可能性があることです(ただし、たとえ10と言ってもかまいません)。それらはすべて国オブジェクトに属していますか?

例えば.

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

これらは単純な比率ですが、統計がメソッドを保証するのに十分複雑であると仮定します。

オブジェクト固有の操作と、オブジェクトに対して実行できるがその一部ではない操作の間の境界はどこにありますか?

14
User

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();

これは良くない。 A 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);

さらに良いのは、国をパラメーターとしてとる、Statisticsと呼ばれる抽象スーパークラスまたはインターフェースを用意することです。

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

などなど。これは、一般化、委任、抽象化につながります。統計収集は、特定のインスタンスに委任された特定のに一般化された特定のabstraction(統計収集API)。

これがあなたの質問に100%答えるかどうかはわかりません。結局のところ、(EEの人々のように)不可侵の法則に基づいた確実なモデルはありません。できることは、意味のあるものを置くことだけです。そして、それはあなたがしなければならないエンジニアリングの決定です。最善の方法は、OOの原則(および一般的な優れたソフトウェアモデリングの原則)を実際に理解することです。)

16
luis.espinal

私はどちらも間違いなく他より優れていると思います。 pdf.Print()の使用はより厳密ですが、次の場合にはPdfPrinterクラスを使用する方がよいでしょう。

  • プリンターのインスタンスを管理する必要がある
  • Pdf.Print(...)の複雑さを解消する幅広いオプションとアクションがあります(印刷のキャンセル、追加の書式設定など)。

そうでなければ私はそれに夢中にならないでしょう。

4
Kevin Hsu