Nesne başlatıcılarla kurucu ve akışkan arayüzleri kullanmanın bir anlamı var mı?


10

Java ve C # 'da, bir kurucuyu parametrelerle tanımlayarak, nesneyi oluşturduktan sonra her özelliği tanımlayarak veya oluşturucu / akışkan arabirimi desenini kullanarak başlatma sırasında ayarlanabilen özelliklere sahip bir nesne oluşturabilirsiniz. Bununla birlikte, C # 3, oluşturucu modelinin büyük ölçüde işe yaramadığı anlamına gelen nesne ve toplama başlatıcıları tanıttı. Başlatıcıları olmayan bir dilde, bir inşaatçı uygulanabilir ve daha sonra şu şekilde kullanılabilir:

Vehicle v = new Vehicle.Builder()
                    .manufacturer("Toyota")
                    .model("Camry")
                    .year(1997)
                    .colour(CarColours.Red)
                    .addSpecialFeature(new Feature.CDPlayer())
                    .addSpecialFeature(new Feature.SeatWarmer(4))
                    .build();

Tersine, C # 'da şunlar yazabilir:

var vehicle = new Vehicle {
                Manufacturer = "Toyota",
                Model = "Camry",
                Year = 1997,
                Colour = CarColours.Red,
                SpecialFeatures = new List<SpecialFeature> {
                    new Feature.CDPlayer(),
                    new Feature.SeatWarmer { Seats = 4 }
                }
              }

... önceki örnekte görüldüğü gibi bir inşaatçı ihtiyacını ortadan kaldırır.

Bu örneklere dayanarak, geliştiriciler C # 'da hala yararlı mıdır, yoksa tamamen başlatıcılar tarafından değiştirilmiş mi?


are builders usefulneden bu tür soruları görmeye devam ediyorum? Bir Builder bir tasarım modelidir - elbette, bir dil özelliği olarak ortaya çıkabilir, ancak günün sonunda sadece bir tasarım deseni. Bir tasarım deseni "yanlış" olamaz . Kullanım durumunuzu yerine getirebilir veya etmeyebilir, ancak bu tüm kalıbı yanlış yapmaz, sadece uygulanmasıdır. Günün sonunda tasarım desenlerinin belirli sorunları çözdüğünü unutmayın - sorunla karşılaşmazsanız neden çözmeyi denesiniz?
VLAZ

@vlaz Yapımcıların yanlış olduğunu söylemiyorum - aslında sorum, başlatıcılar verilen inşaatçılar için herhangi bir kullanım örneği olup olmadığını sormaktı. Açıkçası, insanlar bir inşaatçının özel alanları ayarlamak için hala yararlı olduğunu yanıtladılar ve bu da sorumu yanıtladı.
svbnet

3
@vlaz Açıklığa kavuşturmak için: Başlatıcıların büyük ölçüde , bir iç yapıcı sınıfı yazmanın "geleneksel" kurucu / akışkan arayüz deseninin yerini aldığını, daha sonra o sınıfın içinde o ana sınıfın yeni bir örneğini oluşturan zincirleme ayarlayıcı yöntemlerini yazdığını söylüyorum. Ben am değil olan başlatıcı desen oluşturucu o özgü yerini olduğunu söyleyerek; Başlatıcıların geliştiricileri bu belirli oluşturucu modelini uygulamak zorunda bıraktıklarını , yanıtlarda belirtilen kullanım örneklerine kaydettiklerini ve bu da oluşturucu modelini işe yaramaz hale getirmediklerini söylüyorum .
svbnet

5
@vlaz Endişenizi anlamıyorum. "Bir tasarım modelinin yararlı olmadığını söylüyordunuz" - hayır, Joe bir tasarım modelinin yararlı olup olmadığını soruyordu . Bu nasıl kötü, yanlış veya yanlış bir soru? Sence cevap açık mı? Cevabın açık olduğunu sanmıyorum; bu benim için iyi bir soru gibi görünüyor.
Tanner Swett

2
@vlaz, singleton ve servis bulucu kalıpları yanlış. Ergo tasarım desenleri yanlış olabilir.
David Arno

Yanıtlar:


12

@ User248215 tarafından değinildiği gibi asıl mesele değişmezliktir. C # 'da bir oluşturucu kullanmanızın nedeni, ayarlanabilir özelliklerin gösterilmesine gerek kalmadan bir başlatıcısının açıklığını korumaktır. Bu bir kapsülleme sorunu değil, bu yüzden kendi cevabımı yazdım. Bir ayarlayıcıyı çağırmak, ayarlayıcının gerçekte ne yaptığını ima etmediği veya sizi uygulamasına bağlayamadığı için kapsülleme oldukça diktir.

