Bir sınıfın benzersiz örneklerini sağlamanın yolları?


14

Belirli bir sınıfın her örneğinin benzersiz bir şekilde tanımlanabilir bir örnek olmasını sağlamak için farklı yollar arıyorum.

Örneğin Name, alanla bir sınıfım var name. Bir sahip olduktan sonra Namenesneyi namefarklı bir örneğini edebilmek istemiyorum John Smith I başlatıldı NameJohn Smith gibi adıyla da nesneyi örnekleme işlemleri burada yaparsa, yoksa orjinal nesneye bir referans yerine geri geçirmek istediğinizi yeni bir nesneden.

Bunu yapmanın bir yolunun, Maptüm geçerli Name nesnelerini tutan statik bir fabrikaya sahip olduğunun farkındayım ve fabrika, bir referansa geri dönmeden önce John Smith ile bir nesnenin zaten var olmadığını kontrol ediyor Namenesne.

Başımın üst kısmından düşünebileceğim başka bir yol, Namesınıfta statik bir Haritaya sahip olmak ve geçirilen değer namezaten başka bir nesnede kullanılıyorsa, bir istisna atma çağrıldığında , ancak istisna atmanın farkındayım bir kurucuda genellikle kötü bir fikirdir .

Bunu başarmanın başka yolları var mı?


1
Bir singleton

5
birincisiyle
gitsen

16
@MarcB op singleton istemiyor. aynı sınıftan birçok örneği olabilir, ancak bu örneklerin tanımlanabilir olması gerekir.

1
@MarcB Tekil paternin farkındayım ama bir sınıfın sadece bir örneğinin mümkün olduğunu düşündüm? Birden çok örnek, farklı değerler istiyorum. Soru bu durumu netleştirmiyorsa özür dileriz. edit: Sadece göndermeden önce ilk yorum gördüm.
Fıstık

2
I'm aware that one way of doing this is to have a static factory that holds a Map...Öyleyse neden bu şekilde yapmak istemiyorsun?
SinirliWithFormsDesigner

Yanıtlar:


13

Aslında sorunuzu zaten cevapladınız. İlk yolunuz burada daha etkili olmalıdır. Kullanmak static factoryher zaman constructordüşündüğünüzden daha fazla tercih edilir . Yani, Constructorbu durumda kullanmaktan kaçınabilirsiniz , aksi throw some exceptiontakdirde verilen adla bir örneğin mevcut olması gerekir.

Böylece, statik bir fabrika yöntemi oluşturabilirsiniz: - getInstanceWithName(name)bu adla zaten kullanılabilir olan örneği alır ve yoksa, yeni bir örnek oluşturur ve özelliğinizi yapar constructor, çünkü çoğunlukla uğraşırken yapılması gerekir static factories.

Ayrıca, bunun için sınıfınızda statik Listveya Mapoluşturulan benzersiz örneklerin tümünü korumanız gerekir Factory.

DÜZENLEME : -

Kesinlikle geçmelisiniz - Etkili Java - Madde # 1: Yapıcılara göre Statik fabrikaları düşünün . Bu kitaptan daha iyi bir açıklama alamazsınız.


1
Bu OP'nin zaten düşündüğü bir şey.
BGurung

OP'nin bazı endişelerini açıkça ele alan bağlantı için +1.
Robert Harvey

@RobertHarvey. Evet, bu kitap, bu tür konuların çoğu için en iyi kaynaktır. Ve aslında ilk öğe bu. :)
Rohit Jain

Etkili Java için +1, ben aslında, şimdi çantamda oturan kitap var :) Ancak ben sadece statik fabrika / statik yöntem ve yapıcı istisna dışında benzersizliği elde etmek için başka yollar merak vardı . Eğer yoksa, bunu kabul edeceğim.
Fıstık

@Fıstık. Elbette. Daha fazla bilgi almak için kazmak için en iyi kaynak budur.
Rohit Jain

5

Etkili Java'nın Mentions'ı çok fazla güvenilirlik katıyor gibi görünüyor, bu nedenle bu cevap şunlara dayanıyor:

  • Etkili Java Madde 8: Geçersiz kılmaya eşit olduğunda genel sözleşmeye uyun
  • Etkili Java Öğesi 9: Eşit değerleri geçersiz kıldığınızda her zaman hashCode'u geçersiz kıl
  • Etkili Java Öğe 15: Değiştirilebilirliği en aza indirin

Geri adım atıyorum ve neden bu isim nesnesinin birden fazla örneği olup olmadığını önemsediğinizi soruyorum.

Nadiren bu tür nesne havuzlaması yapmam gerekiyor. Tahminimce OP bunu yapıyor, böylece Namenesnelerini basitçe karşılaştırabiliyorlar ==. Veya Namea HashMapveya benzeri anahtarların içindeki nesneleri kullanın .

