Yaratma sırasında değişken olan ancak daha sonra değiştirilemez olan üyelerle sınıf


22

Nesnelerin bir koleksiyonunu oluşturan bir algoritmaya sahibim. Bu nesneler yaratma sırasında değişkendir, çünkü çok az ile başlarlar, ancak algoritma içindeki farklı yerlerde verilerle doldurulurlar.

Algoritma tamamlandıktan sonra nesneler asla değiştirilmemelidir - ancak yazılımın diğer bölümleri tarafından tüketilirler.

Bu senaryolarda, aşağıda açıklandığı gibi sınıfın iki versiyonunun olması iyi bir uygulama olarak kabul edilir mi?

  • Değişken bir algoritma tarafından oluşturulur, sonra
  • Algoritmanın tamamlanmasından sonra, veriler döndürülen değişmez nesnelere kopyalanır.

3
Sorunuz / sorunuzun ne olduğunu açıklığa kavuşturmak için sorunuzu düzenleyebilir misiniz?
Simon Bergot

Yanıtlar:


46

Oluşturucu desenini belki de kullanabilirsiniz . Gerekli verileri toplamak amacıyla ayrı bir 'oluşturucu' nesne kullanır ve tüm veriler toplandığında gerçek nesneyi oluşturur. Oluşturulan nesne değişmez olabilir.


Çözümünüz benim gereksinimlerim için doğru olanıydı (hepsi belirtilmedi). Soruşturma sırasında iade edilen nesnelerin hepsi aynı özelliklere sahip değildir. Oluşturucu sınıfın birçok null alanı vardır ve veriler oluşturulduğunda, 3 farklı sınıftan hangisinin üretileceğini seçer: bunlar kalıtımsal olarak birbirleriyle ilgilidir.
Paul Richards,

2
@Paul Bu durumda, bu cevap sorununuzu çözdüyse, kabul edildi olarak işaretlemelisiniz.
Riking,

24

Bunu başarmanın basit bir yolu, birinin özellikleri okumasını ve sadece salt okunur yöntemleri çağırmasını sağlayan bir arayüze ve o sınıfı yazmanıza izin veren bu arayüzü uygulayan bir sınıfa sahip olmaktır.

Onu yaratan yönteminiz, öncekilerle ilgilenir ve daha sonra etkileşime girmesi için salt okunur bir arayüz sağlayan ikinciyi döndürür. Bu, kopyalamaya gerek duymaz ve arayan kişiye, yaratıcının aksine kolayca kullanmak istediğiniz davranışları kolayca ayarlamanıza olanak tanır.

Bu örneği ele alalım:

public interface IPerson 
{
    public String FirstName 
    {
        get;
    }

    public String LastName 
    {
        get;
    }
} 

public class PersonImpl : IPerson 
{
    private String firstName, lastName;

    public String FirstName 
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public String LastName 
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

class Factory 
{
    public IPerson MakePerson() 
    {
        PersonImpl person = new PersonImpl();
        person.FirstName = 'Joe';
        person.LastName = 'Schmoe';
        return person;
    }
}

Bu yaklaşımın tek dezavantajı, onu uygulayıcı sınıfa basitçe aktarmasıdır. Güvenlik meselesiyse, bu yaklaşımı kullanmak yeterli değildir. Bunun için bir geçici çözüm , arayanın çalıştığı ve iç nesneye erişemediği bir arayüz sunan değişken sınıfı sarmak için bir cephe sınıfı oluşturabilmenizdir .

Bu sayede oyuncu seçimi bile size yardımcı olmaz. Her ikisi de aynı salt okunur arayüzden türetilebilir, ancak döndürülen nesnenin dökülmesi yalnızca size sarılmış değiştirilebilir sınıfın temel durumunu değiştirmediğinden değiştirilemez olan Facade sınıfını verir.

Bunun, değişmez bir nesnenin bir kez ve herkes için kurucu aracılığıyla yapıldığı tipik eğilimi takip etmediğinden bahsetmeye değer. Anlaşılır, birçok parametreyle uğraşmak zorunda kalabilirsiniz, ancak kendinize tüm bu parametrelerin önceden tanımlanması gerekip gerekmediğini veya bazılarının daha sonra verilip verilmeyeceğini sormalısınız. Bu durumda, sadece gerekli parametreleri olan basit bir kurucu kullanılmalıdır. Başka bir deyişle, programınızdaki başka bir sorunu ele alıyorsa bu deseni kullanmayın.


1
"Salt okunur" bir nesneyi döndürerek güvenlik daha iyi olmaz, çünkü nesneyi alan kod, yansımayı kullanarak nesneyi yine de değiştirebilir. Bir dize bile yansıma kullanılarak değiştirilebilir (kopyalanamaz, yerinde değiştirilebilir).
MTilsted

Güvenlik sorunu özenle özel bir sınıfla çözülebilir
Esben Skov Pedersen

@Esben: Hala MS07-052 ile mücadele etmek zorundasınız : Kod çalıştırma kod çalıştırma ile sonuçlanır . Kodunuz, kodlarıyla aynı güvenlik bağlamında çalışıyor, bu nedenle sadece bir hata ayıklayıcı ekleyebilir ve ne isterlerse yapabilirler.
Kevin,

Kevin1 tüm kapsülleme hakkında söyleyebilirsiniz. Yansımaya karşı korumaya çalışmıyorum.
Esben Skov Pedersen,

1
"Güvenlik" kelimesini kullanmanın sorunu, derhal birisinin daha güvenli bir seçenek olduğunu söylediğim şeyin maksimum güvenlik ve en iyi uygulamaya eşdeğer olduğunu varsaymasıdır. Ben de asla söylemedim. Kütüphaneyi birisinin kullanması için dağıtmıyorsanız, şaşırtmadıkça (ve bazen de şaşkınken bile) güvenliği güvence altına almayı unutabilirsiniz. Ancak, içinde bulunan içsel nesneyi almak için yansıma kullanarak geri gönderilen bir cephe nesnesine müdahale ederseniz, tam olarak kullanılması gerektiği gibi kütüphaneyi kullanmayacağınız konusunda hemfikir olduğumuzu düşünüyorum.
Neil,

8

Sen @JacquesB söylediği gibi Oluşturucu desen kullanmak veya alternatif seninkilerden bu nesneler aslında neden düşünebiliriz sahip oluşturulması sırasında değişken olması?

Başka bir deyişle, gerekli tüm değerleri kurucuya aktarmak ve bir seferde örnekler yaratmak yerine neden onları yaratma sürecinin zamana yayılması gerekiyor?

Çünkü Oluşturucu yanlış sorun için iyi bir çözüm olabilir.

Sorun, 10 parametre uzunluğundaki bir kurucu ile bitiyorsanız ve nesneyi azar azar oluşturarak hafifletmek istiyorsanız, tasarımın berbat olduğunu ve bu 10 değerin "olması gerektiğini gösterebilir" torbalanmış "/ birkaç nesneye gruplanmış ... veya ana nesne birkaç küçük parçaya bölünmüş ...

Bu durumda - tamamen değişmezliğe sadık kalın, tasarımı geliştirin.


Kodun veriyi almak için birden fazla veritabanı sorgusu yaptığı için hepsini bir kerede oluşturmak zor olurdu; farklı tablolardaki ve farklı veritabanlarındaki verileri karşılaştırır.
Paul Richards,
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.