1

私は、約 60 の異なる「タイプ」のイベントがあるイベントのログを扱っています。各イベントは約 10 個のプロパティを共有し、さまざまな追加プロパティを共有するイベントのサブカテゴリがあります。

これらのイベントをどのように処理するかは、イベントの種類または実装するカテゴリ インターフェイスによって異なります。

しかし、コードの肥大化につながっているようです。サブクラス メソッドは同じインターフェイスをいくつか実装しているため、サブクラス メソッドには多くの冗長性があります。

「タイプ」プロパティを持つ単一のイベント クラスを使用し、タイプをチェックしてタイプのカテゴリの編成を維持するロジックを記述する方が適切ですか (たとえば、カテゴリ a のイベント タイプのリスト、カテゴリ b の 2 番目のリスト、等)?それとも、この場合、サブクラスの設計の方が適切ですか?

最初のアプローチ:

public interface Category1 {}
public interface Category2 {}

public abstract class Event {
 private base properties...;
}

public class EventType1 extends Event implements Category1, Category2 {
 private extra properties ...;
}

public class EventType2 extends Event implements Category3, Category4 {
 private extra properties ...;
}

2 番目のアプローチ:

public enum EventType {TYPE1, TYPE2, TYPE3, ...}
public class Event {
 private union of all possible properties;
 private EventType type;
}

私の個人的な意見では、単一のイベント オブジェクトが適切であると思われます。なぜなら、私が正しく考えている場合、継承を使用してモデルを表現する必要はないからです。なぜなら、変更されるのは実際には動作と私の条件だけだからです。タイプに基づいています。

次のようなコードが必要です。

if(event instanceof Category1) {
  ...
}

これは、instanceof の代わりにイベントでメソッドを呼び出して、適切なサブクラスのそれぞれに「同じコード」を実装できるという点で、最初のアプローチでうまく機能します。

しかし、2 番目のアプローチははるかに簡潔です。次に、次のようなものを書きます。

if(CATEGORY1_TYPES.contains(event.getEventType()) {
 ...
}

また、すべての「処理ロジック」は単一のクラスに編成でき、サブクラス間で冗長に分散されることはありません。では、これは OO の方が適切に見えますが、そうでないほうがよいというケースですか?

4

6 に答える 6

1

特定のCategoryインターフェースの抽象基本クラスを拡張する場合は、別のCategoryも実装する必要があるため、継承が制限される可能性があります。

したがって、推奨されるアプローチは次のとおりです。特定のCategoryインターフェイスメソッドに同じ実装が必要であると仮定すると(イベントに関係なく)、Categoryインターフェイスごとに実装クラスを記述できます。

だからあなたは持っているでしょう:

public class Category1Impl implements Category1 {
    ...
}

public class Category2Impl implements Category2 {
    ...
}

次に、各Eventクラスに対して、実装するCategoryインターフェイスを指定し、Category実装クラスのプライベートメンバーインスタンスを保持します(したがって、継承ではなく構成を使用します)。カテゴリインターフェイスメソッドごとに、メソッド呼び出しをカテゴリ実装クラスに転送するだけです。

于 2008-09-28T23:26:35.650 に答える
1

探していた答えが実際には得られなかったので、あまり望ましくない学習経験に基づいて、私自身の最善の推測を提供しています.

イベント自体には実際には振る舞いはありません。振る舞いを持つのはイベントのハンドラーです。イベントはデータ モデルを表すだけです。

イベントをプロパティのオブジェクト配列として扱うようにコードを書き直したので、Java の新しい可変引数と自動ボクシング機能を使用できます。

この変更により、約 100 の巨大なコード クラスを削除し、同じロジックの多くを 1 つのクラスの約 10 行のコードで実現することができました。

教訓: OO パラダイムをデータ モデルに適用することが常に賢明であるとは限りません。大規模な可変ドメインを扱うときは、OO を介して完全なデータ モデルを提供することに集中しないでください。OO 設計は、モデルよりもコントローラーにメリットをもたらす場合があります。通常、10% のパフォーマンスの低下は許容され、他の手段で回復できるため、前もって最適化に集中しないでください。

基本的に、私は問題を過剰に設計していました。これは、適切な OO 設計が過剰であり、1 泊のプロジェクトが 3 か月のプロジェクトになるケースであることが判明しました。もちろん、私は難しい方法で物事を学ばなければなりません!

于 2008-10-06T14:30:59.583 に答える
1

イベント タイプごとのオブジェクト ソリューションを使用しますが、代わりに、一般的に使用されるインターフェイスの組み合わせを、その骨格実装を提供する (おそらく抽象) クラスの下にグループ化します。これにより、多くのインターフェイスを持つことによって生成されるコードの肥大化が大幅に減少しますが、一方で、クラスの数が増加します。しかし、適切かつ合理的に使用すれば、よりクリーンなコードにつながります。

于 2008-09-28T22:54:31.047 に答える
0

.javaファイルが多数あるだけでは必ずしも悪いことではありません。クラスのコントラクトを表す少数(2〜4程度)のインターフェイスを意味のある形で抽出し、すべての実装をパッケージ化できれば、60個の実装でも非常にクリーンなAPIを提供できます。

また、いくつかのデリゲートクラスまたは抽象クラスを使用して、共通の機能を取り込むことをお勧めします。デリゲートおよび/または抽象ヘルパーはすべてパッケージプライベートまたはクラスプライベートである必要があり、公開するAPIの外部では使用できません。

于 2008-09-28T23:15:56.537 に答える
0

動作のかなりの混合と一致がある場合は、他のオブジェクトの合成を使用することを検討し、特定のイベントタイプオブジェクトのコンストラクターにそれらのオブジェクトを作成させるか、ビルダーを使用してオブジェクトを作成します。

おそらくこのようなものですか?

class EventType {

  protected EventPropertyHandler handler;

  public EventType(EventPropertyHandler h) {
     handler = h;
  }

  void handleEvent(map<String,String> properties) {
    handler.handle(properties);
  }
}

abstract class EventPropertyHandler {
   abstract void handle(map<String, String> properties);
}
class SomeHandler extends EventPropertyHandler {
   void handle(map<String, String> properties) {
      String value = properties.get("somekey");
      // do something with value..
   }
}

class EventBuilder {
   public static EventType buildSomeEventType() {
      // 
      EventType e = new EventType( new SomeHandler() );
   }
}

おそらくいくつかの改善が可能ですが、それで始められるかもしれません。

于 2008-09-28T23:19:03.097 に答える
0

イベントの種類ごとに、イベント自体が実行できる異なる動作が本質的にあるかどうかによって異なります。

Event オブジェクトには、型ごとに異なる動作をするメソッドが必要ですか? その場合は、継承を使用してください。

そうでない場合は、列挙型を使用してイベント タイプを分類します。

于 2008-09-29T19:54:12.580 に答える