Özelliklerin anlamı nedir?


11

İşte özellikler ve karşı argümanlarım için bazı argümanlar:

Alıcı ve ayarlayıcı yöntemleri yazmaktan daha kolay

Getter ve setter yöntemi çiftleri bir kod kokusudur. Bunları yazmayı kolaylaştırmak, Scantron formunu kullanarak ve tüm 'C'leri doldurarak bir matematik testinde başarısız olmayı kolaylaştırmak gibidir. Kalıcılık için yalnızca durum içeren nesneler alıcılar / ayarlayıcılar kullanmamalı ve kalıcılık anında değişmez nesneler oluşturmalıdır.

Bir nesnenin tüketicisi için önemli olan, nasıl yaptığı değil, yaptığı şeydir. Davranışı yaptığı şeydir; onun durumu nasıl yapıyor. Kendinizi bir nesnenin durumu hakkında önemsiyorsanız (kalıcılık hariç, bu aynı zamanda OO'yu da kırıyorsa), sadece OOP yapmazsınız ve avantajlarını kaybedersiniz.

Tüketicilere kabaca bir performans göstergesi veriyorlar

Bu, herhangi bir mülk için gelecekte değişebilecek bir şeydir. 1.0 sürümünde, PropertyX'e erişmenin yalnızca bir alan döndürdüğünü varsayalım. Sürüm 1.5'te, alan null ise, PropertyX yeni bir null nesne oluşturmak için Null Nesne desenini kullanır. Sürüm 2.0, alan PropertyX içindeki getter yöntemi ile daha da doğrulanıyor.

Mülk gittikçe karmaşıklaştıkça, bir mülkü kullanmanın performans göstergesi gittikçe daha az doğru görünüyor.

Kamusal alanlardan daha iyidirler

Bu doğru. Ama yöntemler de öyle.

Bir nesnenin yöntemden çok farklı bir yönünü temsil ederler ve nesnenin tüm tüketicileri bunu önemsemelidir

Yukarıdaki ifadelerin her ikisinin de doğru olduğundan emin misiniz?

Yazmak daha kolay, adamım

Elbette, yazmak yazmaktan myObject.Lengthdaha kolaydır myObject.Length(), ancak bu biraz sözdizimsel şekerle düzeltilemez mi?


Neden özellikler yerine yöntemler kullanılmalı?

  • Performans garantisi yoktur. Yöntem daha karmaşık hale gelse bile API doğru kalacaktır. Tüketici, performans sorunlarıyla karşılaşıyorsa ve API kelimesine güvenmiyorsa kodunu profille oluşturması gerekir.

  • Tüketicinin düşünmesi için daha az. Bu tesiste bir pasör var mı? Emin bir yöntem değildir.

  • Tüketici uygun bir OOP zihniyetinden düşünüyor. Bir API'nin tüketicisi olarak, bir nesnenin davranışıyla etkileşime girmekle ilgileniyorum. API'de özellikler gördüğümde, duruma çok benziyor. Aslında, özellikler çok fazla işliyorsa, özellik olmamalı, hatta gerçekte bir API ARE'deki özellikler tüketicilere göründüğü haliyle.

  • API programcısı dönüş değerlerine sahip yöntemler hakkında daha derin düşünecek ve mümkünse bu yöntemlerde nesnenin durumunu değiştirmekten kaçınacaktır. Komutların sorgulardan ayrılması mümkün olan her yerde uygulanmalıdır.


Size soruyorum, neden yöntemler yerine özellikleri kullanalım? Üzerindeki noktaların çoğu MSDN kod içinde ve kendileri kokuyor, ve ya özellik ve yöntemlerle ait değil.

(Bu düşünceler CQS'yi düşündükten sonra bana geldi.)


5
+1. Özellikler, alanların sözdizimine sahip yöntemlerdir ve bu mantıklı değildir.
Nemanja Trifunovic

23
@Nemanja Trifunovic: type GetFoo() void SetFoo()On bin kez yazdıysanız, mantıklı geliyor . Tüm zaman C # kod yazma hiç bir özellik tarafından karıştırılmamış.
Ed

23
Zaten kararını vermişsin gibi geliyor bana. Soru nedir?
Dean Harding

9
@Nemanja Trifunovic: " Harfler ve ayarlayıcılar genellikle kötü" Bunu istediğiniz kadar tekrarlayabilirsiniz, ancak bu doğru olmayacaktır. Neden kötü olduğunu düşündüğünüzü açıklamaya ne dersiniz? Bildiğim kadarıyla SO değişken değişken adı yerine özellik adı yazarak çöküyor, bu özelliği çağırır çağrısı program çökecek ve oldukça nadir göz önüne alındığında bu hata kaçırmak mümkün değildir. Bu gerçekleştiğinde, buna neden olmak için tam olarak ne yaptığımı biliyorum ve iki saniye içinde tamir ettirdim. Sorunu görmüyorum.
Ed

3
Sadece @NemanjaTrifunovic'e geçerek neden alıcı ve belirleyici yöntemlerin kötü makale olduğu oldukça eski , java hakkında ve bir java zayıflığının altını çiziyor : özelliklere sahip olmamanın zayıflığı . (dolayısıyla çok fazla uygulama detayı gösterir)… burada kuyruğumuzu ısırmak. (Bu başlıklı edilmelidir Alıcılar ve hiçbir kahrolası de bu ilgili standart düşünce var çünkü belirleyicilerin, java kötü )
ZJR

Yanıtlar:


44

Neden "özelliklere karşı yöntemler"? Bir yöntem bir şey yapar. Özellik, bir nesnenin üyesidir. Tamamen farklı şeylerdir, ancak genellikle yazılan iki tür yöntem - alıcılar ve ayarlayıcılar - özelliklere karşılık gelir. Özelliklerin yöntemlerle genel olarak karşılaştırılması anlamlı olmadığından, alıcılar / ayarlayıcılar hakkında konuşmak istediğinizi varsayacağım.

Getter ve setter yöntemi çiftleri bir kod kokusudur.

Mutlaka tartışmam gerekecekti, ama her iki durumda da bu özellik getters / setters ve mülkler meselesi değil, her ikisinin de kullanılması gerekip gerekmediği meselesi. Ayrıca, örneğin setXsalt okunur özellikler yapabileceğiniz gibi parçayı dışarıda bırakabileceğinizi de unutmayın .

Bir nesnenin tüketicisi için önemli olan, nasıl yaptığı değil, yaptığı şeydir. Davranışı yaptığı şeydir; onun durumu nasıl yapıyor. Kendinizi bir nesnenin durumu hakkında önemsiyorsanız (kalıcılık hariç, bu aynı zamanda OO'yu da kırıyorsa), sadece OOP yapmazsınız ve avantajlarını kaybedersiniz.

Son derece tartışmalı bir tutum. GUI a tarafından tutulan verileri DataStuffManagerImplçıkarmak istiyorsa, bu sayıyı bir şekilde alması gerekir (ve hayır, uygulamanın yarısını widget sınıfına sıkıştırmak bir seçenek değildir).

Mülk gittikçe karmaşıklaştıkça, bir mülkü kullanmanın performans göstergesi gittikçe daha az doğru görünüyor.

[Yöntemler var] Performans garantisi yoktur. Yöntem daha karmaşık hale gelse bile API doğru kalacaktır. Tüketici, performans sorunlarıyla karşılaşıyorsa ve API kelimesine güvenmiyorsa kodunu profille oluşturması gerekir.

Hemen hemen tüm durumlarda, tüm doğrulama mantığı vb. Hala etkili bir şekilde O (1) veya başka bir şekilde maliyetsizdir. Değilse, belki çok ileri gittiniz ve değişim zamanı. Ve bir getX()yöntem genellikle ucuz olarak kabul edilir!

Tabii, myObject.Length yazmak myObject.Length () yazmaktan daha kolaydır, ancak bu biraz sözdizimsel şekerle düzeltilemez mi?

Özellikleri şunlardır o sözdizimsel şeker.

Tüketicinin düşünmesi için daha az. Bu tesiste bir pasör var mı? Emin bir yöntem değildir.

"Bu alıcı için bir pasör var mı?" Aynı farklılık.

API programcısı dönüş değerlerine sahip yöntemler hakkında daha derin düşünecek ve mümkünse bu yöntemlerde nesnenin durumunu değiştirmekten kaçınacaktır. Komutların sorgulardan ayrılması mümkün olan her yerde uygulanmalıdır.

Bize burada ne anlatmaya çalıştığından emin değilim. Mülkler için, yan etkilere neden olmamak için daha güçlü bir yazılı yasa yoktur.


3
+1, ve bu yazılı olmayan bir yasa değil. MSDN'deki mülk kullanım yönergeleri, bunu diğerleriyle birlikte yazmıştır. Bence OP birçok şüpheden kurtulmak için onlardan geçmelidir. Ve bunu telefonumdan yazdığım için buraya bir bağlantı gönderemiyorum, ancak yönergeleri bulmak kolay olmalı.
decyclone


@delnan: Özellikler sözdizimsel şeker değildir. Özellikler alanlar gibi ele alınabilir (ayarlayıcıları varsa atama hedefi olarak kullanılabilirler). Yöntemler yapamaz.
xofz

1
@SamPearson: ile obj.x = yeşler obj.setX(y)ve obj.xeşler obj.getX(). Bu nasıl farklı?

1
@SamPearson, bir özellik ayarlayıcının ve alıcıdan birbirinden bağımsız olarak görünürlüğünü değiştirebilirsiniz. Bunu her zaman Entity Framework nesnelerimle kullanıyorum: ayarlayıcılarım korunuyor (böylece yalnızca çerçeve bir değer ayarlayabilir). O izin vermeden int uzunluk = myObject.Length söylemek mükemmel açıdan problemsiz Yani myObject.Length = 10
Michael Brown

19

Getter ve setter yöntemi çiftleri bir kod kokusudur.

Bu hatalı bir varsayımdır ve tamamen yanlıştır. Get / Set yöntemleri bir veri elemanını kapsüllemenin bir yoludur ve hiçbir şekilde bir "kod kokusu" değildir. Gerçekten bazı insanlar "kod kokusu" terimi etrafında atmaktan nefret ediyorum, ama yine de ...

Bu, herhangi bir mülk için gelecekte değişebilecek bir şeydir. 1.0 sürümünde, PropertyX'e erişmenin yalnızca bir alan döndürdüğünü varsayalım. Sürüm 1.5'te, alan null ise, PropertyX yeni bir null nesne oluşturmak için Null Nesne desenini kullanır. Sürüm 2.0, alan PropertyX içindeki getter yöntemi ile daha da doğrulanıyor.

Mülk gittikçe karmaşıklaştıkça, bir mülkü kullanmanın performans göstergesi gittikçe daha az doğru görünüyor.

Kötü tasarlanmış bir API gibi geliyor, bu özellik sözdizimi hatası nasıl görmüyorum.

C # 'daki özellikler, programcılar olarak hayatımızı biraz daha kolaylaştıran çok yaygın bir model için sözdizimsel şekerdi. Bununla birlikte, bu günlerde, veri bağlamayı kullanmak istiyorsanız, özellikleri kullanmalısınız, böylece bunlar sözdizimsel şekerden biraz daha fazladır. Sanırım gerçekten hiçbir noktanıza katılmıyorum ve neden doğrudan ortak bir modeli destekleyen bir dil özelliğini sevmediğinizi anlamıyorum.


1
Kod kokusundan daha iyi bir terim bulmak için bir ödül vereceğim. Sadece bin kez kullanıldığı yerlerde yeniden düzenleme hakkında bir kitap okuyun. Kara tahtadaki tırnaklar gibi.
JeffO

1
@Jeff O: Evet, bu terimi en etrafa fırlatan insanların genellikle çok fazla deneyimleri olmadığını görüyorum.
Ed

6
@Jeff O ve @Ed S: IME, "kod kokusu" insanların gerçekten "Sevmiyorum ama aslında bir nedenim yok" anlamına geldiklerinde kullandıkları bir terim haline geldi
Steven Evers

3
@SnOrfus: Evet, ya da pratikte pek mantıklı olmayan "dini" görüşlere sahip olduklarında, "bir yöntemin asla X sayısından daha fazla satır içermemesi" gibi , bu da genellikle bir yerde okudukları bir şeyin tekrarıdır.
Ed

1
Uygunsuz alıcı / ayarlayıcı yöntemlerinin kullanımı bir kod koku, ama öyle uygunsuz kullanımı olmalıdır şey . İşlerin dar kullanım durumları olsa bile, bu kullanım durumları için bu tür şeyleri kullanmak bir kod kokusu olarak düşünülmemelidir. Her şey için ayarlayıcıların yaratılması kör bir alışkanlık olmamalı, ancak uygun olduğunda bunları dahil etmekten korkmamalıdır. İhtiyaç duyulan şey, gelecekte devletin ne olduğunu daha erken (devlet değişmez ise kolay) bulabilmek yerine, durumu değiştirebilmenin faydalarını dengelemektir. Her ikisi de faydalıdır, ancak kod birini seçmelidir.
supercat

10

Sizin öncülünüz yanlış.

Mülkler hiçbir şekilde performans veya dahili uygulama ya da her neyse bir sözleşme değildir.
Özellikler, dilerseniz anlamsal olarak bir özniteliği temsil eden özel yöntem çiftleridir. Ve böylece tek sözleşme, bir mülkün, bir özelliğin davranmasını beklediğiniz gibi davrandığıdır.
Bir nesnenin rengini sorarsam, düz alan erişimi ile elde edilip edilmediğini veya tam zamanında hesaplanıp hesaplanmadığını varsaymıyorum.
Bütün mesele, ister bir alan ister erişimci kullansanız da, bir özniteliğin davranışlarını yöntemler kullanarak ortaya çıkarma yeteneğine sahip olmak, arabirimin tüketicisine açıktır.

Niteliklere sahip olmak (ve özelliklerin alanlara zıt olarak uygulamalarını gizlemek), görsel nesne denetleyicilerine ve diğer otomatik görüntüleme oluşturmaya, veri bağlama ve diğer birçok yararlı şeye sahip olmanın temeli olan güçlü bir bildirim özelliğidir. Ve en önemlisi, bu bilgileri diğer programcılarınız için de açıkça taşır.


6

Tüketici uygun bir OOP zihniyetinden düşünüyor. Bir API'nin tüketicisi olarak, bir nesnenin davranışıyla etkileşime girmekle ilgileniyorum. API'de özellikler gördüğümde, duruma çok benziyor. Aslında, özellikler çok fazla işliyorsa, özellik olmamalı, hatta gerçekte bir API ARE'deki özellikler tüketicilere göründüğü haliyle.

Bir mülkün devlet olması gerekiyordu . Altta yatan ayarlayıcı veya alıcı kodu eklemek değiştirirse anlamlı setine gerekli işlenmesine veya sonra devlet olsun gerçekten artık bir özelliktir ve gereken yöntemleri ile değiştirin. Bu, kodun geliştiricisi olarak size kalmış.

Bir ayarlayıcıya veya alıcıya çok fazla (ne kadar çok bağlı) kod koymak yanlıştır, ancak her durumda paterni atmak için bir neden değildir.


6

Eksik olan bir şey var ve bunun cehaletten kaynaklanıp kaynaklanmadığını veya kasıtlı olarak bu ayrıntıyı gözden geçirip geçirmediğinizi bilmiyorum, özellikler ARE yöntemleri.

C # 'ın özellik sözdizimini kullandığınızda, derleyici sessizce getter ve setter yöntemlerini meta veriyle oluşturur. Aslında, istediğin sözdizimsel şeker. CLR'de çalıştırılabilecek birkaç dil bu ayrıntıyı sizden tamamen gizlemez (Boo, bellek bana hizmet ediyorsa ve bazı Lisp uygulamaları) ve alıcıları ve ayarlayıcıları açıkça arayabilirsiniz.

Özelliklerin, bazen değişiklik bildirim olaylarını tetikleme (örneğin INotifyPropertyChanged) veya bir sınıf örneğini kirli olarak işaretleme gibi yan etkileri vardır. Burası gerçek değerlerine sahip oldukları yerdir, ancak onları oluşturmak biraz daha fazla iştir (sözdizimi meraklı makrolara sahip Boo hariç).

Şimdi, daha geniş olan soru, alıcı ve belirleyici yöntemlerin aslında İyi Bir Şey olup olmadığıdır. Açıkça ödünleşmeler var; mutator yöntemleriniz varsa, artık iş parçacığı senkronizasyonu sorunlarıyla uğraşmanız gerektiğinden, kodunuz doğal olarak daha az paralelleştirilebilir. Ve mutasyon yöntemleri (ister özellikler ister alıcı / ayarlayıcı yöntemleri olarak adlandırılır; eşdeğerdir) kullanarak Demeter Yasasını ihlal etme riskiniz olabilir, çünkü bunu yapmak çok uygun.

Ancak bazen yapılması gereken doğru şey budur. Bazen sorununuz bazı kaynaklardan veri almak, biraz değiştirmek, güncellenmiş verileri kullanıcıya sunmak ve değişiklikleri kaydetmek. Bu deyim, özellikler tarafından iyi hizmet edilir. As Allen Holub makalesi diyor, Alıcılar ve ayarlayıcılar sorunları var sırf bunları kullanmak asla gelmez. (Papağan soyut Guruspeak zararlı olarak kabul edilir). Sınıf / Sorumluluklar / İşbirliği Yapanlar yaklaşımını izleseniz bile, yine de birisine bilgi ya da bilgi sunumları sunmaya başlarsınız; amaç dolaşıklığın yüzey alanını en aza indirmektir.

Özelliklerin tersi, başka bir nesnenin bunlardan faydalanmasının çok kolay olmasıdır. Özelliklerin dezavantajı, başka bir nesnenin bunlardan faydalanmasının çok kolay olmasıdır ve bunu kolayca önleyemezsiniz.

Nesne mutasyonu, örneğin bir MVC mimarisinde kontrolör katmanında anlamlıdır. Bu sizin ortak çalışanınız. Görüşünüz aynı zamanda bir ortaktır, ancak nesnelerinizi doğrudan değiştirmemelidir, çünkü farklı sorumlulukları vardır. Sunum kodunu iş nesnelerinize dönüştürmek, alıcıları / ayarlayıcıları da önlemek için doğru yol değildir.

Saf OO soyutlamaları yerine fonksiyonel kullanırsanız denklem biraz değişir, bu da genellikle bir "kayıt" nesnesinin kopyalarını, birkaç değişiklikle oldukça özgür olsa da, oldukça önemsiz hale getirir. Ve hey, Performans garantileri almaya çalışıyorsanız, özellikler genellikle değişmez bir koleksiyonun tembel olarak yeniden yapılandırılmasından daha öngörülebilir.


5

Kitabımdaki özelliklerin kullanılmasının bir başka önemli nedeni, okunabilirliği büyük ölçüde artırabilmeleridir.

account.setBalance(Account.getBalance()+deposit);

açıkça daha az okunabilir

account.Balance += deposit;

6
Bakiyenin değiştirilmesiyle ilgili önemli bir iş mantığının olacağından emin olunması dışında, bakiye (gereğinden fazla çek olup olmadığını kontrol edin; ücret hizmet bedeli; kayıt işlemi vb.) Farklı bir örneğe uygulanırsa okunabilirlik noktanız tamamen geçerlidir ( Sıcaklık, Arka Plan Rengi vb.)
Kate Gregory

9
Neden hesap açılmıyor Para yatırma (tutar)?
xofz

4
@Sam Pearson: +1. Alıcıların / ayarlayıcıların neden genellikle zayıf tasarımı gösterdiğinin mükemmel bir örneği.
Nemanja Trifunovic

4

Bana neredeyse tam tersi dini bakış açısına sahipsiniz :)

Delphi Java taşındı zaman özellikleri eksikliği bana büyük bir hakaret oldu. Ben bir özellik bildirmek ve ya doğrudan özel bir değişkene işaret ya da (korumalı) alıcı ve ayarlayıcı yazma sonra "onları sıhhi tesisat" özelliği için kullanılır. Bu, mülkü kapsülledi ve açık bir şekilde nasıl erişilmesi gerektiğini kontrol etti. Erişildiğinde toplamı hesaplayan salt okunur bir özelliğiniz olabilir ve buna "_getTotal ()" veya benzeri balonlar değil "Toplam" debilirsiniz. Ayrıca, soyut temel sınıfta korunmalarını sağlayıp sonra herkese açık veya alt sınıflarda yayınlayarak mülklere erişimi kısıtlayabileceğiniz anlamına da geliyordu.

Bana göre, özellikler nesnenin durumunu ayarlamanın ve elde etmenin daha doğal ve etkileyici bir yoludur. Güçlendirilmemiş kodlama kurallarına güvenmek, özelliklerini eleştirdiğiniz her şeyden çok bir "kod kokusudur". Ayrıca, diğerlerinin söylediği gibi, kötü tasarlanmış bir mülk kullanımı bulmak ve başarısızlıklarını genel olarak mülk kavramını denemek ve reddetmek için kullanmak son derece kötü bir formdur. Sadece mülklerin kötü kullanımını gördünüz ve sanırım öyle olduğunu varsayıyorum ama çok dogmatik olmadan önce daha fazla araştırma yapmalısınız.


+1 Bu gerçekten bir mülkün gerçek kullanımıdır. Mükemmel cevap. " Bu aynı zamanda, soyut temel sınıfta korunmalarını sağlayıp daha sonra halka açarak veya alt sınıflarda yayınlayarak mülklere erişimi kısıtlayabileceğiniz anlamına da geliyordu. "
Karthik Sreenivasan

Delphi özellikleri reklamı yanlış kullanır. Listeyi sıralamazsınız, sorted özelliğini olarak ayarlarsınız true. Böylece bunu ayarlamak falseorijinal listeyi verir. : D Yoksa rastgele karıştırıyor mu? : D Ya da her neyse, sadece aptalca. Ayrıca, uygun bir sıralama kümesine kıyasla çok yavaş. Özellikleri fena değil, ama onları çok tutumlu kullanmayı öğrendim (alıcı ve ayarlayıcılarla oldukça mutlu olana kadar; çoğunlukla Java kullanıyorum).
maaartinus

1

Özelliklerin Java Fasulye Çerçevesi'nde kullanılmasının nedenlerinden biri, bir IDE ile entegrasyona izin vermekti - bu bileşenleri IDE'ye sürükleyebilir ve özellik düzenleyicilerini kullanarak özellikleri düzenleyebilirsiniz.

(o zamanlar sadece düzenli alıcılar ve ayarlayıcılardı - ve sadece adlandırma kuralı tarafından tanımlandılar - ve bu gerçekten kokuyordu)

Bugün, hata ayıklama gibi, normal kod aracılığıyla özelliklere erişilemediği ve değiştirildiği daha da fazla durum var.


1

Başka bir açı - gerçekten VB'den geldi. Unutmayın, .NET'in tasarlandığı 20. yüzyılın karanlık günlerinde, VB için kolay, açılan bir yedek olması, VB programcılarınızın şeyleri web formlarına sürükleyip bırakabilmeleriydi. VB'nin özellikleri vardı, bu yüzden şeyleri doğru çevirmek için bu özelliği korumanız gerekiyordu.


1
Anders Heljsberg, C # 'ı (ve bazı IL) tasarladı ve aynı zamanda özellikleri olan Delphi'yi de tasarladı.
Jesse C. Slicer

1

Mülkler için en az iki amaç vardır:

  • Farklı uygulansalar bile , kavramsal olarak alanlarla aynıdırlar . Alıcı, nesnenin durumunu değiştirmemeli ve hiçbir yan etkisi olmamalıdır. Bir ayarlayıcı, durumu yalnızca kavramsal olarak bir alanı değiştirmeye benzer şekilde değiştirmeli ve başka yan etkilere sahip olmamalıdır.

  • Sözdizimsel olarak herkese açık (muhtemelen salt okunur) alanlarla aynıdır. Bu, ortak alanın, arayanları kaynak düzeyinde bozmadan bir mülke dönüştürülebileceği anlamına gelir.


Evet, ancak "olması gereken" kelimesine dikkat edin. Emlakçılar hakkında yan etkilere sahip olmasını engelleyen özellikler hakkında hiçbir şey yoktur ve aslında bunun olduğu çok sayıda vaka gördüm.
Nemanja Trifunovic

1
Bir özellik için bir kamu alanı değiştirme olacaktır ikili uyumluluk kırmak, tüketen kod yeniden derlenmesi gerekir - ben tahmin ediyorum ki değiştirilmemiş halde sen :) varmaya ne olduğunu
MattDavey

@MattDavey: Teşekkürler. Demek istediğim buydu. Düzenlenen.
dsimcha
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.