Bir değişken alıcı ve ayarlayıcı içeriyorsa, genel olmalı mı?


23

Özel değişkenli bir sınıfım var ve sınıfın bir alıcısı ve bu değişken için bir ayarlayıcısı var. Neden bu değişkeni ortak yapmıyorsun?

Alıcıları ve ayarlayıcıları kullanmanız gerektiğini düşündüğüm tek vaka, set veya cihaz dışında bir işlem yapmanız gerekip gerekmediğidir. Örnek:

void my_class::set_variable(int x){
   /* Some operation like updating a log */
   this->variable = x;
}

10
Alıcı ve ayarlayıcılar koruma için var. Bir gün yapmak this->variable = x + 5veya UpdateStatisticsayarlayıcıda bir işlev çağırmak isteyebilirsiniz ve bu durumlarda classinstancea->variable = 5sorunlara neden olabilir.
Coder,

1
Başka bir örnek: set_inch, set_centimeter, get_inch, get_centimeter, bazı ürkütücü eylemlerle.
rwong

Evet, alıcılar ve ayarlayıcılar, örnek değişkenlerinizi kontrol etmelerini istediğiniz şekilde kontrol etmenize yardımcı olur.
developerdoug

7
@Coder: Gerektiğinde her zaman alıcı / ayarlayıcı ekleyebilirsiniz? Yoksa bu kolayca C ++ 'ta yapamayacağınız bir şey mi (benim deneyimim çoğunlukla Delphi)?
Marjan Venema

Yanıtlar:


21

Hiç bir mülk duydunuz mu?

Bir özellik "yerleşik" erişicileri olan bir alandır (alıcılar ve ayarlayıcılar). Örneğin, Java'da özellikler yoktur, ancak alıcıları ve ayarlayıcıları özel bir alana yazmanız önerilir. C # özelliklere sahiptir.

Peki neden alıcılara ve ayarlayıcılara ihtiyacımız var? Temel olarak , alanı korumak / korumak için buna ihtiyacımız var . Örneğin, alana bellek referansından erişemiyorsunuz, daha sonra alanı değiştirecek bir yönteme erişiyorsunuz (referans). Bu yöntem, kullanıcının bilmek istemediği bazı işlemleri gerçekleştirebilir ( enkapsüle etme davranışı) örneğin, sizin de örneğinizde olduğu gibi, ) gerçekleştirebilir. Örneğin, bir düzine sınıfın genel alanınızı kullandığını ve kullanım şeklini değiştirmeniz gerektiğini düşünün ... Alanın kullanım şeklini değiştirmek için bu sınıfların her birine bakmak zorundasınız ... yani "OOlysh".

Ancak, örneğin, Ölü olarak adlandırılan bir boole alanınız varsa. Bir setDead ve isDead bildirmeden önce iki kez düşünmelisiniz. İnsan tarafından okunabilen erişimcileri , örneğin setDead yerine kill () yazmalısınız.

Ancak, JavaBean adlandırma kurallarına uyduğunuz (burada Java hakkında konuşurken) olduğunu varsaydığınız pek çok çerçeve vardır, bu nedenle, bu durumlarda, adlandırma kurallarını izleyen tüm alıcıları ve ayarlayıcıları beyan etmeniz gerekir.


2
Şimdi "okunabilir insan" nihayet "grok" olabileceğime dair bir argüman. Genelde duyduğum diğer tüm argümanlar, ihtiyaç ortaya çıktığında kolayca çözülebilecek bir tür gelecek
kanıtıdır

13
Gelecekte prova yapma konusundaki küçümseme, yaygın ancak yanlış yönlendirilmiş. Evet, ihtiyaç duyulduğunda, söz konusu kodun tek müşterisiyseniz, bu değişiklikleri yapabilirsiniz . Çözümünüzü dış müşteriler için asla yayınlamazsanız, teknik borca ​​maruz kalabilirsiniz ve hiç kimsenin bilmesine gerek kalmayacak. Ancak, iç projeler en az beklediğiniz zaman kamuya açılma alışkanlığına sahip ve sonra da size karşı çıkacaksınız.
Kilian Foth

