Pregunta

Supongamos que tengo los siguientes tipos de datos:

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

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

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

Ahora necesito recordar cuando cada uno de los clientes conectados a cada uno de los servicios.
Me gustaría hacer la estructura:

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

O, para ser capaz de buscar por IDS y no tener que escribir todo el igual () y hashCode ():

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

Ahora podía acceder a los datos LastConnection por

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

Todo esto parece fea, sobre todo que tengo que pasar como parámetros a decenas de métodos que esperan mapa de mapas de LastConnections, así que estoy pensando en crear mis propias clases que se vería algo así:

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, yo ya aprendieron que la herencia es 3v1l, por lo que vamos a tratar composición:

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

El problema es que no estoy seguro de lo que sería el mejor enfoque respetando los principios sólidos y todas las mejores prácticas. La creación de clases que no hacen nada, excepto que se extiende colecciones ya existentes parece multiplicar las entidades más de lo necesario, pero haría que mi código sea más clara (Especialmente cuando hay niveles próximos - como Mapa de AllConnections por mes y así sucesivamente). Cualquier dirección?

¿Fue útil?

Solución

  

Creación de clases que no hacen nada   excepto que se extiende ya existente   colecciones parece que multiplicar   entidades más allá de la necesidad

Me gustaría cambiar extiende a encapsular. Usted está ocultando los detalles de cómo se almacena esta información. Clientes de su clase no necesitan saber cómo se les proporcionan el historial de conexiones cliente. Creo que esta es una buena idea ya que se puede cambiar el modelo subyacente sin tener clientes de la API de cambiar su código.

  

pero haría que mi código más claro

Esto es muy bueno y es una buena razón para hacer esto. YourClass.getCustomerConnection (CID) es mucho más claro que yourCollection.get (id) .get (id) .getConnection (). Es necesario hacer la vida de las personas que utilizan este código sea más fácil, incluso si usted es esa persona.

  

(Especialmente cuando hay niveles próximos - como Mapa de AllConnections por mes y así sucesivamente)

Bueno, entonces usted está planeando por delante y hacer que su código extensible. Lo cual es una buena práctica OO. En mi opinión el conculsion que haya llegado por su cuenta es lo que yo haría.

Otros consejos

Me gustaría crear un objeto específico para el almacenamiento de esta información. Lo que se está creando es un Gestor de objeto, en lugar de una colección sencilla.

¿No que sea derivan de un mapa o una clase de colección bien conocida, ya que la semántica de la forma en que almacena esta información puede cambiar en el futuro.

En lugar implementar una clase que une un cliente y su conexión, y dentro de esa clase utilizar la clase de recogida adecuado (que está en la libertad de cambiar más adelante sin afectar la interfaz y el resto de su código)

Su / conexión de la clase administrador de cliente es más que un simple contenedor. Es capaz de almacenar meta-datos (por ejemplo, cuando se estableció esta relación). Se pueden realizar búsquedas en las conexiones dado información al cliente (si se requiere). Puede manejar duplicados cómo se necesite, en lugar de cómo la clase de colección subyacente ellos, etc, etc Puede ranura de forma sencilla en la depuración / monitoreo de la extracción / rendimiento a entender fácilmente lo que está pasando maneja.

Creo que también se debe considerar cómo se van a utilizar las colecciones y cómo se obtienen los datos:

  • Si son resultado simple ajusta a visualizar en una página (por ejemplo), a continuación, utilizando colecciones estándar parece razonable - y, a continuación, puede utilizar una gran cantidad de librerías estándar para manipularlos
  • .
  • Por otro lado, si son mutables y cualquier cambio necesitan ser persistido (por ejemplo), entonces encapsulación de los mismos dentro de sus propias clases podría ser preferible (que luego puede escribir los cambios en las bases de datos, etc.).

¿Cómo se obtiene y persisten sus datos? Si se almacena en una base de datos, entonces tal vez usted puede utilizar SQL para seleccionar LastConnections por cliente y / o servicio y / o mes, en lugar de tener que mantener las estructuras de datos a sí mismo (y simplemente volver listas simples o mapas de conexiones o el número de conexiones ). O tal vez usted no desea ejecutar una consulta para cada solicitud, por lo que necesita para mantener toda la estructura de datos en la memoria.

La encapsulación es generalmente una buena cosa, especialmente en lo que se ayude a adherirse a la Ley de Demeter - tal vez usted puede empujar algunas de las operaciones que se llevará a cabo en las colecciones de nuevo en la clase AllConnections (que es efectivamente un DAO). A menudo, esto puede ayudar a la unidad de pruebas.

Además, ¿por qué se está extendiendo HashMap considera mal aquí, teniendo en cuenta que sólo desea añadir un método de ayuda trivial? En su código de AllConnections, AllConnections siempre se comportan de la misma manera que un HashMap - es polimórfica sustituibles. Por supuesto, usted está potencialmente encerrarse en el uso de HashMap (en lugar de TreeMap, etc), pero que probablemente no importa, ya que tiene los mismos métodos públicos como mapa. Sin embargo, si usted realmente quiere hacer esto realmente depende de cómo se va a utilizar las colecciones - sólo que no creo que se debe de forma automática descuento herencia de implementación como siempre mal (por lo general sólo es !)

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

Why not use custId+"#"+srvurl as a key in a simple Map<String, LastConnection>?

Or use a Tuple or Pair class as key that contains the two IDs and implements hashCode() and equals() - the "cleanest" OO solution.

Why are you maintaining the relationships between objects outside of those objects.

I'd suggest something like the following:

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()
  {
    ...
  }
}

You then pass List<Customer> to the methods that use this information.

You could create a class that implements Map<K,V>, and internally delegate to a container map:

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

The nice thing with this approach is that you can pass around a Map which has a standard, well-defined contract, but you avoid extending library classes, which is often frowned upon.

EDIT : As pointed out below, this does have the downside of requiring you to implement a lot of methods that do nothing short of delegate to the underlying collection

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top