¿Maneras de asegurar instancias únicas de una clase?

14

Estoy buscando diferentes maneras de asegurar que cada instancia de una clase dada sea una instancia única identificable.

Por ejemplo, tengo una clase Name con el campo name . Una vez que tengo un objeto Name con name inicializado a John Smith, no quiero poder crear una instancia de un objeto Name diferente también con el nombre de John Smith, o si la creación de instancias tiene lugar, quiero una referencia al objeto original que se devolverá en lugar de un nuevo objeto.

Soy consciente de que una forma de hacer esto es tener una fábrica estática que contenga un Map de todos los objetos Nombre actuales y la fábrica verifique que un objeto con John Smith como el nombre no existe antes. devolviendo una referencia a un objeto Name .

Otra forma en la que podría pensar fuera de la cabeza es tener un Mapa estático en la clase Name y cuando se llama al constructor a lanzar una excepción si el valor pasado para name ya está en uso en otra objeto, sin embargo, estoy enterado lanzar excepciones en un constructor generalmente es una mala idea .

¿Hay otras maneras de lograr esto?

    
pregunta Peanut 22.10.2012 - 19:44

5 respuestas

13

En realidad ya has respondido tu pregunta. Tu primera forma debería ser más efectiva aquí. Usar static factory siempre es preferible que constructor donde creas que puedes. Por lo tanto, puede evitar usar Constructor en este caso, de lo contrario, tendría throw some exception si ya existe una instancia con el nombre dado.

Por lo tanto, puede crear un método de fábrica estático: - getInstanceWithName(name) que obtendrá la instancia ya disponible con ese nombre y, si no existe, creará una nueva instancia y hará que su constructor sea privado. como se debe hacer principalmente cuando se trata de static factories .

También, para eso necesitas mantener un List o Map estático de todas las instancias únicas creadas, en tu clase Factory .

EDIT : -

Sin duda, debería consultar: Java efectivo - Artículo n.º 1: Considere fábricas estáticas sobre constructores . No puedes obtener una mejor explicación que ese libro.

    
respondido por el Rohit Jain 22.10.2012 - 19:51
5

Las menciones de Eficaz Java parecen agregar mucha credibilidad, por lo que esta respuesta se basa en:

  • Artículo 8 de Java efectivo: obedecer el contrato general cuando se reemplaza a los iguales
  • Artículo 9 de Java efectivo: siempre anula el código de hash cuando anulas iguales
  • Artículo 15 de Java efectivo: minimizar la mutabilidad

Daría un paso atrás y me preguntaría por qué te importa si hay más de una instancia de este objeto de nombre.

Rara vez necesito hacer este tipo de agrupación de objetos. Supongo que el OP está haciendo esto para que puedan simplemente comparar sus objetos Name con == . O use los objetos Name dentro de un HashMap o similar como clave.

Si es así, esto es algo que se puede resolver a través de implementación correcta de equals() .

Me gusta así:

public final class Name {
  private final String name;

  public Name(String name) {
    if (name == null) {
      name = ""; //or exception if you like
    }
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Name)) {
      return false;
    }
    Name other = (Name) o;
    return other.name.equals(name);
  }

  @Override
  public int hashCode() {
    return name.hashCode();
  }
}

Una vez hecho esto, se cumple lo siguiente:

Name a = new Name("weston");
Name b = new Name("weston");
assert(a.equals(b)); //same but:
assert(a!=b); //not the same instance
//test out the Name instances in a hashmap:
HashMap<Name,Object> map = new HashMap<Name,Object>();
Object detailsIn = new Object();
map.put(a,detailsIn);
Object detailsOut = map.get(b);
assert(detailsIn==detailsOut); //the map returned the same details object
//even though we put with 'a' and got with 'b' thanks to our correct equals implementation

Estoy adivinando tu objetivo, pero de esta manera puedes usar la clase Name en mapas hash, etc., y no tienen que ser exactamente la misma instancia.

    
respondido por el weston 22.10.2012 - 20:08
3
  • Haz de Name una interfaz
  • Cree una interfaz NameFactory con un método Name getByName(String)
  • Cree una implementación de NameFactory con un Map<String,WeakReference<Name>> dentro de ella
  • synchronize en el mapa por nombre dentro del método getByName antes de crear nuevas instancias de Name
  • Opcionalmente, use una implementación privada estática de la interfaz Name dentro de su implementación de NameFactory

Este enfoque le permitiría asegurarse de que:

  • Solo existe una instancia de Name en cualquier momento,
  • No hay pérdida de memoria "Lingerer" en tu clase, cuando Name s se quedan más tiempo del necesario,
  • El diseño sigue siendo comprobable con objetos simulados, porque utiliza interfaces.
respondido por el dasblinkenlight 22.10.2012 - 20:12
1

debe hacer que los constructores sean privados y crear métodos como getNameInstance(String) , si ya existe un objeto con el mismo nombre (basado en una clase estática, por ejemplo), devuelve esa referencia, o crea un nuevo objeto usando su constructor privado y agréguelo a la tabla hash

    
respondido por el HericDenis 22.10.2012 - 19:58
1

Intenta seguir. Tienes que hacer un seguimiento de cada objeto que creas. Para ello estoy utilizando la lista. E hizo que el constructor de la clase fuera privado, de modo que la comprobación previa se pueda aplicar antes de crear una instancia

class UniqueName
    {
        private string Name;
        public int ID;
        private static int Count=0;
        static List<UniqueName> lt=new List<UniqueName>();

        private UniqueName(string Name)
        {
            this.Name = Name;
            ID = ++Count;
        }

        public static UniqueName GetUniqueueInstance(string Name)
        {
            foreach (UniqueName un in lt)
            {
                if ( string.Compare( un.Name,Name,StringComparison.InvariantCultureIgnoreCase)==0)
                    return un;
            }

            UniqueName temp=new UniqueName(Name);
            lt.Add(temp);
            return temp;
        }
    }
    
respondido por el Akshay 23.10.2012 - 12:59

Lea otras preguntas en las etiquetas