2
Gerçekten harika bir noktaya değindin. Öldürmek set değil, bir eylem. Uygulamayı tamamen gizler - OO'yu bu şekilde kodlarsınız. Öte yandan, özellikler, ayarlayıcılar / alıcılar kadar salaktır - daha da saçmadır, çünkü kolay sözdizimi, insanları ihtiyaç duyulmadıklarında bile değişkenlere eklemeye teşvik eder (OO-Furbar'ın olmasını bekler). Ölü bayraklarına "özellik" etiketi ekleyebildikleri zaman kill () yöntemini kullanmayı kim düşünebilir?
Bill K,

1
Soru bir C ++ sorusuyla etiketlendi. C ++ özellikleri desteklemiyor, peki neden bunu gönderdin?
Thomas Eding

1
@ThomasEding: C ++, geçersiz kılma atama operatörlerine sahip olmak için biraz benzersizdir. C ++ "özellik" terimini C # veya VB.NET gibi dillerle aynı şekilde kullanmazken, konsept hala oradadır. C ++ 'da operatör aşırı yükünü kullanmak mümkündür, böylece değerlendirmek için foo.bar = biz.baz+5bir fonksiyonu çağırır , sonra ona beş ekler ve elde edilen değere ayarlamak için bir fonksiyonu çağırır . Bu tür aşırı yüklemelere "özellikler" denmez, ancak aynı amaca hizmet edebilirler. bizbazfoobar
supercat,

25

Bu en popüler fikir değil ama çok fazla fark göremiyorum.

Setleyiciler ve alıcılar oldukça kötü bir fikir. Bunu düşündüm ve dürüst olmak gerekirse, uygulayıcı / alıcı bir mülk ile pratikte bir kamu değişkeni arasında bir fark bulamam.

THEORY'de bir ayarlayıcı ve alıcı veya özellik, bir değişken ayarlandığında / alındığında bazı ekstra işlemler yapmak için bir yer ekler ve teoride kodunuzu değişikliklerden izole eder.

Gerçekte, bir eylem eklemek için kullanılan belirleyicileri ve alıcıları nadiren görüyorum ve bir eylem eklemek istediğinizde, bunu TÜM'e eklemek istediğiniz bir sınıfı (günlüğe kaydetme gibi) yapmanız gerektiğini düşünmesi gereken bir sınıfın alıcılarına veya alıcılarına eklemek istiyorsunuz. daha iyi bir çözüm olmak.

Tasarım kararlarını izole etmeye gelince, bir int değerini uzun süre değiştirirseniz, hala ayarlayıcılarınızı değiştirmeniz ve en azından elle erişen her hattı kontrol etmeniz gerekir - orada pek bir yalıtım yoktur.

Değişken sınıflar zaten varsayılan olarak kaçınılmalıdır, bu nedenle bir ayarlayıcı eklemek son çare olmalıdır. Bu, nesne istenen bir duruma gelinceye kadar bir değerin ayarlanabildiği, daha sonra sınıfın değişmez hale gelebileceği ve ayarlayıcılarınızın istisnalar atacağı üretici deseniyle hafifletilir.

Alıcılar için - Bir alıcı ile genel final değişkeni arasındaki farktan hala bir şey bulamıyorum. Buradaki sorun, her iki durumda da kötü OO olmasıdır. Bir nesneden bir değer istememeli ve üzerinde çalışmamalısınız - bir nesneden sizin için bir işlem yapmasını istemelisiniz.

Bu arada, hiçbir zaman kamu değişkenlerini savunmuyorum - Belirleyicilerin ve alıcıların (ve hatta mülklerin) zaten ortak değişkenlere çok yakın olduğunu söylüyorum.

En büyük sorun, basitçe OO programcısı olmayan kişilerin, Nesne Yönelimli kodun çalışma şeklinin tam tersi olarak, etrafta geçirilen ve işletilen mülk toplarına (yapılar) nesneler yapmak için belirleyiciler ve alıcılar kullanmaya çok istekli olmalarıdır.


Buradaki diğer cevapların dışında, alıcı ayarlayıcı ile ilgili iyi bir şey şudur: Gerçek özel değişken için onun değerini varsayarsak, içine bazı onaylamalar / dönüşümler ekleyebilirim.
WinW