C # 8.0'ın bir sonraki sürümünde, withdeğişmez nesnelerin kurucuları yazmaya gerek kalmadan net ve kısaca başlatılmasını sağlayacak bir anahtar kelime getirmesi muhtemeldir .

Başlatıcıların aksine, inşaatçılar ile yapabileceğiniz bir başka ilginç şey, denilen yöntem sırasına bağlı olarak farklı nesne türlerine neden olabilmeleridir.

Örneğin

value.Match()
    .Case((DateTime d) => Console.WriteLine($"{d: yyyy-mm-dd}"))
    .Case((double d) => Console.WriteLine(Math.Round(d, 4));
    // void

var str = value.Match()
    .Case((DateTime d) => $"{d: yyyy-mm-dd}")
    .Case((double d) => Math.Round(d, 4).ToString())
    .ResultOrDefault(string.Empty);
    // string

Yukarıdaki örneği açıklığa kavuşturmak için, vakaları belirterek bir "eşleşme" oluşturmak için oluşturucu desenini kullanan bir desen eşleştirme kütüphanesidir. Vakalar, Casebir fonksiyondan geçen yöntem çağrılarak eklenir . Eğer valueişlevin parametre türüne atanabilir olan o çağrılır. Sen bulabilirsiniz GitHub'dan tam kaynak kodu XML yorumlarının düz metin olarak okunması zor olduğundan, ve burada bir bağlantıdır belgelere inşa SandCastle (bkz Açıklamalar bölümü)


Bir IEnumerable<Func<T, TResult>>üye kullanarak bunun bir nesne başlatıcısı nasıl yapılamaz göremiyorum .
Caleth

@Caleth Aslında denediğim bir şeydi ama bu yaklaşımla ilgili bazı sorunlar var. Koşullu hükümlere izin verilmez (bağlantılı belgelerde gösterilmez, ancak kullanılır ve gösterilir) ve tür çıkarımına izin vermez TResult. Nihayetinde tip çıkarımı bununla çok ilgiliydi. Ayrıca bir kontrol yapısı gibi görünmesini istedim. Ayrıca mutasyona izin vereceği için bir başlatıcı kullanmak istemedim.
Aluan Haddad

12

Nesne başlatıcıları, özelliklerin çağrı kodu tarafından erişilebilir olmasını gerektirir. Yuvalanmış inşaatçılar sınıfın özel üyelerine erişebilir.

VehicleDeğişmez yapmak istiyorsanız (tüm ayarlayıcıları özel yaparak), iç içe geçmiş oluşturucu özel değişkenleri ayarlamak için kullanılabilir.


0

Hepsi farklı amaçlara hizmet !!!

Yapıcılarreadonly özel ve korunan üyelerin yanı sıra işaretli alanları başlatabilir . Ancak, bir kurucu içinde yapabileceklerinizle sınırlısınız; thisÖrneğin, herhangi bir harici yönteme geçmekten kaçınmalısınız ve sanal üyeleri çağırmaktan kaçınmalısınız çünkü bunlar henüz kendisini oluşturmayan türetilmiş bir sınıf bağlamında yürütülebilir. Ayrıca, yapıcıların çalışacağı garanti edilir (arayan çok alışılmadık bir şey yapmazsa), bu nedenle yapıcıdaki alanları ayarlarsanız, sınıfın geri kalanındaki kod bu alanların boş olmayacağını varsayabilir.

Başlatıcılar inşaattan sonra çalışır. Yalnızca kamu mülklerini aramanıza izin verir; özel ve / veya salt okunur alanlar ayarlanamaz. Geleneksel olarak, bir mülk belirleme eylemi oldukça sınırlı olmalıdır, örneğin idempotent olmalı ve sınırlı yan etkileri olmalıdır.

Oluşturucu yöntemleri gerçek yöntemlerdir ve bu nedenle birden fazla argümana izin verir ve kural olarak nesne oluşturma da dahil olmak üzere yan etkiler olabilir. Salt okunur alanları ayarlayamasalar da, hemen hemen başka bir şey yapabilirler. Ayrıca, yöntemler genişletme yöntemleri olarak uygulanabilir (hemen hemen tüm LINQ işlevselliği gibi).

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.