Pergunta

Eu estou trabalhando com um log de eventos, onde existem cerca de 60 "tipos" diferentes de eventos. Cada evento ações cerca de 10 propriedades, e depois há subcategorias de eventos que compartilham várias propriedades extras.

Como eu trabalho com esses eventos não depende de seu tipo ou quais interfaces categóricas eles implementam.

Mas parece estar levando a inchaço código. Eu tenho um monte de redundância nos métodos da subclasse porque implementar algumas das mesmas interfaces.

É mais apropriado usar uma única classe de evento com uma lógica de propriedade e escrever "tipo" que os controlos digitar e manter alguma organização de categorias de tipos (por exemplo, uma lista de tipos de eventos que são categoria um, uma segunda lista que são categoria b, etc)? Ou é o design subclasse mais apropriado neste caso?

Primeira Abordagem:

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 ...;
}

Segunda abordagem:

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

A minha opinião pessoal é que parece que um único objeto de evento é o que é apropriado, porque, se eu estou pensando sobre isso corretamente, não há necessidade de usar a herança para representar o modelo porque é realmente apenas o comportamento e minha condições que alteram com base no tipo.

Eu preciso ter código que faz coisas como:

if(event instanceof Category1) {
  ...
}

Isso funciona bem na primeira abordagem, em que em vez de instanceof eu só posso chamar o método no evento e implementar "o mesmo código" em cada uma das subclasses apropriadas.

Mas a segunda abordagem é muito mais concisa. Em seguida, o material Eu escrevo como:

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

E toda minha "lógica de processamento" podem ser organizados em uma única classe e nenhuma dele é redundante espalhar-se entre as subclasses. Portanto, este é um caso em que, embora OO parece mais adequada, seria melhor não muito?

Foi útil?

Solução

Depende se cada tipo de evento inerentemente tem um comportamento diferente que o evento em si pode executar.

Os seus objetos Event precisam de métodos que se comportam de forma diferente por tipo? Se assim for, o uso de herança.

Se não, use uma enumeração para classificar o tipo de evento.

Outras dicas

Eu iria com o objeto por solução tipo de evento, mas, ao invés, grupo combinações de interfaces comumente usadas sob classes (provavelmente abstratas) fornecendo sua esquelético implementações . Isto reduz significativamente o inchaço código gerado por ter muitas interfaces, mas, por outro lado, aumenta o número de classes. Mas, se usado corretamente e razoavelmente, que leva a um código mais limpo.

A herança pode ser limitante se você decidir estender uma classe base abstrata de um em particular interface de Categoria, porque pode ser necessário implementar outra categoria também.

Então, aqui está uma abordagem sugeriu: Supondo que você precisa a mesma implementação de um método de interface particular Categoria (independentemente do Evento), você poderia escrever uma classe de implementação para cada interface categoria.

Então você teria que:

public class Category1Impl implements Category1 {
    ...
}

public class Category2Impl implements Category2 {
    ...
}

Em seguida, para cada uma das classes de evento, basta especificar as interfaces Categoria ele implementa, e manter uma instância membro particular da classe Categoria de implementação (para que você use composição, em vez de herança). Para cada um dos métodos Categoria de interface, simplesmente encaminhar a chamada de método para a classe Categoria implementação.

Desde que eu realmente não obter as respostas que eu estava procurando Eu estou oferecendo meu próprio palpite com base na minha experiência menos do que o aprendizado desejável.

Os eventos em si, na verdade, não têm comportamentos, são os manipuladores dos eventos que têm comportamentos. Os eventos apenas representam o modelo de dados.

Eu reescrevi o código para eventos apenas tratar como arranjos de objetos de propriedades para que eu possa usar novos argumentos variáveis ??de Java e recursos de auto-boxing.

Com esta mudança, eu era capaz de eliminar cerca de 100 aulas gigantescas de código e realizar muito da mesma lógica em cerca de 10 linhas de código em uma única classe.

Lesson (s) aprendida: Não é sempre aconselhável aplicar paradigmas OO ao modelo de dados. Não se concentrar em fornecer um modelo de dados perfeita via OO quando se trabalha com um grande domínio, variável. projeto OO beneficia o controlador mais que o modelo vezes. Não se concentrar em adiantado otimização, bem como, porque geralmente uma perda de desempenho de 10% é aceitável e pode ser recuperado através de outros meios.

Basicamente, eu estava excesso de engenharia do problema. Acontece que este é um caso onde o design OO adequada é um exagero e se transforma um projeto de uma noite em um projeto de 3 meses. Claro, eu tenho que aprender as coisas da maneira mais difícil!

Simplesmente ter um grande número de arquivos .java não é necessariamente ruim. Se você pode significativamente extrair um pequeno número (2-4 ou mais) de interfaces que representam os contratos das classes, e depois empacotar todas as implementações acima, a API que você apresenta pode ser muito limpo, mesmo com 60 implementações.

Eu também poderia sugerir o uso de algum delegado ou classes abstratas para puxar funcionalidade comum. Os delegados e / ou ajudantes abstratos devem ser todos pacote-privadas ou classe-privada, fora não disponível a API que você expor.

Se houver mistura considerável e correspondência de comportamento, eu consideraria usando a composição de outros objetos, em seguida, ter tanto o construtor do tipo de objeto evento específico criar esses objetos, ou usar um construtor para criar o objeto.

talvez algo assim?

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() );
   }
}

Há provavelmente algumas melhorias que poderiam ser feitas, mas que pode você começar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top