1
@Kiran true, ancak bunu yapıcıya ayarlarsanız doğrulamalar yapabilirsiniz ve değişmez bir sınıfa sahipsiniz. Setleyiciler için kamuya açık yazılabilir bir değişkenin iyi olduğunu söylemiyorum, hatta setçilerin kötü olduğunu söylüyorum. Kazananlar için halka açık bir son değişkeni uygulanabilir bir alternatif olarak düşünebilirim.
Bill K,

C # gibi bazı dillerde, özellikler ortak değişkenlerle ikili olarak uyumlu değildir, bu nedenle API'nizin genel değişkenini yaparsanız, ancak bazı doğrulama eklemek istiyorsanız, dönüştürürken müşterinizin programını kıracaksınız. bir özellik. En baştan kamuya açık bir mülk yapmak daha iyidir.
Robert Harvey

@RobertHarvey Bu, hala özellikleri ortaya çıkardığınız anlamına gelir. Amacım, gösterme özelliklerinden uzak durulması gerektiği ve gerektiğinde bunları alıcılarla sınırlandırmaya ve sınıfınızı değişmez hale getirmeye çalışmanız gerektiği idi. Eğer sınıfınız değişmez ise, neden bir alıcıda koda ihtiyaç duyuyorsunuz - ve bu nedenle bir alıcıya sahip olamayacağınız bir durumda. Maruz bırakılabilir değişken özelliklere sahip olmayan bir sınıf yazma yeteneğiniz yoksa, evet, bir pasör her zaman yazılabilir bir kamu değişkeninden daha iyidir (ve ayağa vurulmak her zaman bağırsakta bıçaklanmaktan daha iyidir).
Bill K,

1
Değişken durum kabul edilebilir, ancak yine de nesnenizden sizin için bir şey yapmasını istemelisiniz, nesnenize bir şey yapmamalısınız - bu nedenle durumunuzu değiştirdiğinizde bir ayarlayıcı bunu yapmak için iyi bir yol değildir, mantıkla bir iş yöntemi yazmayı deneyin bunun yerine. Örneğin, "setZLocation (getZLocation () + 5) yerine," move (Up5) ".
Bill K,

8

Alıcıların ve ayarlayıcıların kullanıcısı, kapsülleme ilkesine girer . Bu, sınıf içinde işlerin nasıl yürüdüğünü değiştirmenize ve her şeyi çalışır durumda tutmanıza izin verecektir.

Örneğin, diğer 3 nesne foo.barçubuğun değerini almaya çağırıyorsa ve çubuğun adını değiştirmeye karar verirseniz, elinizde bir sorun var demektir. Eğer çağrılan nesneler, buna foo.barsahip olan tüm sınıfları değiştirmek zorunda kalır. Bir ayarlayıcı / alıcı kullanılırsa, değiştirecek hiçbir şeyiniz yoktur. Başka bir olasılık değişkenin türünü değiştirmektir; bu durumda alıcıya / ayarlayıcıya sadece bir miktar dönüşüm kodu eklersiniz ve gayet iyisinizdir.


1
+1 - üye değişken uygulama, alıcı ve ayarlayıcı arabirimdir. Sadece arayüz halka açık olmalıdır. Ayrıca alıcı ve ayarlayıcı isimleri, temelde basit bir üye değişkeni olup olmadığına bakılmaksızın, soyutlama açısından anlam ifade etmelidir. Orada olan sıkı birleştiğinde sınıflardan inşa edilmiş bir alt sistemi kolay yolu olduğu durumlar - - istisnalar ama bu sadece bütün alt sistemini temsil etmektedir sınıfa, yine bir seviyeye kadar veri gizleme sınırını iter.
Steve314

Sınıf içindeki çalışmaları değiştirmem gerektiğinde alıcıyı ve / veya ayarlayıcıyı basitçe tanıtamaz mıyım? Delphi'de kolayca yapılan bir şeydir, fakat belki başka dillerde değil mi?
Marjan Venema

