私が書くすべてのクラスはインターフェースに準拠すべきですか?


10

私はTypescriptでゲームを作成しており、オブジェクトの実装ではなく、インターフェイスに基づいてコードを作成する「インターフェイスベースのプログラミング」のアイデアに固執しようと決心しました。

私は十分な数のインターフェースとそれらを実装するクラスを作成し、一歩下がって、クラスが単純であることを認識しました。実装を変更する必要はおそらくないでしょう。クラスは(Phaser.Spriteタンクのように動作するように制限された方法でを移動します)。

次に、YAGNIのアイデアについて数年前に読んだことを覚えています。これは基本的に、コードを過度に設計して、決して使用しない可能性があるものを含めるべきではないということです。

ベストプラクティスに従って、すべてのクラスがインターフェイスを実装する必要がありますか、それとも将来的にスワップアウトされる可能性があると予想されるクラスに限定する必要がありますか?


実際のクラスをパラメーターとして使用する場合、インターフェイス、このクラスのインターフェイスにコーディングすることも覚えておいてください。特定のクラスの使用を強制する人は誰もいません。それを継承して完全に新しい機能を提供することもできますが、それは正しくないようです。人々がアイデアに頭を抱えやすくするためのインターフェースが存在します。悲しいことに、いや、本当にすべてのためのインターフェースは必要ありません。
アンディ

回答:


6

インターフェイスを持つ理由は、それが多態性を単純化するためです。つまり、実際の実装を知るのではなく、コントラクトでインスタンスを送信できます。たとえば、 "Reader"をメソッドに送信して、呼び出されたメソッドがその "read()"メソッドを使用できるようにすることができます。インターフェイス "Reader"を宣言することにより、指定したメソッドを実装することにより、任意のオブジェクトをこのコントラクトに準拠させることができます。この方法では、コントラクトの基礎となるオブジェクトが完全に異なる場合でも、呼び出し元は特定のメソッドが存在すると想定できます。

これにより、基本クラスからポリモーフィズムが分離され、コントラクトを暗黙指定することにより、クラスチェーンの境界間でも可能になります。

今...これは、複数の継承チェーンが同じように動作する必要がある場合、または他のユーザーに渡したい共通の動作を持つ多くの基本クラスがある場合にのみ役立ちます。

継承チェーンが1つ(ベースクラス->サブクラス)またはベースしかない場合、または実際に関連オブジェクトを他のユーザーに渡したり、一般的に使用したりする必要がない場合は、インターフェイスの実装を追加しないでください。役に立たない。


また、インターフェイスは抽象化をモデル化する必要があることも追加します。したがって、クラスのすべてのパブリックメンバーをホイストするだけでそれらを作成しないでください。そのクラスが何を表しているのかを考えて、そのタイプのオブジェクトが持つべきインターフェイスにそれらのものだけを入れてください。また、単一のクラスに複数のインターフェース(たとえばMoves、およびShootsタンクの例)を作成することもできます。
TMN 2016年

7

実際にインターフェースが必要かどうかわからない場合は、おそらく必要ありません。これはYAGNI原則の中核です。ときあなたは、実装を交換できるようにする必要があり、あなたはインターフェイスを紹介します。


6

すべてのクラスのインターフェースを作成するのは少々やり過ぎです。純粋にオブジェクト指向の観点から見ると、すべてのクラスにはすでにインターフェースがあります。インターフェイスは、クラスのパブリックメソッドとデータメンバーにすぎません。

通常、「インターフェース」は「interfaceキーワードを使用して定義されたJavaクラス」または「パブリックで純粋な仮想関数のみを含むC ++クラス」を意味します。これらは、クラスのインターフェースをその実装から切り離すため、有用な抽象化です。

それを念頭に置いて、適切な場合はインターフェースを使用してください。

  • インターフェイスには複数の実装がありますか?その場合、この状況、一般に公開されているメソッドをインターフェースに抽出する候補になる可能性があります。

  • 私のモジュールの内部動作を知らないはずのその他のモジュールに、潜在的なインターフェースの実装を引き渡すのでしょうか?モジュール間のタッチポイントのサイズが小さくなるため、ここではインターフェースが役立ちます。

