Bir nesneyi düzgün şekilde başlatamayabilecek kurucular nasıl yazılır


12

Bazen başarısız olabilecek bir yapıcı yazmanız gerekir. Örneğin, bir dosya yoluna sahip bir nesneyi başlatmak istiyorum, örneğin

obj = new Object("/home/user/foo_file")

Yol uygun bir dosyaya işaret ettiği sürece her şey yolunda. Ancak dize geçerli bir yol değilse işler kırılmalıdır. Ama nasıl?

Yapabilirdin:

  1. istisna atmak
  2. return null nesnesi (programlama diliniz kurucuların değerleri döndürmesine izin veriyorsa)
  3. geçerli bir nesne döndürme ancak yolunun düzgün ayarlanmadığını belirten bir işaretle (ugh)
  4. diğerleri?

Çeşitli programlama dillerinin "en iyi uygulamalarının" bunu farklı uygulayacağını varsayıyorum. Örneğin ObjC'nin (2) tercih ettiğini düşünüyorum. Ancak (2), C ++ 'da, yapıcıların bir dönüş türü olarak geçersiz olması gereken yerlerde uygulanması imkansızdır. Bu durumda (1) 'i kullanıyorum.

Programlama dilinizde bu sorunu nasıl ele alacağınızı gösterebilir ve nedenini açıklayabilirsiniz?


1
Java'daki istisnalar bunu ele almanın bir yoludur.
Mahmoud Hossam

C ++ kurucuları geri dönmez void- bir nesne döndürürler.
gablin

6
@gablin: Aslında bu kesinlikle doğru değil. hafızayı ayırmak için newçağırır operator new, sonra onu doldurmak için yapıcıdır. Yapıcı hiçbir şey döndürmez ve newaldığı işaretçiyi döndürür operator new. voidYine de "hiçbir şey döndürmezse" ifadesi "döndürür " anlamına gelir .
Jon Purdy

@Jon Purdy: Hm, kulağa makul geliyor. İyi karar.
gablin

Yanıtlar:


8

Kirli işi yapmak için bir kurucuya güvenmek asla iyi değildir. Ayrıca, başka bir programcıya, açık bir belge belirtilmedikçe (ve sınıfın kullanıcısı bunu okumuş veya söylememişse) kurucuda iş yapıp yapamayacağı da açık değildir.

Örneğin (C # 'da):

public Sprite
{
    public Sprite(string filename)
    {
    }
}

Kullanıcı dosyayı hemen yüklemek istemezse ne olur? Ya dosyanın isteğe bağlı önbelleğe alınmasını istiyorlarsa? Yapamazlar. Bir koyma düşünebilir bool loadFilekurucusundaki argüman, ama şimdi olduğu gibi o zaman bu bu pis bir hale getirir hala bir ihtiyaç Load()dosyası yüklemek için bir yöntem.

Mevcut senaryo göz önüne alındığında, bunu yapmak için sınıf kullanıcıları için daha esnek ve açık olacaktır:

Sprite sprite = new Sprite();
sprite.Load("mario.png");

Veya alternatif olarak (kaynak gibi bir şey için):

Sprite sprite = new Sprite();
sprite.Source = "mario.png";
sprite.Cache();

// On demand caching of file contents.
public void Cache()
{
     if (image == null)
     {
         try
         {
             image = new Image.FromFile(Source);
         }
         catch(...)
         {
         }
     }
}

yük (..) başarısız olursa, tamamen işe yaramaz bir nesnemiz var. Sprite olmadan sprite istediğimden emin değilim ... Ama soru gerçek sorudan daha
kutsal bir

7

Java'da, istisnalar kullanabilir veya null döndürmenize izin veren fabrika modelini kullanabilirsiniz.

Scala'da fabrika yönteminden bir Seçenek [Foo] döndürebilirsiniz. Bu Java'da da işe yarayacaktır, ancak daha hantal olacaktır.


.NET dillerinde Özel Durumlar veya fabrika kullanma.
Beth Whitezel

3

Bir istisna atın.

Geri verebilmeniz için null değerinin kontrol edilmesi gerekiyor (ve kontrol edilmeyecek)

İşaretli istisnalar bunun içindir. Başarısız olabileceğini biliyorsun. Arayanlar bunun üstesinden gelmek zorundadır.


3

Olarak C ++ , yapıcılar sınıfının / initialize üye oluşturmak için kullanılır.

Bu sorunun doğru cevabı yok . Ancak şimdiye kadar gözlemlediğim şey, çoğu zaman bu şeyleri nasıl ele almanız gerektiğini seçen müşteri (veya API'nızı kullanacak kişi) olmasıdır.

Bazen tüm kaynakları yapıcı üzerindeki nesne kudreti ihtiyacı tahsis ve isteyebilir atmak emin yaratılması her zaman başarılı olur şey (nesnenin oluşturulmasını iptal) başarısız olursa bir istisna veya yapıcı o hiçbirini yapmak ve yaptırmak , bazı üye işlevlerinin yapılması için bu görevleri bırakarak.

Davranışı seçmek size kalmışsa, istisnalar hataları işlemek için varsayılan C ++ yoludur ve bunları yapabildiğiniz zaman kullanmalısınız.


1

Nesneyi hiçbir parametre olmadan veya yalnızca hiçbir zaman başarısız olmayacağından emin olan parametrelerle başlatabilir ve daha sonra, bir istisnayı güvenli bir şekilde atabileceğiniz veya istediğiniz her şeyi yapabileceğiniz bir başlatma işlevi veya yöntemi kullanırsınız.


6
Daha fazla başlatma gerektiren kullanılamaz bir nesneyi döndürmek en kötü seçim olduğunu düşünüyorum. Artık, sınıf her kullanıldığında kopyalanması veya yeni bir yönteme katılması gereken çok satırlı bir parçanız var. Nesne inşa edilemiyorsa kurucuya tüm işi yapabilir ve bir istisna atabilirsiniz.
kevin cline

2
@kevin: Nesneye bağlı. Başarısızlıklar muhtemelen dış kaynaklardan kaynaklanacaktır, bu nedenle işletme niyeti kaydetmek isteyebilir (örneğin dosya adı), ancak tam olarak başlatılması için tekrarlanan girişimlere izin verebilir. Bir değer nesnesi için muhtemelen temeldeki hatayı yakalayabilecek bir hatayı bildirmeye eğilimliydim, bu yüzden muhtemelen (sarılmış?) Bir istisna atar.
Dave

-4

Herhangi bir sınıfı veya listeyi yapıcıda başlatmamayı tercih ederim. İhtiyacınız olduğunda bir sınıfı veya listeyi başlatın. Örneğin.

public class Test
{
    List<Employee> test = null;
}

Bunu yapma

public class Test
{
    List<Employee> test = null;

    public Test()
    {
        test = new List<Employee>();
    }
}

Bunun yerine gerektiğinde başlat Eg.

public class Test
{
    List<Employee> emp = null;

    public Test()
    { 
    }

    public void SomeFunction()
    {
         emp = new List<Employee>();
    }
}

1
Bu kötü bir tavsiye. Nesnelerin geçersiz durumda olmasına izin vermemelisiniz. Yapıcı bunun içindir. Karmaşık mantığa ihtiyacınız varsa, fabrika modelini kullanın.
AlexFoxGill

1
Yapıcılar sınıf değişmezleri kurmak için orada, örnek kod hiç iddia etmek yardımcı olmaz.
Niall
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.