@ marjan Elbette, daha sonra herhangi bir noktada alıcıyı / alıcıyı tanıtabilirsiniz. O zaman sorun şu ki, geri dönüp TÜMÜNÜ alanını alıcı / ayarlayıcı yerine kullanmakta olan kodu değiştirmelisiniz. Kafası karışmış olan mıyım yoksa sen mi emin değilim. 0.o
Pete

3
Şahsen, bunun biraz sahte bir tartışma olduğunu düşünüyorum. Bir değişkenin anlamını değiştirirseniz ancak değişken bir alıcı ve ayarlayıcıya sahipse, ne denildiği önemli değildir. Arayüzün görünür bir parçası değil. Müşterilere, kapsüllenmiş değişkenin anlamının değişmesini veya açıklanmasını göstermek için alıcıların ve ayarlayıcıların adını değiştirmek istemeniz çok daha muhtemeldir. Bu son durumda, genel bir değişkene göre daha iyi bir durumda değilsiniz. Bu, alıcılar ve ayarlayıcılara sahip bir değişkenin kapsüllenmeden çok daha fazla ortaya çıktığı argümanının dışındadır.
CB Bailey

1
Bir refactor operasyonu her iki durumda da neredeyse ücretsizdir, bu yüzden bunu gerçekten satın almıyorum. Ayrıca, kesinlikle ihtiyaç duymadığınız sürece bir pasör veya alıcı kullanmak çok Kötü Bir Şekil - sonunda, kavramı anlayamayan insanlara, sadece tohumlarını damlatmak yerine, ihtiyaç duydukları zaman yerine üyeler için otomatik olarak ayarlayıcılar ve alıcılar ekliyorlar. kod üssün boyunca kötülüğün.
Bill K,

5

Alıcı ve ayarlayıcı kullanmak, hangi içeriğin belirli bir değişkende saklanacağını kontrol etmenizi sağlar. İçeriğin belirli bir tür veya değerde olması gerekiyorsa, ayarlayıcı kodunuzun bir kısmı yeni değerin bu gereksinimleri karşıladığından emin olmak için olabilir. Değişken halka açıksa, bu gereksinimlerin karşılandığından emin olamazsınız.

Bu yaklaşım aynı zamanda kodunuzu daha uyarlanabilir ve yönetilebilir hale getirir. Bu mimariyi, diğer tüm sınıflardan gizleyen ya da o sınıfı kullanan işlevlerden saklayan işlevleriniz varsa, bir sınıfın mimarisinde değişiklik yapmak çok daha kolaydır. Değişken adının daha önce bahsedilen değişikliği, alıcılar ve ayarlayıcılar gibi işlevleriniz varsa, yapılması daha kolay olan birçok değişiklikten yalnızca biridir. Genel fikir, özellikle sınıf değişkenlerinizle mümkün olduğunca özel tutmaktır.


Çok teşekkürler! Bahsettiğin aynı durumu düşünüyordum. Eğer bir değişkenin [0,1] 'de içeriğe girmesini istersem, gelen değeri ayarlayıcısında kontrol etmeliyim :)
Oni

Bir proje üzerinde çalışan tek geliştirici olduğunuzda, bunun gibi şeylerin işe yaramaz olduğunu düşünmek kolaydır, ancak kendinizi bir ekiple çalışırken bulursanız, bunun gibi tekniklerin alışkanlığı içinde olmanın çok kullanışlı olacağını ve size yardımcı olacağını göreceksiniz. yol boyunca çok fazla böcek kaçının.
Kenneth,

C # kullanıyorsanız, özellikleri kullanın, özelliğin ayarlayıcı bölümündeki bazı mantıklara bağlı olarak gerekirse özel bir örnek ayarlamak için bir özellik kullanabilirsiniz.
developerdoug

2

"Alıcıları ve ayarlayıcıları kullanmak zorunda kalacağınızı düşündüğüm tek vaka set veya cihazların dışında bir işlem yapmanız gerekip gerekmediğini" söylüyorsunuz.

Gelecekte bir noktada set ve get dışında bir işlem yapmanız gerekebilir ve bu olduğunda binlerce satır kaynak kod satırını değiştirmek istemiyorsanız alıcı ve ayarlayıcıları kullanmalısınız .

