C # 6.0'ın yeni boş koşullu operatörü Demeter Yasasına aykırı mı?


29

Demeter Kanunu şöyle der:

  • Her ünite diğer üniteler hakkında sadece sınırlı bilgiye sahip olmalıdır: sadece mevcut ünite ile ilgili "yakından" olan üniteler.
  • Her birim sadece arkadaşlarıyla konuşmalıdır; yabancılarla konuşma.
  • Sadece yakın arkadaşlarınızla konuşun.

C # 6.0 boş koşullu işleç adı verilen yeni bir işleç başlattı . IMHO, kodlamayı kolaylaştırır ve okunabilirliği artırır. Ancak, daha sonra birleştirilmiş kod yazmayı da kolaylaştırır, çünkü sınıf alanlarında gezinmek daha kolaydır, zaten boşluğu kontrol eder (gibi bir şey var x = A?.B?.C?.D?.E?.F?).

Bu yeni operatörün Demeter Yasasına aykırı olduğunu söylemek doğru mudur?


2
Bunun neden A?.B?.C?.D?.E?.F?ihlal edeceğine inanıyorsunuz ? - LoD kaç nokta hakkında değil ve çağıran yöntemin noktaları ihlal eden bir yapı hakkında böyle bir bilgiye sahip olmaması durumunda böyle bir çağrı mükemmel kabul edilebilir olacaktır. Bu tür kod olabilir LOD ihlal hepsi kullanımları söylemek yeterli değildir do LOD ihlal etmektedir.

14
" Demeter Yasası Bir Nokta Sayma Egzersizi Değildir " Okuma ? Bu kesin örneği tartışıyor.
outis

@outis: mükemmel okuma. Ben biçimindeki her kodun X.Y.Z.W.U"kanuna" aykırı olduğunu söylemiyorum . Ancak, kodla başa çıkma deneyimlerime göre, zamanın% 90'ı sadece çirkin eşleşmiş bir kod.
Arthur Rizzo

2
@ArthurRizzo, ancak boş koşullu operatörün LoD'ye karşı bir sorunu yok. Bu hatalı olan koddur. Operatör, insanın okumasını basitleştirmek için sadece bir araçtır. .?En fazla LOD ihlal +veya -yok.

1
RC Martin, saf veri sınıfları ile davranışsal sınıfları birbirinden ayırır. Eğer erişilen Özellikleri davranışsal sınıfın iç verilerini açığa pasajı kesinlikle Lod ihlal, ancak bu boş-koşullu operatör ile ilgisi yoktur. Her neyse, özellikler, koku olabilecek iç verileri göstermek zorunda değildir, ancak LoD'yi ihlal etmez. RC Martin'e göre şema kesinlikle saf veri sınıflarında geçerli olabilir.
Paul Kertscher

Yanıtlar:


44

Bu yeni operatörün Demeter Yasasına aykırı olduğunu söylemek doğru mudur?

Hayır *


* Boş koşullu işleç, dil ve .NET çerçevesi içinde bir araçtır. Herhangi bir aracın kötüye kullanma ve verilen bir uygulamanın sürekliliğine zarar verebilecek şekilde kullanılması yeteneği vardır.

Ama bir araç olması olabilir mutlaka anlamına gelmez istismar olmak vardır istismar, ne de aracı tutulabilir herhangi bir ilke (ler) ihlal ettiğini edilecek.

Demeter Yasası ve diğerleri, kodunuzu nasıl yazmanız gerektiğine dair kılavuz ilkelerdir . İnsanları hedef alıyor, araçları değil. Bu nedenle, C # 6.0 dilinin içinde yeni bir araç olması, kodunuzu nasıl yazmanız ve yapılandırmanız gerektiği ile ilgili değildir .

Herhangi bir yeni araçla, kodunuzu korumayı bırakan adam şiddetli bir psikopat olacaksa ... olarak değerlendirmeniz gerekir . Yine, bunun, kullanılan araçlar hakkında değil, kodu yazan kişiye rehberlik ettiğini unutmayın.


foo = new FiveDMatrix(); foo.get(0).get(0).get(0).get(0).set(0,1);iyi olurdu (ve bundan daha kötüsü olmaz foo[0][0][0][0][0] = 1) ... ve bunun LoD'u ihlal etmediği birçok durum.

