Pergunta

Suponha que eu tenho os seguintes tipos de dados:

class Customer {
  String id; // unique
  OtherCustData someOtherData;
}

class Service {
  String url; // unique
  OtherServiceData someOtherData;
}

class LastConnection {
  Date date;
  OtherConnData someOtherData; // like request or response
}

Agora eu preciso lembrar quando cada um dos clientes ligados a cada um dos serviços.
Eu faria a estrutura:

Map<Customer, Map<Service, LastConnection>> lastConnections;

Ou, para ser capaz de pesquisar por ids e não tem que escrever todo o igual () e hashCode ():

Map<String, Map<String, LastConnection>> lastConnections;

Agora eu poderia acessar os dados LastConnection por

LastConnection connection = lastConnections.get(custId).get(srvUrl);

Tudo isso parece feio, especialmente que eu tenho que passá-lo como parâmetros para dezenas de métodos que esperam mapa de mapas de LastConnections, por isso estou pensando em criar minhas próprias classes que seria algo parecido com isso:

class CustomerConnections extends HashMap<String, LastConnection> {
}

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}

Ok, eu já aprendi que a herança é 3v1l, então vamos tentar composição:

class CustomerConnections {
    Map<String, LastConnection> customerConnections;
    LastConnection get(String srvUrl) { 
        return customerConnections.get(srvUrl);
    }
    ... // all other needed operations;
}

class AllConnections {
    Map<String, CustomerConnections> allConnections;
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
    public CustomerConnection get(String custId) {
        return allConnections.get(custId);
    }
    ... // all other needed operations;
}

O problema é que eu não tenho certeza qual seria a melhor abordagem respeitando princípios sólidos e todas as melhores práticas. Criação de classes que não fazem nada, exceto estendendo coleções já existentes parece multiplicar entidades além da necessidade, mas faria o meu código mais claro (especialmente quando existem níveis próximos - como Mapa de AllConnections por mês e assim por diante). Todos os sentidos?

Foi útil?

Solução

Criação de classes que não fazem nada excepto que se prolonga já existente coleções parece multiplicação entidades além da necessidade

Eu mudaria estender para encapsular. Você está escondendo os detalhes de como essas informações são armazenadas. Os clientes da sua classe não precisa saber como você está fornecendo-lhes a história de conexão do cliente. Eu acho que isso é uma boa idéia, pois você pode alterar o modelo subjacente sem ter clientes da mudança api seu código.

mas faria o meu código mais clara

Isso é ótimo e é uma boa razão para fazer isso. YourClass.getCustomerConnection (CID) é muito mais clara do que yourCollection.get (id) .get (id) .getConnection (). Você precisa fazer a vida das pessoas que usam esse código mais fácil, mesmo se você é essa pessoa.

(Especialmente quando há níveis próximos - como Mapa de AllConnections por mês e assim por diante)

bom, então você está planejando em frente e fazer o seu extensível código. Que é uma boa prática OO. Na minha opinião o conculsion de ter atingido em seu próprio país é o que eu faria.

Outras dicas

Gostaria de criar um objeto dedicado para armazenar essas informações. O que você está criando é um gerente objeto, ao invés de uma coleção simples.

I que não torná-lo derivar de um mapa ou outra classe de coleção bem conhecida, uma vez que a semântica de como você armazenar esta informação pode mudar no futuro.

Em vez implementar uma classe que une um cliente e sua conexão, e dentro de que o uso de classe a classe de recolha apropriado (que está em liberdade para mudança mais tarde, sem afetar a interface eo resto do seu código)

Sua classe gerente de cliente / conexão é mais do que um recipiente simples. Ele pode armazenar os meta-dados (por exemplo, quando se esta relação estabelecida). Ele pode realizar pesquisas em conexões dadas informações do cliente (se precisar). Ele pode lidar com duplicatas como você precisa, em vez de como as subjacentes alças classe coleção-los etc. etc. Você pode facilmente ranhura na depuração / logging / Monitoramento de desempenho para compreender facilmente o que está acontecendo.

Eu acho que você também deve considerar como as coleções vão ser usados ??e como os dados são obtidos:

  • Se eles são conjuntos de resultados simples de ser exibidas em uma página (por exemplo), em seguida, usando coleções padrão parece razoável. - E então você pode usar lotes de bibliotecas padrão para manipulá-los
  • Por outro lado, se eles são mutáveis ??e quaisquer mudanças precisam ser persistentes (por exemplo), em seguida, encapsulando-os dentro de suas próprias classes pode ser preferível (que pode, então, mudanças gravação para bancos de dados, etc).

Como você recebe e persistir seus dados? Se ele é armazenado em um banco de dados, então talvez você pode usar SQL para selecionar LastConnections por cliente e / ou serviços e / ou mês, em vez de ter que manter os datastructures-se (e apenas retornar listas simples ou mapas de conexões ou contagens de conexões ). Ou talvez você não deseja executar uma consulta para cada solicitação, por isso necessidade de manter toda a estrutura de dados na memória.

O encapsulamento é geralmente uma boa coisa, porém, particularmente no que pode ajudá-lo a aderir ao Lei de Deméter - talvez você pode empurrar algumas das operações que você vai realizar nas coleções de volta para a classe AllConnections (que é efetivamente um DAO). Isso muitas vezes pode testar ajuda unidade.

Além disso, por que está estendendo HashMap considerada mal aqui, considerando que você só quer adicionar um método auxiliar trivial? Em seu código para AllConnections, AllConnections sempre se comportam da mesma forma que um HashMap - é polymorphically substituíveis. Claro, você está potencialmente se trancar em usar HashMap (em vez de TreeMap, etc), mas que provavelmente não importa, uma vez que tem os mesmos métodos públicos como mapa. No entanto, se você realmente quer fazer isso realmente depende de como você pretende usar as coleções - Eu só não acho que você deve herança de implementação automaticamente desconto como sempre ruim (ele só é normalmente !)

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}

Por que não usar custId+"#"+srvurl como uma chave em um Map<String, LastConnection> simples?

Ou usar um Tuple ou classe Par como a chave que contém a dois IDs e implementos hashCode() e equals() - o " mais limpa" solução OO.

Por que você está mantendo as relações entre objetos fora desses objetos.

Eu sugiro algo como o seguinte:

public class Customer 
{
  public List<LastConnection> getConnectionHistory() 
  {
    ... 
  }

  public List<LastConnection> getConnectionHistory(Service service) 
  {
    ...
  }

  public List<LastConnection> getConnectionHistory(Date since) 
  {
    ...
  }
}

public class LastConnection
{
  public Date getConnectionTime() 
  {
    ...
  }

  public Service getService()
  {
    ...
  }
}

Você, então, passar List<Customer> aos métodos que utilizam essas informações.

Você pode criar uma classe que implementos Map<K,V>, e delegar internamente para um mapa recipiente:

class CustomerConnections implements Map<String,LastConnection> {
    private Map<String, LastConnection> customerConnections;

    @Override
    public LastConnection get(Object srvUrl) { 
        return customerConnections.get(srvUrl);
    }
    // all other needed operations;
}

A coisa agradável com esta abordagem é que você pode passar em torno de um Map que tem um padrão, contrato bem definido, mas você evitar estender classes biblioteca, que muitas vezes é desaprovada.

Editar : Como se verá mais adiante, isso tem a desvantagem de exigir que você para implementar uma série de métodos que não fazem nada menos do delegado para a coleção subjacente

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