Birinin değişkenin adresini almasını ve iletmesini istemiyorsanız alıcıları ve ayarlayıcıları kullanmalısınız, eğer bu değişken daha sonra herhangi bir kaynak kod belirtmeden değiştirilebiliyorsa veya nesne artık mevcut durduktan sonra bile değiştirilebilirse .


Son paragrafınız her iki yolu da kesen mükemmel bir noktaya değinir: alıcıların ve ayarlayıcıların kullanılmasını istemek, diğer kodların bir şeyin adresini almasını önler. Dışsal kodlara sahip olmanın ciddi faydalar sağlaması ve birkaç dezavantajı olması gereken şeylerin adresini alırsa, bu kısıtlamalar kötü bir şey olabilir. eğer böyle bir davranışa izin vermenin çok az yararı ve dezavantajı varsa, bunu kısıtlamak iyi bir şey olabilir.
supercat,

1

İlk önce paradigma konusunda açık konuşalım.

  • Veri Yapıları -> Uygun şekilde bilgili işlevler tarafından değiştirilebilen ve değiştirilebilen bir bellek düzeni.
  • Nesneler -> uygulamasını gizleyen ve iletişim kurulabilecek bir arayüz sağlayan kendi kendine yeten bir modül.

Bir alıcı / alıcı nerede yararlıdır?

Veri Yapıları'nda alıcılar / Belirleyiciler yararlı mı? Yok hayır.

Veri Yapısı, bir işlev ailesi tarafından ortak olan ve manipüle edilen bir bellek düzeni belirtimidir.

Genel olarak, herhangi bir eski yeni fonksiyon ortaya çıkabilir ve bir veri yapısını değiştirebilir, eğer diğer fonksiyonların hala anlayabileceği şekilde yaparsa, fonksiyon aileye katılır. Aksi halde, hileli bir işlev ve bir hata kaynağıdır.

Beni yanlış anlamayın, her yerde snitch, turn-coats ve double-agent'larla birlikte veri yapısı üzerinde savaşan birkaç fonksiyon ailesi olabilir. Her birinin oynayacağı kendi veri yapısına sahip olmaları iyi, ama paylaştığında ... siyaset konusunda anlaşamayan birkaç suçlu aileyi hayal edin, çok hızlı bir karmaşa olabilir.

Ortalık genişletilmiş fonksiyon ailelerinin başarabileceği göz önüne alındığında, hileli fonksiyonların her şeyi karışmadığı şekilde veri yapısını kodlamanın bir yolu var mı? Evet, bunlara Nesneler denir.

Alıcılar / ayarlayıcılar Nesnelerde yararlı mı? Yok hayır.

Bir veri yapısını bir nesneye sarmanın amacı, hileli işlevlerin bulunmamasını sağlamaktı. Eğer fonksiyon aileye katılmak isterse, önce iyice incelenmiş ve sonra nesnenin bir parçası olmuş olmalı.

Alıcı ve ayarlayıcının amacı, nesnenin dışındaki işlevlerin doğrudan nesnenin bellek düzenini değiştirmesine izin vermektir. Bu hilelere izin vermek için açık bir kapı gibi geliyor ...

Kenar Çantası

Bir kamu alıcı / belirleyicisinin mantıklı olduğu iki durum vardır.

  • Nesne içindeki veri yapısının bir kısmı nesne tarafından yönetilir, ancak nesne tarafından kontrol edilmez.
  • Bazı öğelerin uygulama nesnesinin kontrolünde olmaması beklenen bir veri yapısının üst düzey soyutlamasını açıklayan bir arayüz.

Konteynerler ve konteyner arayüzleri bu iki durumun her ikisine de mükemmel örneklerdir. Kap, veri yapılarını (bağlantılı liste, harita, ağaç) dahili olarak yönetir, ancak spesifik eleman üzerinde herkese ve muhtelif ellere kontrol eder. Arayüz bunu soyutlar ve uygulamayı tamamen görmezden gelir ve sadece beklentileri açıklar.

