web-dev-qa-db-ja.com

どちらが良いですか:一連のゲッターまたは選択文字列パラメーターを持つ1つのメソッド?

私たちの知識領域には、圧力記録プレートの上を素足で歩く人々が含まれます。センサーデータで人間の足が認識された場合、「Foot」クラスのオブジェクトを生成する画像認識を行います。

足のデータに対して実行する必要があるいくつかの計算があります。

さて、どちらのAPIがより良いでしょう:

class Foot : public RecognizedObject  { 
  MaxPressureFrame getMaxPressureFrame();
  FootAxis getFootAxis();
  AnatomicalZones getAnatomicalZones();

  // + similar getters for other calculations

  // ...
}

または:

class Foot : public RecognizedObject {
  virtual CalculationBase getCalculation(QString aName);

  // ...
}

さて、思いつくことのできるプロとコンはたくさんありますが、どれが最も重要であるか本当に決めることはできません。これはエンドユーザーアプリケーションであり、販売しているソフトウェアライブラリではありません。

何かアドバイス?

最初のアプローチのいくつかのプロは次のようになります:

  • KISS-すべてが非常に具体的です。 API、しかし実装も。
  • 強く型付けされた戻り値。
  • このクラスから継承するのは簡単です。上書きできるものはなく、追加されるだけです。
  • APIは非常に閉じているため、何も実行されず、何もオーバーライドされないため、失敗する可能性は少なくなります。

いくつかの短所:

  • 私たちが考案した新しい計算がすべてリストに追加されると、ゲッターの数は増加します
  • APIは変更される可能性が高く、重大な変更が導入された場合、新しいAPIバージョンであるFoot2が必要です。
  • 他のプロジェクトでクラスを再利用する場合、すべての計算が必要になるとは限りません

2番目のアプローチのいくつかのプロ:

  • より柔軟
  • aPIが変更される可能性は低くなります(抽象化が正しいと仮定すると、そうでない場合、変更するとコストが高くなります)

いくつかの短所:

  • ゆるいタイプ。すべての呼び出しでキャストが必要です。
  • 文字列パラメータ-私はそれについて悪い感情を抱いています(文字列値の分岐...)
  • 現在、追加の柔軟性を要求するユースケース/要件はありませんが、将来的には適用される可能性があります。
  • aPIは制限を課します。すべての計算は基本クラスから派生する必要があります。計算を取得することはこの1つの方法を介して強制され、追加のパラメーターを渡すことは不可能です。ただし、複雑さをさらに増すパラメーターを渡す、より動的で非常に柔軟な方法を考案しない限りです。
15
Bgie

最初のアプローチで成果が上がると思います。マジックストリングは次の問題を引き起こす可能性があります:入力ミス、誤用、重要な戻り値の型安全性、コード補完の欠如、コードの不明確(このバージョンにその機能はありましたか?実行時に確認します)。列挙型を使用すると、これらの問題のいくつかが解決されますが、発生した短所を見てみましょう。

  • 私たちが考案した新しい計算がすべてリストに追加されると、ゲッターの数は増加します

確かに、これは煩わしいかもしれませんが、物事を適切かつ厳密に保ち、列挙型よりもはるかに有用な優れた見出しコメントを付けて、プロジェクトのどこでも最新のIDEでコードを補完できます。

  • APIは変更される可能性が高く、重大な変更が導入された場合、新しいAPIバージョンであるFoot2が必要です。

確かに、しかしそれは実際には巨大なプロです;)あなたは部分的なAPIのためのインターフェースを定義することができ、それからあなたは新しいAPIの影響を受けない依存クラスを再コンパイルする必要はありません(従ってFoot2の必要はありません)。これにより、より良い分離が可能になり、依存関係は実装ではなくインターフェースになりました。さらに、既存のインターフェイスが変更されると、依存クラスでコンパイルエラーが発生し、古くなったコードを防ぐのに役立ちます。

  • 他のプロジェクトでクラスを再利用する場合、すべての計算が必要になるとは限りません

マジックストリングまたは列挙型の使用がそれでどのように役立つかわかりません...正しく理解できれば、コードをFootクラスに含めるか、それをいくつかの小さなクラスに分割して、両方のオプションに当てはまります。

6
user116462

オプション3をお勧めします。計算はFootの抽象化の本質的な部分ではなく、それを操作することを明確にします。次に、Footと計算を次のように別々のクラスに分割できます。

class Foot : public RecognizedObject {
public:
    // Rather low-level API to access all characteristics that might be needed by a calculation
};

class MaxPressureFrame {
public:
    MaxPressureFrame(const Foot& aFoot); // Performs the calculation based on the information in aFoot
    //API for accessing the results of the calculation
};

// Similar classes for other calculations

このようにして、計算のタイピングは強力であり、既存のコードに影響を与えずに新しい計算を追加できます(Footによって公開された情報量に重大なエラーがない限り)。