web-dev-qa-db-ja.com

空のインターフェイス(マーカーインターフェイスではない)は不適切なプログラミング方法ですか?

私が持っているアーキテクチャを設計しています:

public interface IObjectReader{
    public Object read();
}

public class ConcreteObjectReader implements IObjectReader{
     @Override
     public Object read(){
         //do stuff
         return new Object();
     }
}

これで、リーダーをパラメーター化できるようにしたい場合は、次の方法で別のインターフェイスを作成できます。

public interface IParameterizedObjectReader extends IObjectReader {
    public void setParams(Map<String,String> params);
    public Map<String,String> getParams();
}

私にはこれは合理的です。ただし、私のプロジェクトには、オブジェクトライター、オブジェクトプロセッサなども含まれており、最終的にはパラメーター化する必要もあります。このシナリオでは、同じコントラクト(getParamsとsetParams)を定義する2つ以上のインターフェイスを持つことは、私には非常に悪い考えです。だから私はこのようなインターフェイスIParameterを定義します:

public interface IParameter{
    public void setParams(Map<String,String> params);
    public Map<String, String> getParams();
}

また、IParametereziedObjectReaderインターフェイス(IParameterizedObjectWriterなども同様)がIParameterを拡張するようにしますが、空のままにしておきます。

これは悪い考えですか?または、IParameterインターフェイスのみを残して、そのサブインターフェイスを削除する必要がありますか?わかりやすくするために、これらのパラメーター化されたインターフェイスをコード内のマーカーとして使用していないので、アーキテクチャ上の理由で空になっていることを言わなければなりません。

このソリューションをどのように異なる方法で設計しますか?

5
sibly22

空のインターフェイス(マーカーインターフェイスではない)は不適切なプログラミング方法ですか?

通常、はい。定義により、空のインターフェースは何も提供しません。それらは、マーカーインターフェイス(通常は悪)、または別のタイプのエイリアス(何かの名前を変更するときにレガシーコードが原因で時々役立つ)にすることができます。しかし、このようなグリーンフィールドプロジェクトでは、彼らは単なるエンジニアリングとYAGNIです。

このソリューションをどのように異なる方法で設計しますか?

あなたの要件についてもっと知らなければ、私は言うことはできません。しかし、任意読み取り/書き込み/処理を行い、任意パラメータの数/形状を作成しようとするのは、ばかげた用事です。 「何でもできる」システムは、コードを書くだけで有用な抽象化を提供しておらず、実装と保守が悪夢のようになりがちです。スクリプト言語が必要な場合は、seスクリプト言語を使用してください。

13
Telastyn

これは インターフェース分離原理 の仕事のように見えます!

あなたはこれを作りたいと言います:

public interface IParameterizedObjectReader extends IObjectReader {
    public void setParams(Map<String,String> params);
    public Map<String,String> getParams();
}

またはこれ:

public interface IParameterizedObjectReader extends IObjectReader, IParameter { }

これが必要ですか?

IParameter p;

この:

IObjectReader oReader;

この:

IParameterizedObjectReader por;

それは、それらすべてを必要とするクライアントがいない場合、理由がわかりにくいために物事を少し難しくしているためです。それが拡張するインターフェースからそれが約束するものを得るのでインターフェースが空であるかもしれないという事実は本当に私には何の意味もありません。私は単に重複がないのが好きです。しかし、それはインターフェースの存在を正当化または弱体化しません。

インターフェイスの存在を正当化するのは、一部のクライアントがそれを使用したいということです。クライアントはインターフェースを所有します。彼らはインターフェースが約束するものを必要としています。空のボディで定義されていても問題ありません。地獄、インターフェイスは単に名前の間接化を提供するために存在するかもしれません。

そして、はい、この方法で複雑さを作成できます。 「アーキテクチャ上の理由」のために作成しないでください。何かがそれを必要とするのでそれを作成してください。今。今日。

クライアントは、気にしないメソッドについて知る必要はありません。このルールに従うと、インターフェースはロールインターフェースになります。それぞれが正当な理由で存在します。単一の責任があります。そして、すべての可能なメソッドのセットについて、インターフェースの組み合わせが爆発的に増えることはありません。

ああ、覚えておいてください、IMyInterfaceプレフィックスはC#のものです。 JavaはMyImplementationImpl接尾辞を実行します。どちらもひどいものですが、それらは実際のものです。

2
candied_orange

インターフェースのツリーを構築し、あるインターフェースを別のインターフェースから継承させると、そもそもインターフェースを持つという目的がすぐに無効になります。クラスツリーを作成して、インターフェイスをまったく使用しないこともできます。

単一のシナリオを提供するだけですべてを実行する1つの複合インターフェイスを持つよりも、それぞれが単一の機能を持つ複数の小さなインターフェイスを持つ方が常に優れています。後者の場合、あなたは本当にあなたの頭の後ろにすでに持っているクラスにインターフェースを結びつけ、それを他のものには役に立たなくし、それゆえに持っても意味がありません。

したがって、特定の例では、互いに独立したIReaderとIParameterizableインターフェイスが必要であり、それぞれが任意のクラスの完全な機能セットではなく単一の機能を定義しています。

2
Martin Maat

リーダー、ライター、およびプロセッサーに共通の署名を持つメソッドがあるという事実は、単なる偶然の状況です。

IParameterインターフェースを導入すると、リーダー、ライター、およびプロセッサの抽象概念が同じ契約署名の下でバインドされます。
最初の変更リクエストの後、readerクラスに引数を1つ追加するか、パラメータタイプを変更する必要があります-IParameterを破棄します。

アプリケーションにはパラメーターのないリーダーとパラメーター化されたリーダーの両方が必要なので、2つの方法でリーダーを導入することを検討してください。

public interface IObjectReader
{
    public Object read();
    public Object read(Map<String,String> params);
}
0
Fabio