@MichaelT Bu boyutluluğun matrislerine girmeye başladığınızda, endeksleri bir vektör / tuple / dizinin kendisi olarak ele almak ve matris sınıfının içindekilerin verinin gerçekte nasıl saklandığı konusunda endişelenmesine izin vermek daha kolay olacak gibi görünüyor. (Şimdi, bunun hakkında düşündüğüm kadarıyla, en azından kapsülleme ile ilgili olduğu gibi, Demeter Yasası'nın bir uygulamasıdır.)
JAB,

(Ve tabii ki, bu tür bir uygulama çok boyutlu dilimleme yapmayı ve bazı gerçekten güçlü matris araçlarına sahip olmayı kolaylaştırıyor.)
JAB

1
@ JAB Sadece bir örnek bulmaya çalışıyordum. Daha iyisi, muhtemelen Dom file = prase("some.xml"); file.get(tag1).getChild().get(tag2).getChild() ...bir aptal kodun yapısını işlemden geçirme sorunudur. Bu yabancı değil ... sadece aptal. Bu tür yapılarda bu .?hale çok faydalı oluyor .

10

Sırala.

Yalnızca bir erişim ( a?.Foo) yapıyorsanız , buna eşdeğerdir:

a == null ? null : a.Foo

çoğu insanın kabul edeceği şey, Demeter Yasası'nın ihlali değildir. Bu noktada, okunabilirliği artırmak için sadece sözdizimsel şeker.

Bundan daha fazlası olan ve muhtemelen Demeter Yasasını ihlal edecek olan bu özellik, bu tür bir kullanımı teşvik etme eğilimindedir. Yukarıdaki "iyi" kullanımın tek başına dilde bu tür bir değişikliği garanti altına almak için yeterli olmadığını söyleyebilirim, bu yüzden daha az açıkça kullanılmasını desteklemek için yapılmasını bekliyorum.

Bununla birlikte, Demeter Yasasının kendi başına bir yasa olmadığını, daha çok bir kılavuz olduğunu hatırlamaya değer. Bir sürü kod onu ihlal ediyor ve iyi çalışıyor. Bazen, tasarımın veya kodun sadeliği, Demeter Yasasını ihlal ederek ortaya çıkan riskten daha değerlidir.


Bundan başka bir şey mutlaka LoD bozmaz, örneğin oluşturucu paterni
jk.

@Telastyn: bahsediyoruz yeni dil sözdizimi hakkında yaptığı destek yöntemi çağrıları: a?.Func1(x)?.Func2(y) boş kaynaştırma operatörü başka bir şeydir.
Ben Voigt

@BenVoigt - ah, sadece tarlalar, mülkler ve indeksleyiciler ile çalıştığını gösteren makaleden çıkıyordum. MSVS2015 ile test etmek için kullanışlı değildi. Haklısın.
Telastyn

1
a? .Foo == null değerine eşit değil mi? null: a.Foo. İlki bir kere değerlendirir, ikincisi iki kere değerlendirir. Bir yineleyici olsaydı önemli olabilirdi.
Loren Pechtel

9

Hayır. Hem operatörü kendi başına hem de bunun için sahip olduğunuz ağır zincirleme kullanımı düşünelim.

Kendi başına .?A, sol değer olan sınıfın aynı miktarda bilgisine ve metodun getirdiği türden .A != null, yani viz'e bağlıdır. Bu konuda bir bilmesi gereken Aözelliğin bulunup bulunmadığını ve mukayese edilebilir bir değer döndürür null.

Sadece yazılan mülklerin yapılması durumunda Demeter kanununu ihlal ettiğini iddia edebiliriz. ASomut bir tür olmaya zorlanmadık bile (değeri türetilmiş olabilir). Buradaki bağlantı minimumdur.

Şimdi düşünelim var x = A?.B?.C?.D?.E?.F.

Bu, Anull olabilecek ya da bir Bözelliğe sahip olması gereken ya da bir özelliğe sahip olması gerektiği anlamına gelir , bu özellik null değerinde boş olan ya da bir Cözelliğe Esahip olabilir. bir Fözelliğe sahip olabilir .

Başka bir deyişle, bunu statik olarak yazılmış bir dille yapıyor olmamız veya yazma gevşekse döndürülebilen türlere bir sınırlama uygulamamız gerekir. C # çoğu durumda statik yazmayı kullanır, bu yüzden hiçbir şeyi değiştiremedik.

Eğer öyleyse, aşağıdaki kod yasaları da ihlal eder:

ExplicitType x;
var b = A.B;
if (b == null)
  x = null;
else
{
  var c = b.C;
  if (c == null)
    x = null;
  else
  {
    var d = c.D;
    if (d == null)
      x = null;
    else
    {
      var e = d.E;
      if (e == null)
        x = null;
      else
        x = e.F;
    }
  }
}

Bu tamamen aynı . Farklı elemanların eşleştirmesini kullanan bu kodun, tüm bağlantı zinciri hakkında "bilmesi" gerekir, ancak her birimin iyi tanımlanmış bir birleşimine sahip olduğu için Demeter Yasasını ihlal etmeyen kodu kullanıyor sonraki.


3
+1 Yeni operatör tanımladığınız acı tarif için sadece sözdizimsel bir şeker.
Ross Patterson,

1
Bir dev bir şeye benzeyen bir kod yazarsa, bir şeyin doğru olmadığını fark etmenin daha kolay olduğunu düşünüyorum. Operatörün% 100 syntatik şeker olduğunu biliyorum, ama yine de insanların var x = A?.B?.C?.D?.E?.Fsonunda aynı olsalar bile, diğerlerinden farklı bir şeyler yazma eğiliminde olduklarını düşünüyorum .
Arthur Rizzo

2
Bir şeyin doğru olmadığını fark etmek daha kolaydır, A?.B?.C?.D?.E?.Fçünkü yanlış olabilecek daha az şey vardır; ya Fbu yoldan geçmeye çalışmalıyız , ya da yapmamalıyız, uzun formun içinde hatalar olabilir, bunun yanı sıra yapılacak yanlış şey de olabilirdi.
Jon Hanna,

@ArthurRizzo Ancak, yukarıdaki kod türünü LoD ihlalleriyle ilişkilendirirseniz, boş denetlemenin gerekmediği durumlarda onları kaçırmanız kolaydır ve sadece yapabilirsiniz A.B.C.D. İlgisiz bir ayrıntıya dayanan iki farklı şeyden ziyade tek bir şeye sahip olmak (zincirleme mülk erişimi) çok daha basittir (sıfır-kontrol)
Ben Aaronson

5

Davranışların kapsanması veya verilerin tutulması amacıyla nesne oluşturulabilir ve dış kodla paylaşılması veya yaratıcısı tarafından özel olarak tutulması amacıyla nesneler oluşturulabilir.

Kapsayıcı davranış amacıyla (paylaşılmış olsun veya olmasın) veya dış kod ile paylaşılmış olmak için (davranış veya verileri kapsüllemek olsun olmasın) oluşturulan nesnelere genellikle yüzey ara yüzlerinden erişilmelidir. Bununla birlikte, veri tutma nesneleri yalnızca yaratıcısı tarafından kullanılmak üzere yaratıldığında, “derin” erişimden kaçınmanın normal Demeter Yasası nedenleri geçerli değildir. Nesnede veri depolayan veya işleyen bir sınıfın parçası, başka bir kodun ayarlanmasını gerektirecek şekilde değiştirilirse, bu tür kodların güncellenmesini garanti etmek mümkün olacaktır - çünkü yukarıda belirtildiği gibi, nesne için yaratılmıştır. tek bir sınıfın özel kullanımı.

Ben düşünürken? Operatör belki de daha iyi tasarlanmış olabilirdi, nesnelerin yuvalanmış veri yapılarını kullandığı ve operatörün Demeter Yasası tarafından ifade edilen prensipleri ihlal etmeyecek birçok kullanım senaryosuna sahip olduğu yeterli durumlar var. LoD'ı ihlal etmek için kullanılabileceği gerçeği, "." Den daha kötü olmadığı için operatöre karşı bir argüman olarak görülmemelidir. Bu konuda operatör.


Demeter Yasası neden veri tutanlar için geçerli değildir?
Telastyn,

2
@Telastyn: LoD'nin amacı, bir kod parçası başka bir şeyin manipüle edebileceği veya ilgilenebileceği iç nesnelere erişirse ortaya çıkabilecek sorunlardan kaçınmaktır . Eğer evrendeki başka hiçbir şey iç nesnelerin durumunu değiştiremez veya değiştiremezse, bu tür sorunlara karşı korunmaya gerek yoktur.
supercat,

Katıldığımdan emin değilim. Başka şeyler verileri değiştirmeyi umursamıyor olabilir, içerilen nesneye bir yolla bağlanıyorsunuz (temel olarak üç bağlantı noktası - iki nesne ve onların ilişkisi). Bazen bu eşleşme önemli bir şey olmayacak, ama yine de bana kokulu geliyor.
Telastyn,

@Telastyn: Yollarla ilgili düşünceleriniz iyi, ama sanırım amacım gayet iyi. Bir nesneye birden çok yolla erişmek, bu yollar arasında eşleşme oluşturur. Bazı erişimler sığ yoldan geliyorsa, derin yoldan erişim de istenmeyen bağlantılara neden olabilir. Ancak, tüm erişim belirli bir derin yoldan geçiyorsa, o derin yolun birleşmesi için hiçbir şey olmayacaktır.
supercat

@Telastyn Derinlemesine veri elde etmek için veri yapılarını geçmek tamamen iyidir. İç içe yöntem çağrıları ile aynı değildir. Bazen bir veri yapısını ve nasıl iç içe geçtiğini bilmek zorunda
kalırsınız
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.