Eğer öyleyse, bu doğru bir şekilde uygulanmasıylaequals() çözülebilecek bir şeydir .

Şöyle ki:

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

Bir kez yapıldığında aşağıdakiler doğrudur:

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

Ben amacınızı tahmin ediyorum, ama sen kullanabilirsiniz bu şekilde Namekarma sınıfı vb haritalar ve onlar do not aynı örneği olmak zorunda.


Örnek, lütfen.
Robert Harvey

@RobertHarvey doğru uygulama örneği?
weston

Bir tane vermişsiniz gibi görünüyor. Ancak bunun statik bir fabrika yönteminde yalnızca Name özelliğini eşitlik açısından denetlemekten ne kadar farklı olduğu net değil.
Robert Harvey

1
@RobertHarvey Daha fazla açıklamaya çalıştım, statik fabrika gerektirmeyen eksiksiz bir alternatif öneriyorum ve her isim için birden fazla örneğe sahip olmak istemedikleri OP başlangıç ​​noktasına meydan okuyorum.
weston

Benzersiz nesneler istemek için geçerli bir neden, senkronize edilmiş bir bloğun nesneyi monitör olarak kullanmasını istemenizdir. Birbiri .equals () olan iki nesne çalışmaz.
Leigh Caldwell

3
  • Yap Namebir arayüz
  • NameFactoryBir yöntemle arayüz oluşturmaName getByName(String)
  • Bir uygulamasını oluşturun NameFactorybir ile Map<String,WeakReference<Name>>onun içinde
  • synchronizeharitada getByNameyeni isimler oluşturmadan önce yöntemin içindeki ada göreName
  • İsteğe bağlı olarak, uygulama uygulamanızda Namearabirimin statik özel uygulamasını kullanın .NameFactory

Bu yaklaşım aşağıdakileri yapmanızı sağlar:

  • NameHerhangi bir zamanda yalnızca tek bir örnek var,
  • Sınıfınızda Namegerekenden daha uzun süre yapıştığında sınıfınızda "Lingerer" bellek sızıntısı yok,
  • Arabirim kullandığınız için tasarım alay konusu nesnelerle test edilebilir.

Bir fabrika yöntemiyle bellek sızıntıları throwyoktur, bir nesneyi döndürmek yerine aynı ad varsa veya bir nullnesneyi döndürürseniz .
Robert Harvey

@RobertHarvey Gerçekten sızıntı değil, meşru nesneler (sözde "oyalanmak"). Basit bir statik harita değer nesnelerinin serbest bırakılmasını önlerken, zayıf referansların bir haritası onları diğer canlı referanslar var olduğu sürece hafızada tutacaktır.
dasblinkenlight

Ne demek istediğini anlıyorum. Bu, destructorkullanışlı olabileceği nadir örneklerden biri olabilir .
Robert Harvey

1
Çok karmaşık. @Weston cevabı gibi yapılabilir, eşittir geçersiz kılınabilir ve fabrikanın bir isim koleksiyonu tutmasını sağlayabilirsiniz.
Tulains Córdova

@ user1598390 Bir şey mümkün olduğunca basit olmalı, ancak daha basit olmamalıdır. Weston'un "çözümü" OP'nin sorununu çözmez (harita yoktur) ve bir ad koleksiyonu, daha uzun bir bellek sızıntısı oluşturur (evet, Java'da bellek sızıntıları vardır).
dasblinkenlight

1

yapıcıları özel yapmalı getNameInstance(String)ve aynı ada sahip bir nesne zaten mevcutsa (örneğin, statik bir sınıfa dayanabilir), bu başvuruyu döndürürsünüz, aksi takdirde özel kurucunuzu kullanarak yeni bir nesne oluşturup eklersiniz gibi yöntemler oluşturmalısınız. hashtable'a


Sorunun 3. paragrafında söylediklerimi tekrarladınız. Alternatif yolların peşindeydim.
Fıstık

Üzgünüm, sanırım neredeyse aynı anda cevap verdik, çünkü benimkinden önce cevapları kontrol ettim. Aslında, StackOverflown'da cevaplamaya çalıştım ve taşındı.
HericDenis

1

Takip etmeyi deneyin. Oluşturduğunuz her nesneyi takip etmelisiniz. Bu amaçla List kullanıyorum. Ve sınıf yapıcısını özel yaptım, böylece bir örnek oluşturmadan önce ön kontrol uygulanabilir

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

Bu Java değil mi? Sahte kod yazdınız mı? Veya başka bir dilde mi? Lütfen bunu açıkça belirtin.
Rohit Jain

C # gibi görünüyor. Akshay, başka koleksiyonlar öğrenmelisin List. Bu iyi bir seçim olacaktır Dictionary<string,UniqueName>.
weston
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.