上記のイタチの単語に注意してください。「可能性がある」は候補であり、「可能性がある」は有用です。特定の状況で「はい」または「いいえ」と言う厳格な規則はありません。

そうは言っても、すべてにインターフェースを用意することはおそらくやり過ぎです。このパターンが見られる場合は、次のようになります。

interface I {
  int getA()
  int getB()
  ...
  int getY()
  int getZ()
}

class C : I {
  int getA() { ... }
  int getB() { ... }
  ...
  int getY() { ... }
  int getZ() { ... }
}

インターフェイスのもう1つの理由は、テストシステムが必要とするかどうかです。これは、言語とテストフレームワークに依存する場合があります。うまくいけば、あなたはありません、もちろん、これを実行する必要があります。
ダリエン、2016年

@Darien:テストシステムがインターフェースを必要とする理由は、テストが実際には異なる(模擬)実装を使用しており、インターフェースが適切な場合の最初の箇条書きに戻るためです。
Bart van Ingen Schenau 2016年

ここにいくつかの素晴らしいものがあります。ただ考えてみてください。インターフェイスは、公開されているメソッドとクラスのデータメンバーにすぎません。これはインターフェースの実装については当てはまりますが、許可されていても、決して実装されないインターフェースについては当てはまりません。これはコードの匂いのようなものです。
ロビーディー

@RobbieDeeそれは例えばJavaに当てはまります。interfaceたまたま、Javaのすべてがinterfaceそのパブリックインターフェース(OOコンセプト)でもあるということです。

全員!回答の2番目と3番目の文を書き留めます。それをラミネートします。財布に入れてください。頻繁に参照。
radarbob

5

新しい開発者にとって、「ベストプラクティス」であると言われたからといって、インターフェイスを単に追加する不便さであると考えるのは非常に魅力的です。あなた盲目的にこれをしているなら、それはカーゴカルトプログラミングのスマックです。

一連のクラスをまとめて投げるのではなく、大規模な開発用のインターフェースを検討する必要がある非常に良い理由がいくつかあります。

フレームワークのモック

さまざまなレイヤーのオブジェクトを作成せずにマルチレイヤーアプリケーションをテストする場合は、疑いなくモックフレームワークを使用してレイヤーをモックアウトする必要があります。ここではインターフェースが広く使用されています。

依存性注入

追加した膨らみのために彼らはやや支持を失いましたが、アイデアは健全です-インターフェースに基づいてコンクリートを単純に交換する機能。この原則は、ファクトリーパターンなどの多くのデザインパターンにも見られます。


これらのアプローチは、SOLID原則Dに要約されています。これの摩擦は、具体化ではなく抽象化を使用することです。

デザインパターン自体と同様に、いつ使用するかは判断の呼びかけです。要点は、インターフェイスをクラスに貼り付けるだけでなく、インターフェイスの有用性を理解することです。ここでは、DIPとYAGNIのさまざまなメリットについての良い議論があります


依存性注入とIoCコンテナーは2つのまったく異なるものであることに注意してください(1つは設計原則であり、もう1つはさまざまなフレームワークを使用してその原則を具体的に実践する1つの方法です)。IoCコンテナーを使用せずにDIを使用できます。
サラ

@kai 「あなたはIoCコンテナを使用せずにDIを使用することができます」。もっと成熟した開発ショップができると思います。一見単純な概念であるコードを汚染する必要はまったくありません。ジョエルも同じような見方をしています。
ロビーディー

YAGNIは非常にトリッキーです。哲学が何であれ、ほとんどの場合、実際には、YAGNIは手抜きの言い訳として使用されます。結合を避けることは、より真剣に受け止められるべきです。多くのスクラムミーティングで見るとイライラします。他の誰かが仕事を終えなかったために、開発者は自分をブロックされたと呼びます。他の開発者をブロックすることで、なぜ時間を節約できるのですか?私の提案は、結合を回避するためにインターフェースを使用することです。もちろん、Modelクラスのインターフェースを使用する必要はありません。
Ripal Barot
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.