Java 如果有很多类型,我不应该按对象类型划分子类吗?

Java 如果有很多类型,我不应该按对象类型划分子类吗?,java,design-patterns,inheritance,Java,Design Patterns,Inheritance,我正在处理一个事件日志,其中有大约60种不同的“类型”的事件。每个事件共享大约10个属性,然后是共享各种额外属性的事件子类别 我如何处理这些事件取决于它们的类型或它们实现的分类接口 但这似乎导致了代码膨胀。我在子类方法中有很多冗余,因为它们实现了一些相同的接口 是否更适合使用具有“type”属性的单个事件类和写入逻辑来检查类型并维护类型类别的某些组织(例如,类别a的事件类型列表、类别b的第二个列表等)?或者子类设计在这种情况下更合适 第一种方法: public interface Categor

我正在处理一个事件日志,其中有大约60种不同的“类型”的事件。每个事件共享大约10个属性,然后是共享各种额外属性的事件子类别

我如何处理这些事件取决于它们的类型或它们实现的分类接口

但这似乎导致了代码膨胀。我在子类方法中有很多冗余,因为它们实现了一些相同的接口

是否更适合使用具有“type”属性的单个事件类和写入逻辑来检查类型并维护类型类别的某些组织(例如,类别a的事件类型列表、类别b的第二个列表等)?或者子类设计在这种情况下更合适

第一种方法:

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 ...;
}
public enum EventType {TYPE1, TYPE2, TYPE3, ...}
public class Event {
 private union of all possible properties;
 private EventType type;
}
第二种方法:

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 ...;
}
public enum EventType {TYPE1, TYPE2, TYPE3, ...}
public class Event {
 private union of all possible properties;
 private EventType type;
}
我个人的观点是,似乎单个事件对象才是合适的,因为如果我正确地考虑它,就没有必要使用继承来表示模型,因为实际上只有行为和我的条件根据类型而改变

我需要有这样的代码:

if(event instanceof Category1) {
  ...
}
if(CATEGORY1_TYPES.contains(event.getEventType()) {
 ...
}
这在第一种方法中效果很好,因为我可以在事件上调用该方法,并在每个适当的子类中实现“相同的代码”,而不是instanceof

但第二种方法要简洁得多。然后我写了一些东西,比如:

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

我所有的“处理逻辑”都可以组织成一个类,并且没有一个是冗余地分布在子类中的。因此,在这种情况下,虽然OO看起来更合适,但最好不要太过合适?

我会选择每个事件类型的对象解决方案,但我会将常用的接口组合分组在提供其框架实现的类下(可能是抽象的)。这大大减少了由于有许多接口而产生的代码膨胀,但另一方面,增加了类的数量。但是,如果正确、合理地使用,它会导致更干净的代码。

仅仅拥有大量的.java文件并不一定是坏事。如果您可以有意义地提取少量(2-4个左右)表示类契约的接口,然后打包所有实现,那么您提供的API可能非常干净,即使有60个实现


我还建议使用一些委托类或抽象类来引入公共功能。委托和/或抽象帮助器都应该是包私有的或类私有的,在您所公开的API之外不可用。

< P>如果有相当多的混合和匹配行为,我将考虑使用其他对象的组合,然后使特定事件类型对象的构造器创建这些对象,或者使用生成器创建对象

也许是这样的

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() );
   }
}
class事件类型{
受保护的EventPropertyHandler处理程序;
公共事件类型(EventPropertyHandler h){
handler=h;
}
void handleEvent(贴图属性){
handler.handle(属性);
}
}
抽象类EventPropertyHandler{
抽象空句柄(映射属性);
}
类SomeHandler扩展了EventPropertyHandler{
无效句柄(贴图属性){
字符串值=properties.get(“somekey”);
//做有价值的事。。
}
}
类事件生成器{
公共静态事件类型buildSomeEventType(){
// 
EventType e=neweventtype(newsomehandler());
}
}

可能会有一些改进,但这可能会让您开始。如果您决定扩展抽象基类,继承可能会受到限制 特定的类别接口,因为您可能还需要实现另一个类别

因此,这里有一个建议的方法: 假设特定类别接口方法需要相同的实现(不管发生什么事件),可以为每个类别接口编写一个实现类

所以你会:

public class Category1Impl implements Category1 {
    ...
}

public class Category2Impl implements Category2 {
    ...
}

然后,对于每个事件类,只需指定它实现的类别接口,并保留类别实现类的私有成员实例(因此使用组合,而不是继承)。对于每个类别接口方法,只需将方法调用转发到类别实现类。

这取决于每种类型的事件本身是否具有事件本身可以执行的不同行为

您的事件对象是否需要每种类型行为不同的方法?如果是这样,请使用继承


如果没有,请使用枚举对事件类型进行分类。

因为我没有真正得到我想要的答案,所以我根据我不太理想的学习经验提供了我自己的最佳猜测

事件本身实际上没有行为,只有事件的处理程序才有行为。事件只是表示数据模型

我重写了代码,将事件作为属性的对象数组来处理,这样我就可以使用Java新的变量参数和自动装箱功能

有了这个改变,我能够删除大约100个巨大的代码类,并在一个类中用大约10行代码完成大部分相同的逻辑

经验教训:将OO范例应用于数据模型并不总是明智的。在处理大型可变域时,不要专注于通过OO提供完美的数据模型。OO设计有时对控制器的好处大于模型。也不要预先关注优化,因为通常10%的性能损失是可以接受的,并且可以通过其他方式恢复


基本上,我是在设计问题。事实证明,在这种情况下,适当的OO设计是过度的,将一个一夜的项目变成了一个三个月的项目。当然,我必须用艰苦的方式学习

事件实现多个接口,java不支持