Maalesef birçok uygulama bunu yanlış anlar ve gerçek nesneye doğrudan erişim sağlamak için bu tür nesnelerin arayüzünü tanımlar. Gibi bir şey:

interface Container<T>
{
    typedef ...T... TRef; //<somehow make TRef to be a reference or pointer to the memory location of T
    TRef item(int index); 
}

Bu bozuk. Konteyner'in uygulamalarının, içlerinden birinin kontrolünü, kimlerin kullandığı üzerinde açıkça ele alması gerekir. Bunun iyi olduğu değiştirilebilir bir değer dili görmedim (değişmez değer anlambilimine sahip diller, veri bozulma perspektifinden tanım gereği iyidir, ancak mutlaka veri casusluk bakış açısıyla değil).

Alıcıları / ayarlayıcıyı yalnızca kopya anlambilimini kullanarak veya bir proxy kullanarak geliştirebilir / düzeltebilirsiniz:

interface Proxy<T>
{
     operator T(); //<returns a copy
     ... operator ->(); //<permits a function call to be forwarded to an element
     Proxy<T> operator=(T); //< permits the specific element to be replaced/assigned by another T.
}

interface Container<T>
{
     Proxy<T> item(int index);
     T item(int index); //<When T is a copy of the original value.
     void item(int index, T new_value); //<where new_value is used to replace the old value
}

Muhtemelen hileli bir işlev burada hala kargaşa oynayabilir (çoğu şeyin mümkün olması için çaba sarfedilir), ancak kopya-anlambilim ve / veya vekil bir dizi hata olasılığını azaltır.

  • taşma
  • Yetersizlik
  • alt eleman ile etkileşimler tip-kontrol / tip-kontrol edilebilir (tip kaybetme dillerinde bu bir nimet)
  • Asıl öğe bellekte yerleşik olabilir veya olmayabilir.

Özel Alıcılar / Belirleyiciler

Bu, doğrudan tür üzerinde çalışan alıcıların ve belirleyicilerin son basamağıdır. Aslında ben bu alıcıları ve ayarlayıcıları bile çağırmam, erişimciler ve manipülatörler demeyi.

Bu bağlamda, bazen veri yapısının belirli bir bölümünü manipüle etmek, her zaman / hemen hemen her zaman / genellikle belirli bir kitap tutmanın gerçekleşmesini gerektirir. Bir ağacın kökünü güncellediğinizde, bir yana bakan önbelleğin temizlenmesi gerektiğini veya dış veri öğesine erişirken bir kilit kazanılması / bırakılması gerektiğini söyleyin. Bu durumlarda, DRY sorumlusunu uygulamak ve bu eylemleri birlikte düzenlemek mantıklıdır.

Özel bağlamda, ailedeki diğer fonksiyonların bu 'alıcı ve ayarlayıcıları' adım adım atması ve veri yapısını değiştirmesi hala mümkün. Bu yüzden onları daha çok erişimciler ve manipülatörler olarak düşünüyorum. Verilere doğrudan erişebilir veya bu bölümü doğru yapmak için başka bir aile üyesine güvenebilirsiniz.

Korumalı Alıcı / Alıcı

Korumalı bir bağlamda, genel bir bağlamdan çok farklı değildir. Yabancı muhtemelen haydut işlevler veri yapısına erişmek istiyor. Yani hayır, eğer varlarsa kamu alıcıları / belirleyicileri gibi çalışırlar.


0

C ++ deneyiminden setter / getter 2 senaryo için faydalıdır:

  1. dizgiler veya dizi gibi üyelere değer atamadan önce akıl sağlığı kontrolü yapmanız gerekiyorsa.
  2. -1 (veya negatif değerler) false olduğunda bool ataması için int değeri gibi işlev aşırı yüklenmesinin gerekli olduğu durumlarda yardımcı olabilir. ve alıcı için tam tersi.

Bunun dışında, güvenlik geçerli bir nokta olmakla birlikte, önemi giriş veya db ile ilgili modüller gibi çok az geliştirme uygulamasıyla sınırlıdır. Modülünüzü yalnızca birkaç kişi kullandığında neden kodlamayı fazla kullanmıyorsunuz?

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.