it-swarm.com.de

Möglichkeiten, um eindeutige Instanzen einer Klasse sicherzustellen?

Ich suche nach verschiedenen Möglichkeiten, um sicherzustellen, dass jede Instanz einer bestimmten Klasse eine eindeutig identifizierbare Instanz ist.

Zum Beispiel habe ich eine Name Klasse mit dem Feld name. Sobald ich ein Name Objekt mit name auf John Smith initialisiert habe, möchte ich nicht in der Lage sein, ein anderes Name Objekt auch mit dem Namen John Smith oder zu instanziieren Wenn eine Instanziierung stattfindet, möchte ich, dass ein Verweis auf das ursprüngliche Objekt zurückgegeben wird und nicht ein neues Objekt.

Ich bin mir bewusst, dass eine Möglichkeit, dies zu tun, darin besteht, eine statische Factory zu haben, die ein Map aller aktuellen Name-Objekte enthält, und die Factory überprüft, ob ein Objekt mit John Smith als Name noch nicht existiert Rückgabe eines Verweises auf ein Name Objekt.

Eine andere Möglichkeit, die ich mir vorstellen kann, ist eine statische Map in der Klasse Name, und wenn der Konstruktor aufgerufen wird, eine Ausnahme auszulösen, wenn der für name übergebene Wert bereits vorhanden ist Verwendung in einem anderen Objekt, aber mir ist bewusst Ausnahmen in einem Konstruktor zu werfen ist im Allgemeinen eine schlechte Idee .

Gibt es andere Möglichkeiten, dies zu erreichen?

14
Peanut

Eigentlich haben Sie Ihre Frage bereits beantwortet. Ihr erster Weg sollte hier effektiver sein. Die Verwendung von static factory Ist immer vorzuziehen als constructor, wo immer Sie denken, dass Sie können. In diesem Fall können Sie die Verwendung von Constructor vermeiden. Andernfalls hätten Sie throw some exception, Wenn bereits eine Instanz mit dem angegebenen Namen vorhanden ist.

Sie können also eine statische Factory-Methode erstellen: - getInstanceWithName(name), die die bereits verfügbare Instanz mit diesem Namen abruft. Wenn sie nicht vorhanden ist, wird eine neue Instanz erstellt und Ihre constructor privat, wie es meistens beim Umgang mit static factories gemacht werden sollte.

Dazu müssen Sie außerdem ein statisches List oder Map aller in Ihrer Factory -Klasse erstellten eindeutigen Instanzen verwalten.

[~ # ~] edit [~ # ~] : -

Sie sollten auf jeden Fall durchgehen - Effektiv Java - Punkt 1: Betrachten Sie statische Fabriken über Konstruktoren . Sie können keine bessere Erklärung als dieses Buch erhalten.

13
Rohit Jain

Erwähnungen von Effektivem Java scheinen viel Glaubwürdigkeit zu verleihen, daher stützt sich diese Antwort auf:

  • Effektiv Java Punkt 8: Befolgen Sie den allgemeinen Vertrag, wenn Sie gleich überschreiben
  • Effektiv Java Punkt 9: Überschreiben Sie immer den Hashcode, wenn Sie gleich überschreiben
  • Effektiv Java Punkt 15: Mutabilität minimieren

Ich würde einen Schritt zurücktreten und fragen, warum es Sie interessiert, wenn es mehr als eine Instanz dieses Namensobjekts gibt.

Ich muss diese Art von Objektpooling selten durchführen. Ich vermute, dass das OP dies tut, damit sie einfach ihre Name Objekte mit == Vergleichen können. Oder verwenden Sie die Objekte Name in einem HashMap oder ähnlichem als Schlüssel.

Wenn ja, kann dies durch ordnungsgemäße Implementierung von equals() gelöst werden.

Wie so:

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

Sobald dies erledigt ist, ist Folgendes wahr:

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

Ich vermute Ihr Ziel, aber auf diese Weise können Sie die Klasse Name in Hash-Maps usw. verwenden, und sie müssen nicht sei genau die gleiche Instanz.

5
weston
  • Machen Sie Name zu einer Schnittstelle
  • Erstellen Sie eine Schnittstelle NameFactory mit einer Methode Name getByName(String)
  • Erstellen Sie eine Implementierung von NameFactory mit einem Map<String,WeakReference<Name>> im Inneren
  • synchronize auf der Karte nach Namen innerhalb der Methode getByName, bevor neue Instanzen von Name erstellt werden
  • Verwenden Sie optional eine statische private Implementierung der Schnittstelle Name in Ihrer Implementierung von NameFactory

Mit diesem Ansatz können Sie Folgendes sicherstellen:

  • Es ist immer nur eine einzige Instanz von Name vorhanden.
  • Es gibt kein "Lingerer" -Speicherleck in Ihrer Klasse, wenn Names länger als nötig bleiben,
  • Das Design bleibt mit verspotteten Objekten testbar, da Sie Schnittstellen verwenden.
3
dasblinkenlight

sie sollten die Konstruktoren privat machen und Methoden wie getNameInstance(String) erstellen. Wenn bereits ein Objekt mit demselben Namen vorhanden ist (beispielsweise basierend auf einer statischen Klasse 'hastable), geben Sie diese Referenz zurück, andernfalls erstellen Sie ein neues Objekt Verwenden Sie Ihren privaten Konstruktor und fügen Sie ihn der Hashtabelle hinzu

1
HericDenis

Versuchen Sie Folgendes. Sie müssen jedes Objekt, das Sie erstellen, im Auge behalten. Zu diesem Zweck verwende ich List. Der Klassenkonstruktor wurde privat gemacht, sodass vor dem Erstellen einer Instanz eine Vorabprüfung durchgeführt werden kann

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