web-dev-qa-db-ja.com

REST APIクライアントの場合、抽象クラスとインターフェイスのどちらを使用すればよいですか?

REST練習用のAPIクライアントを記述しようとしていますが、プロジェクトのレイアウトを理解するのに苦労しています。

私が今取っているアプローチには、ActionsDomainObjectsRequests、および承認とヘッダーなどを扱うクラス(CoreClient)があります。一般的なDoPut<T>(string address,T item)および類似の動詞を公開します。

ActionUpdateRecordCode(ロジックを含む)

DomainObjectRecordCode(エンティティ)

RequestUpdateRecordCodeRequest(エンティティ、レコードIDとそれに追加するもののリストを保持)

質問1:インターフェイスを実装する必要があるクラス、および最初に必要なインターフェイス、および継承する必要があるクラスを決定するにはどうすればよいですか?

これまでの私の推測では、Actionsは基本的にActionBaseの一種であるため、ActionActionBaseから継承する必要があります。 DomainObjectsは、somethingを実装して一貫性を保つ必要がありますが、私にはわかりません。

最もトリッキーな部分はRequestsです。理想的には、アプリケーションの他の部分でリクエストを一般的に処理して、UIでユーザーが選択できるリクエストのリストを作成できるようにしたいと考えています。私はこれを両方の方法で試しましたが、どちらも変な感じがするので、具体的なクラスに戻ってください。たとえば、インターフェースはIRequest<UpdateRecordCode<UpdateRecordCodeRequest>>、ばかげているようです。

質問2:私はこれを間違っているのですか?誰もが数十のAPIクライアントを書いたように感じます-最小限の計画で数を書いたのですが、今度はこれを「正しく」実行しようとしていますが、それは大変です。

「インターフェイスまたは抽象クラス?」の多くの重複があることを知っています。質問ですが、単純に「XかYか」ではなく、それらがどのように連携するかという点で、これはそれらとは異なると思います。

3
William

過剰設計のアーキテクトは私に反対しますが、C#などの言語では、インターフェースは多重継承を可能にするためにのみ存在し、実装が不十分であり、それが不十分です。つまり、一般的な実装コードを見つけることができる場合は、インターフェイスの代わりに基本クラスを使用することをお勧めします。ただし、なんらかの形式の多重継承が必要な場合は除きます。 C#では、インターフェイスの形式での複数の継承のみが許可されているため、インターフェイスに悩まされています。

特定の例の場合、デザインがインターフェースまたはクラスを保証する理由を説明していません。 「リクエスト」とは、アクション(動詞)とパラメーター(名詞)の組み合わせのようです。これはさまざまな方法で表現できますが、私にとって最も論理的なのは、アクションとパラメータを含む複合オブジェクトです。アクションは、クラスまたはインターフェースを使用して指定する必要はありません。

1
Frank Hileman

@Frank Hilemanが述べたように、C#のインターフェースには実装がなく、複数の具象/抽象クラスから継承することはできません。

ただし、ここでのインターフェースの使用には、継承よりも多くのものがあります。

テスト:アプリケーションでインターフェイスを使用すると、別のオブジェクトが必要とするオブジェクトを「モック」することができます。

たとえば、人の名前をさまざまな方法で操作するクラスをテストする場合、人を格納するためのテーブルとデータを含むデータベースを作成する必要はありません(テストデータのすべてのバリエーションが必要です)。次に、それらのPersonを取得し、それらのPersonを1つずつテストするクラスに渡すために必要なコード。

これは、個人のデータの操作をテストするだけでなく、データとの接続に必要なすべてのコード(認証などを含む)をテストします。

代わりに、テストするクラスがPersonのインターフェースを実装するオブジェクトを受け入れるようにする必要があります。これで、独自の新しい_MyPerson: IPerson_オブジェクトを作成し、テストするさまざまな値をすべて入力して、テストのために毎回渡すことができます。

オブジェクトの保証は、そのオブジェクトが実際に何であるかに関係なく、プロパティや機能を実装します:

処理したい特定の機能を備えたオブジェクトを渡す場合、そのオブジェクトを型チェックして、必要なメソッドまたはプロパティに到達する必要はありません(これは、抽象クラスから継承した具象クラス)。

基礎となるオブジェクトに関係なく、インターフェースを介して公開されるその機能は、すぐに取得および実行可能です。

コードの再利用:

一般的な機能に抽象クラスを使用すると、コードの量とエラーの範囲が減少します。

ActionBaseには、_Create<T>_、<T>Find(int)、_List<T>Get_、_Update<T>_、_Delete<T>_などの一般的なメソッドがある場合があります。ジェネリックを使用してそれらを単一の抽象クラスに実装できるため、通常はすべてを保持するActionクラスからすべてのコードを削除します(_Action: ActionBase<T>_)。

エンティティに関しても、抽象クラスは使用中の共通プロパティを保持します。これらは、すべてのエンティティで使用される場合、識別子(データ型がすべてのエンティティで共通の場合)、ステータスフラグ、DateCreated、DateModifiedなどになります。

5
Steve Padmore