Getters ve Setters ne zaman haklı


175

Alıcı ve ayarlayıcılar genellikle uygun OO olmadığından eleştirilir. Öte yandan, gördüğüm çoğu OO kodunun geniş alıcıları ve belirleyicileri var.

Alıcılar ve belirleyiciler ne zaman haklı çıkar? Bunları kullanmaktan kaçınmaya çalışıyor musunuz? Genelde aşırı mı kullanılıyor?

En sevdiğiniz dil özelliklere sahipse (benimki) bu tür şeyler de bu soru için alıcılar ve belirleyiciler olarak kabul edilir. OO metodolojisi açısından aynı şeylerdir. Onlar sadece daha güzel sözdizimi var.

Alıcı / Belirleyici Eleştirisi Kaynakları (bazıları daha iyi görünürlük sağlamak için yorumlardan alınmıştır):

Eleştiriyi basitçe ifade etmek için: Alıcılar ve Düzenleyiciler, nesnelerin iç durumunu nesnenin dışından değiştirmenize olanak tanır. Bu kapsülleme ihlal ediyor. Sadece nesnenin kendisi içsel durumu önemsemelidir.

Ve örnek bir Prosedür kod sürümü.

struct Fridge
{
    int cheese;
}

void go_shopping(Fridge fridge)
{
     fridge.cheese += 5;
}

Kodun mutator sürümü:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

Alıcılar ve belirleyiciler, uygun kapsülleme sağlamadan kodu daha karmaşık hale getirdi. İçsel durum başka nesneler için erişilebilir olduğundan, bu alıcıları ve ayarlayıcıları ekleyerek çok fazla kazanamayız.

Soru daha önce Yığın Taşması ile tartışıldı:


21
Getters and setters are often criticized as being not proper OO- Alıntı lütfen.
Robert Harvey,


45
@Job, neden kodu olduğu için? Bu iyi bir soru ve ciddiye alındığında kutsal savaşın kokuyor.
Peter Turner

2
@Winston Ewert: "... soru, sınıf içindeki verilere hiç erişmeniz gerekiyorsa sorudur.": Peki, hiç kimse sizi tüm üye değişkenler için alıcılar ve ayarlayıcılar uygulamaya zorlar, sadece ihtiyacınız olanları uygularsınız. Bu yüzden herkese açık üye değişkenleri yerine alıcılar ve ayarlayıcılar kullanıyorsunuz.
Giorgio,

2
@Winston Ewert: Alıcıların / belirleyicilerin yokluğunun bu sorunu nasıl çözeceğini anlamıyorum: Her veri parçasına erişmenin bir yolu olmalı, aksi takdirde faydasızdır; Verinin hangi kısmına kodun hangi kısmı için erişilebilir olduğuna karar vermek iyi bir tasarımın görevidir. Eğer biri kötü bir tasarımcıysa, alıcılarla veya ayarlayıcılarla birlikte olsun olmasın. Sadece 2 sentim.
Giorgio

Yanıtlar:


162

Alıcıların ve ayarlayıcıların olması kendi başına enkapsülasyonu bozmaz. Kapsüllemeyi bozan , herhangi bir düşünce yapmadan, her veri üyesi için ( java lingo'daki her alan ) otomatik olarak bir alıcı ve ayarlayıcı eklemektir . Bu, tüm veri üyelerini halka açıklamaktan daha iyi olsa da, sadece küçük bir adım.

Kapsülleme meselesi, nesnenin durumunu nesnenin dışından tanıyamayacağınız veya değiştirebilmeniz değil, bunun için makul bir politikaya sahip olmanız gerektiğidir .

  • Bazı veri üyeleri tamamen nesnenin içinde olabilir ve alıcıları veya ayarlayıcıları olmamalıdır.

  • Bazı veri üyeleri salt okunur olmalıdır, bu nedenle alıcılara ihtiyaç duyabilir ancak ayarlayıcılara gerek kalmayabilir.

  • Bazı veri üyelerinin birbirleriyle tutarlı tutulması gerekebilir. Böyle bir durumda, her birine bir ayarlayıcı sağlayamazsınız, aynı anda bunları ayarlamak için tek bir yöntem kullanırsınız, böylece tutarlılık için değerleri kontrol edebilirsiniz.

  • Bazı veri üyelerinin, sabit bir miktarda artırılması veya azaltılması gibi yalnızca belirli bir şekilde değiştirilmesi gerekebilir. Bu durumda, bir belirleyici yerine, increment()ve / veya bir decrement()yöntem sağlarsınız.

  • Yine de başkalarının okuma yazma yazması gerekebilir ve hem alıcı hem de ayarlayıcı olur.

Bir örneğini düşünün class Person. Birinin bir ismi, sosyal güvenlik numarası ve yaşı olduğunu varsayalım. Diyelim ki insanların isimlerini veya sosyal güvenlik numaralarını değiştirmelerine izin vermeyiz. Ancak, kişinin yaşı her yıl 1 artırılmalıdır. Bu durumda, adı ve SSN'yi verilen değerlere başlatacak ve yaşını 0'a başlatacak bir kurucu sağlayacaksınız. Ayrıca incrementAge(), yaşı 1'e çıkaracak bir yöntem de sunacaksınız. üçü için alıcılar. Bu durumda ayarlayıcı gerekmez.

Bu tasarımda nesnenin durumunun sınıf dışından kontrol edilmesine izin verirsiniz ve sınıf dışından değiştirilmesine izin verirsiniz. Ancak, devletin keyfi olarak değiştirilmesine izin vermezsiniz. İsmin ve SSN'nin hiçbir şekilde değiştirilemeyeceğini ve yaşın bir kerede 1 yıl artırılabileceğini etkili bir şekilde belirten bir politika var.

Şimdi bir kişinin de maaşı olduğunu varsayalım. Ve insanlar istedikleri zaman işleri değiştirebilir, bu da maaşlarının da değişeceği anlamına gelir. Bu durumu modellemek için başka bir setSalary()yöntemimiz yok! Maaşın istenildiği zaman değiştirilmesine izin vermek, bu durumda tamamen makul bir politikadır.

Bu arada, senin örnekte, ben sınıfını verecek ve yerine yöntemleri ve . O zaman hala kapsülleme yapardın.FridgeputCheese()takeCheese()get_cheese()set_cheese()


public class Fridge {
  private List objects;
  private Date warranty;

  /** How the warranty is stored internally is a detail. */
  public Fridge( Date warranty ) {
    // The Fridge can set its internal warranty, but it is not re-exposed.
    setWarranty( warranty );
  }

  /** Doesn't expose how the fridge knows it is empty. */
  public boolean isEmpty() {
    return getObjects().isEmpty();
  }

  /** When the fridge has no more room... */
  public boolean isFull() {
  }

  /** Answers whether the given object will fit. */
  public boolean canStore( Object o ) {
    boolean result = false;

    // Clients may not ask how much room remains in the fridge.
    if( o instanceof PhysicalObject ) {
      PhysicalObject po = (PhysicalObject)o;

      // How the fridge determines its remaining usable volume is a detail.
      // How a physical object determines whether it fits within a specified
      // volume is also a detail.
      result = po.isEnclosedBy( getUsableVolume() );
    }

     return result;
  }

  /** Doesn't expose how the fridge knows its warranty has expired. */
  public boolean isPastWarranty() {
    return getWarranty().before( new Date() );
  }

  /** Doesn't expose how objects are stored in the fridge. */
  public synchronized void store( Object o ) {
    validateExpiration( o );

    // Can the object fit?
    if( canStore( o ) ) {
      getObjects().add( o );
    }
    else {
      throw FridgeFullException( o );
    }
  }

  /** Doesn't expose how objects are removed from the fridge. */
  public synchronized void remove( Object o ) {
    if( !getObjects().contains( o ) ) {
      throw new ObjectNotFoundException( o );
    }

    getObjects().remove( o );

    validateExpiration( o );
  }

  /** Lazily initialized list, an implementation detail. */
  private synchronized List getObjects() {
    if( this.list == null ) { this.list = new List(); }
    return this.list;
  }

  /** How object expiration is determined is also a detail. */
  private void validateExpiration( Object o ) {
    // Objects can answer whether they have gone past a given
    // expiration date. How each object "knows" it has expired
    // is a detail. The Fridge might use a scanner and
    // items might have embedded RFID chips. It's a detail hidden
    // by proper encapsulation.
    if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
      throw new ExpiredObjectException( o );
    }
  }

  /** This creates a copy of the warranty for immutability purposes. */
  private void setWarranty( Date warranty ) {
    assert warranty != null;
    this.warranty = new Date( warranty.getTime() )
  }
}

4
Lütfen Buzdolabı örneğimi fazla ciddiye almayın. :) Gerçek bir buzdolabı bir konteyner nesnesi olmalı, tam olarak ne oldukları hakkında endişelenmeden nesneleri nasıl tutacağını bilmesini beklerdim. IE bir ArrayList gibi olurdu. Buzdolabını neyin yaptığını gelince, diyelim ki saklandıklarında nesneleri diske seri hale getirelim ki sistem arızasından kurtulacaklar. Tamam. Buzdolabı örneğimi ciddiye almaya yeter.
Winston Ewert,

6
Ancak buzdolabı son kullanma tarihlerini bilmemeli, böylece peynirin kötü gittiğini ve atılması gerektiğini söyleyebilir mi? :) Tamam, bunu durdurmalıyız! :)
Dima

10
Burada devam ettiğiniz Buzdolabı Mantığı ile ilgili ilginç bir tartışma ...
Mason Wheeler

35
Haha, bunun için reklamı görmek isterim: "Yepyeni bir tür buzdolabı: Orada olmayan bir şeyi almaya çalışırken size bir şeyler fırlatıyor! Bu şekilde, yalnızca bir kez deneyeceksiniz! buzdolabını doldurmak ve buzdolabının yasadışı davranış konusunda endişelenmesine izin verin! "
gablin

42
Örnekte her şey yanlış. Bir Age alanı veya bir setAge () yöntemi olmamalıdır. Yaş, zamanın belirli bir noktasına kıyasla Kişi doğum Tarihinin bir işlevidir. Her ne kadar önemsiz görünse de, nesnelerin ve diğer kötü tasarımların tam değişkenliği modern uygulamada tam olarak yanlış olan budur, özel alanlar için olsun / set yöntemleri ile görüldüğü gibi, gerçekten değişebilir olanı, bir alanın ne olduğunu dikkatlice düşünün. Davranışlarını ve hangi durum değişikliklerinin gerçekte geçerli olduğunu bilmeli (hangi setX yöntemlerini tamamen yok etmeli).
Darrell Teague,

41

Java’da alıcıların ve belirleyicilerin temel nedeni çok basittir:

  • Arabirimde yalnızca yöntemleri değil yöntemleri belirleyebilirsiniz .

Bu nedenle, bir alanın arayüzden geçmesine izin vermek istiyorsanız, bir okuyucuya ve bir yazar yöntemine ihtiyacınız olacaktır. Bunlara geleneksel olarak x alanı için getX ve setX adı verilir.


44
Bu bir dil sınırlamasıdır. Asıl soru, diğer nesnelerin bu durumu manipüle etmesine izin vermemiz gerekip gerekmediğidir.
Winston Ewert,

3
@ Peter Turner, açıkça hiçbir şey bir dilin özellikler içeren arayüzlere sahip olmasını engellemez. Kapaklar altında alıcı / ayarlayıcı olarak iyi uygulanabilecek ancak özellikler için arayüz tanımlarına destek eklemek yeterince kolay olacaktır.
Winston Ewert,

2
@Winston, sonunda işlerin gerçekten yapılması için sınıfların birbirleri arasında ileri ve geri bilgi aktarmalarına izin vermeniz gerekir. Bunun yerine ne önerirsiniz?

6
Bir nesnenin, iç kısımlarına daha üst düzeyde bir arabirim sağlaması beklenir. Alıcılar ve Alıcılar düşük seviye arayüz olma eğilimindedir. Örneğin, ikili bir ağaç uygulayan bir sınıfınız olduğunu varsayalım. Ağaçta gezinmek için GetLeft (), GetRight (), GetValue () ve GetKey () gibi işlevlere sahip olabilirsiniz. Ancak bu tamamen yanlış bir yaklaşımdır. İkili ağaç sınıfınız Bul, Ekle, Sil gibi işlemler sağlamalıdır.
Winston Ewert

6
Başka bir örnek almak için, bir tetris parçası düşünün. Tetris parçası, block_type, döndürme, konum gibi bazı içsel durumlara sahiptir. GetBlockType (), GetRotation (), GetPosition () gibi alıcılara sahip olabilirsiniz. Ama gerçekten yapmamalısın. Yapmanız gereken şey, bu parça tarafından işgal edilen tüm karelerin listesini döndüren bir GetSquares () yöntemidir. Ayrıca SetPosition () veya SetRotation () gibi öğelere sahip olmamalısınız. Bunun yerine, MoveLeft (), MoveRight (), Rotate (), Fall () gibi işlemleriniz olmalıdır.
Winston Ewert

20

Gönderen http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and

JavaBean tarzı:

connection.setUser("dukie");
connection.setPwd("duke");
connection.initialize();

OO tarzı:

connection.connect("dukie","duke");

Açıkçası, ikinci yaklaşımı tercih ediyorum; Uygulama ayrıntılarını akıtmaz, daha basit ve daha özlüdür ve tüm gerekli bilgiler yöntem çağrısına dahil edilmiştir, bu nedenle doğru olması daha kolaydır. Ayrıca, mümkün olduğunda, yapıcıdaki parametreleri kullanarak özel üyeler ayarlamayı tercih ederim.

Sorunuz, alıcı / alıcı ne zaman haklı? Belki bir mod değişikliğine ihtiyaç duyulduğunda veya bazı bilgiler için bir nesneyi sorgulamanız gerektiğinde.

myObject.GetStatus();
myObject.SomeCapabilitySwitch = true;

Bunu düşünürken, C # 'da ilk kez kodlamaya başladığımda, yukarıda gösterilen Javabeans tarzında çok fazla kod yazdım. Ancak, dil konusunda deneyim kazandıkça, kurucuda daha çok üye belirleme yapmaya ve yukarıdaki OO stiline daha çok benzeyen yöntemleri kullanmaya başladım.


6
Neden "tüm değişkenleri parametre olarak ver" OO stili?

5
"OO stiliniz" 2 veya 3 seçenek için uygun olsa da, bunun üzerine çıkınca JavaBean stilini tercih ederim. Parametrelerin olası her kombinasyon için 20 aşırı yöntemi olması, sadece korkunç görünüyor
TheLQ

1
@TheLQ: C # 4.0, yapıcı ve yöntem çağrılarında isteğe bağlı ve adlandırılmış parametrelere izin vererek bunu kolaylaştırır.
Robert Harvey,

7
@TheLQ Akıcı sözdizimine sahip Builder'ın ne işe yaradığı, örneğin Guava'nın MapMaker'ına bakın .
maaartinus

5
@ Thorbjørn Ravn Andersen, "parametre olarak tüm argümanları ver" diyerek "JavaBean ayarlayıcıları çağır" dan daha iyi bir OO tarzı olduğunu söyleyebilirim çünkü bir ayarlayıcı, tanım gereği, dahili ayrıntıları ortaya koyan temel bir öznitelik olduğunu belirtir. Örnekte connect (..) yönteminin kullanılması böyle bir varsayımda bulunmaz; belki bir kullanıcı ve şifre öznitelikleri belirlersiniz, belki yapmazsınız. Önemli olan doğru OO konseptine odaklanmanız: “connect” mesajı.
Andres F.

13

Alıcılar ve belirleyiciler ne zaman haklı çıkar?

"Get" ve "set" davranışları aslında modelinizdeki davranışlarla eşleştiğinde, pratikte hiçbir zaman değildir .

Diğer her kullanım sadece bir aldatmacadır, çünkü işletme alanının davranışları açık değildir.

Düzenle

Bu cevap saygısız olarak ortaya çıkmış olabilir, bu yüzden genişleyeyim. Yukarıdaki cevaplar çoğunlukla doğrudur, ancak OO tasarımının programlama paradigmalarına ve bazıları da büyük resmi özleyenlere odaklanmaktadır. Tecrübelerime göre bu, insanların kazanımlardan ve belirleyicilerden kaçınmanın OO programlama dilleri için bazı akademik kurallar olduğunu düşünmelerini sağlar (örneğin, alıcıların özelliklerle özelliklerinin değiştirilmesinin büyük olduğunu düşünür)

Aslında bu tasarım sürecinin bir sonucudur. Bu paradigmaları kırıp kırmadığını ve iyi OO programlamanın ne olup olmadığını tartışarak arayüzlere, kapsülleme ve kalıplara girmeniz gerekmez. Nihayetinde önemli olan tek şey, etki alanınızda bu şekilde çalışan bir şey yoksa, bunları size koyarak, etki alanınızı modellemiyor olmanızdır.

Gerçek şu ki, etki alanınızdaki herhangi bir sistemin alıcıları ve ayarlayıcıları olması pek olası değildir. Maaş bordrosundan sorumlu olan kadın veya erkeğe yürüyemez ve "Bu maaşı X'e ayarla" veya "Bana bu maaşı al " diyemezsiniz . Böyle bir davranış basitçe mevcut değil

Bunu kodunuza ekliyorsanız, sisteminizi etki alanınızın modeline uygun şekilde tasarlamıyorsunuzdur. Evet, bu arayüzleri ve enkapsülasyonu kırar, ama mesele bu değil. Mesele şu ki, var olmayan bir şeyi modelliyorsun.

Muhtemelen önemli bir adım ya da süreci kaçırıyorsunuzdur, çünkü büyük olasılıkla ödeme yapmak için yürüyemem ve bu maaşın X olarak ayarlandığını söylememin bir nedeni vardır.

İnsanlar alıcıları ve ayarlayıcıları kullandıklarında, bu işlem için kuralları yanlış yere itme eğilimindedirler. Bu etki alanınızdan daha da uzaklaşıyor. Gerçek dünya örneğini kullanarak, içeri giren rastgele birinin bu değerleri alma iznine sahip olduğunu kabul etmek, aksi halde onlardan ricada bulunmayacağını kabul etmek gibidir. Sadece alan değil, alanın nasıl olduğu konusunda da yalan söylüyor.


Bu, önceki 17
cevapta

1
Diğer cevaplar nesneler, arayüzler ve diğer dil paradigmaları hakkında konuşur. Hangisi iyi, ama asıl mesele değil. Alıcı ve ayarlayıcılar sadece kötü değil çünkü bazı kodlama kurallarını çiğniyorlar, ama öncelikle bu davranışla temsil ettiğiniz gerçek modelde neredeyse hiç karşılaşmıyorsunuz. Bu nokta, en iyi kodlama uygulamaları hakkındaki tartışmada kaybolma eğilimindedir.
Cormac Mulhall

Sizce maaş bordrosunun arayüzü set/getmaaş değil midir?
Winston Ewert

1
Yetkilendirme katmanlarının etrafına sarılırlar ve belirli dış varlıklar ile sınırlandırılırlarsa alıcı veya ayarlayıcı değillerdir. Bordro departmanında maaşı değiştiren herhangi bir yöntem bulunmadığını söylemiyorum, ancak bu yöntemin şirketin kendi içindeki iç süreçlerle aynı hizada olması gerekiyor. Örneğin, çoğu şirket, bir yönetici tarafından yetkilendirilen çalışan sözleşmesine dayanarak maaş ayarladı. İşçinin maaşını değiştirmesi durumunda yeni bir sözleşme yapılır ve bir yönetici tarafından imzalanmak zorundadır. Bu nedenle, bordro, bir sözleşme nesnesi ve bazı yetkilendirme nesnelerinin maaş
bordosunu

3
Ya da başka bir deyişle, set_salary (new_salary, worker_id) ve yetkili_salary_update (worker_contract, authorising_manager) arasında bir fark var. Süreç dahili iş sürecini modellemeli
Cormac Mulhall

11

Genel bir kural olarak, alıcılar ve belirleyiciler kötü bir fikirdir. Bir alan mantıksal olarak arayüzün bir parçası değilse ve onu özel yaparsanız, sorun değil. Mantıken arayüzün bir parçasıysa ve herkese açık yaparsanız, sorun değil. Ancak, bir özel ve daha sonra bir alıcı ve ayarlayıcı sağlayarak arkanı dönüp etkin bir şekilde halka açtırırsanız, kodunuzun artık daha ayrıntılı ve şaşkın olması dışında başladığınız yere geri dönersiniz.

Açıkçası, istisnalar var. Java'da arayüzleri kullanmanız gerekebilir. Java standart kütüphanesi, normal kod kalitesi ölçümlerinden daha ağır basacak kadar ileri düzeyde geriye dönük uyumluluk gereksinimlerine sahiptir. Aslında efsanevi durumla başa çıkmanız bile mümkündür, ancak nadir bir durum olması durumunda, daha sonra arayüzü kırmadan, depolanan bir alanı anında hesaplamanızla değiştirebilirsiniz. Ancak bunlar istisnalar. Alıcı ve ayarlayıcılar özel gerekçelendirme gerektiren bir kalıptır.


6
Bir alıcı ve ayarlayıcı, alanın değil özniteliğin arayüzün bir parçası olduğu anlamına gelir. GetBirthDate () ve SetBirthDate () yönteminin "yyyy / mm / dd" aldığını varsayalım ancak depolanan alan 01/01 / 1000'den bu yana geçen gün sayısıdır. Bunu 01/01/0001 olarak değiştirebilirsiniz; alıcı ve ayarlayıcı arayüzü aynı tutacaktır. Özellikle 'kamu' kamusal olarak silinebilir anlamına geldiğinden, değişkenler asla kamuya açık olmamalıdır; her zaman gelen değeri doğrulamak, ilgili alanları güncellemek, gerektiğinde dönüştürmek vb. için bir ayarlayıcı kullanın. Dahili depolama biriminin değişmesi durumunda bir alıcı kullanmaya çalışın.
Andy Canfield,

@AndyCanfield, halkın halka açık bir şekilde parçalanabileceği anlamına geldiğini söylemek için biraz güçlüydü. Eğer bir ayarlayıcıya sahipseniz ve yanlış değer ona gönderildiyse, o zaman programı bozmaya çağırabileceğiniz bir istisna atabilirsiniz, ancak bu bir hata ile sonlandırılır. Nesnenin kullanıcısı bir değişkene değer verebilir ve cud yanlış verirse değeri sonra u akılda taşıyabilir ve test edebilirsiniz.u "ah, ancak sadece bir setter kullanırsam 1 test yapmak zorundayım" diyebilir, ancak belki kendi kodunuz değişkene kötü bir değer verir .. yani setter olmayabilir Testlerinizi azaltın. Testlerde, prog "çöpe" değil
barlop

3

Alanın doğrudan mı yoksa yöntem yoluyla mı erişilebilir olduğu gerçekten önemli değil.

Sınıf değişmezleri (faydalı olanlar) önemlidir. Ve onları korumak için, bazen dışardan bir şeyi değiştirmememiz gerekmiyor. Örneğin. Ayrı genişliği ve yüksekliği olan Kare sınıfımız varsa, bunlardan birini değiştirmek onu kare dışında bir şey haline getirir. Bu yüzden yöntem değişikliğine ihtiyacımız varSide Dikdörtgen ise, ayarlayıcılarımıza / genel alana sahip olabiliriz. Ancak ayarlayıcı, sıfırdan büyük olanın daha iyi olup olmadığını test edecek.

Ve somut dillerde (örneğin, java) bu yöntemlere (arabirimler) ihtiyaç duymamızın nedenleridir. Ve yöntemin bir başka nedeni de uyumluluktur (kaynak ve ikili). Bu yüzden onları eklemek daha kolay, sonra kamuya açık alanın yeterli olup olmadığını düşünün.

Btw. Halka açık alanlara sahip, değişmez basit değer tutma sınıfları kullanmayı seviyorum.


Kaçınılması gereken tek şey budur. Tarladan mülk / alıcı / ayarlayıcıya geçmek, çoğu dilde büyük bir değişikliktir.
MrDosu

2

Arayüzleri aynı tutarken içindekileri ne olursa olsun ile değiştirmek isteyebilirsiniz. Arabirimleriniz değişmezse, kodlamanız gerekmez. İçini istediğin gibi değiştirebilirsin.


1
Bu cevabın çok aşağı olmasına şaşırdım. Alıcılar ve ayarlayıcılar, mevcut API'nizi bozmadan gelecekte daha fazla iş yapmanızı sağlar (örneğin, bir etkinlik başlatır, daha fazla giriş doğrulaması yapar, dahili defter tutma yapar). Genel olmayan kodlarda bile, daha az API uygulamanız, güncellemeniz gereken bağımlılıklar daha az ve bu güncellemeleri yaparken daha az hata girmeniz gerekir.
AmadeusDrZaius

0

Benim yaklaşımım bu -

Daha sonra verilerle uğraşmayı beklediğimde, bir alıcı / alıcı belirlenir. Ayrıca, değişiklik oluyorsa, genellikle verileri alıcı / ayarlayıcıya iletirim.

Eğer bu bir POD yapısıysa, yuvaları boş bırakıyorum.

Daha soyut bir düzeyde, soru “verileri kimin yönettiği” dir ve bu projeye bağlıdır.


0

Alıcıları ve ayarlayıcıları kullanmak karmaşıklaşıyorsa, sorun kavramın kendisi değil de dil olabilir.

İşte Ruby'de yazılmış ikinci örnekteki kod :

class Fridge
  attr_accessor :cheese
end

def go_shopping fridge
  fridge.cheese += 5
end

Java'daki ilk örneğe çok benziyor mu? Alıcılar ve belirleyiciler birinci sınıf vatandaşlar olarak muamele gördüklerinde, kullanmaya alışkanlık değillerdir ve ilave esneklik bazen gerçek bir nimet olabilir - örneğin, yeni bir buzdolabında peynir için varsayılan bir değer döndürmeye karar verebiliriz:

class Fridge
  attr_accessor :cheese

  def cheese
    @cheese || 0
  end
end

Elbette herkese açık olarak gösterilmemesi gereken birçok değişken olacak. Gereksiz yere dahili değişkenleri açığa çıkarmak kodunuzu daha da kötüleştirir, ancak alıcıları ve ayarlayıcıları zorla suçlayabilirsiniz.


Bu çok güzel bir şekilde ifade edilir. Oluşturucu fonksiyonlar eklendi çünkü tarifi yavaş yavaş değiştirirken değişken nesneler oluşturmak istiyoruz: belki yapay tatlandırıcı eklerseniz, şeker eklemeniz gerekmez. Adlandırılmış parametreleri kullanmak ve aşırı yüklemeyle bile hepsini yapmak için bir yöntem oluşturmak çok zordur. Ve elbette java'da adlandırılmış parametreler yoktur, bu nedenle insanların Builder desenini kullanmasının bir nedeni daha vardır.
YoYo,

0

SizeGenişliği ve yüksekliği kaplayan bir sınıf düşünün . Yapıcıyı kullanarak ayarlayıcıları ortadan kaldırabilirim ama bu nasıl bir dikdörtgen çizmeme yardımcı oluyor Size? Genişlik ve yükseklik sınıfa dahil olan iç veriler değildir; Boyut tüketicileri için olması gereken paylaşılan verilerdir.

Nesneler davranışlardan ve durum - veya niteliklerden oluşur. Maruz kalan bir devlet yoksa, sadece davranışlar halka açıktır.

Devlet olmadan, bir nesne koleksiyonunu nasıl sıralarsınız? Bir nesnenin belirli bir örneğini nasıl ararsınız? Yalnızca yapıcılar kullanırsanız, nesnenizde uzun bir öznitelik listesi olduğunda ne olur?

Hiçbir yöntem parametresi doğrulama olmadan tüketilmemelidir. Bu nedenle yazmak tembelliktir:

setMyField(int myField){
    this.myField = myField;
}

Bu şekilde yazarsanız, en azından ayarlayıcıyı doğrulama için kullanmaya hazırlandınız; halka açık bir alandan daha iyidir - ancak ancak. Ancak en azından, müşterilerinizin kodunu kırmadan geri gelip geçerlilik kuralları koyabileceğiniz tutarlı bir ortak arayüze sahipsiniz.

Alıcılar, ayarlayıcılar, mülkler, mutasyonlar, onlara ne yapacağınızı söyleyin ama onlar gerekli.


Ancak en azından, müşterilerinizin kodunu kırmadan geri gelip geçerlilik kuralları koyabileceğiniz tutarlı bir ortak arayüze sahipsiniz. Bu doğru değil. Doğrulama kurallarını yolun aşağısına daha da eklemek, "müşterilerinizin kodunu bozabilir". Örneğin, bir intörnek değişkeni alın ve yalnızca olumsuz olmayan değerleri kabul etmek için bir doğrulama kuralı eklemeye karar verdiğinizi hayal edin. Sorun şu ki, müşterinizin kodu zaten negatif bir değere ayarlama olasılığına bağlı olabilir ...
jub0bs 1:15

0

Alıcılar ve belirleyiciler, kapsülleme ve gerçek OO'yu ihlal ederse, o zaman başım derde girer.

Her zaman bir nesnenin, yapmanız gereken akla en iyi gelen şeyi temsil ettiğini hissettim.

Java'da Labirent üreten bir program yazmayı bitirdim ve “Labirent Kareleri” ni temsil eden bir sınıfım var. Bu sınıfta koordinatları, duvarları ve boolelleri vb. Temsil eden veriler var.

Bu verileri değiştirmek / değiştirmek / değiştirmek için bir yolum olmalı! Alıcı ve ayarlayıcı olmadan ne yapabilirim? Java özellikleri kullanmaz ve bu sınıfa yerel olan tüm verilerimi herkese açık olarak ayarlama, KESİNLİKLE bir kapsülleme ve OO ihlalidir.


6
İşte soru şu: Tüm bu alanları halka açık hale getirip alıcıları ve ayarlayıcıları kullanmayı bıraktıysanız kodunuz nasıl farklı olurdu?
Winston Ewert,

Teoride, değil. Neden bu noktada bir sınıf bile yapılıyor? Aynı argüman herhangi bir şeyle yapılabilir. Ancak benim altındaki yazı, daha zarif bir şekilde söylemişti. (Alıcı ve ayarlayıcılar bir nesneye güvenli bir şekilde değer vermenin veya bu nesneden bir değer almanın bir yoludur.) Yazı devam ediyor ..
Bryan Harrington

3
Ben şunu işaret ediyorum: o poster sonunda benimle aynı fikirde ve bu etki için başka bir cevap gönderdi. Temel olarak, alıcıları ve ayarlayıcıları kullanmak, verileri doğrudan işlemekle aynıdır. Bunu yaparak gerçekten OOness kazanmazsınız. OO olabilmek için verilere daha yüksek bir arayüz sunmanız gerekir.
Winston Ewert,

4
Bence onu tanımlamanın en iyi yolu, arayüzlerinizi içten dışa değil dıştan tasarlamanız gerektiğini söylemektir. Nesnenizin sağladığı arabirim, nesnenin nasıl kullanıldığına değil nasıl kullanıldığına göre belirlenir. Bu yüzden alıcıları yazmayın ve harici nesnenin verileri yorumlamasına izin vermeyin. Hangi soruya cevap vermeleri gerektiğini öğrenin ve bu soruyu cevaplayan bir yöntem yazın. Harici nesnelerin bir belirleyici tarafından durumu değiştirmesine izin vermeyin, ne tür manipülasyonlar yapmaları gerektiğini öğrenin ve bunu yapan yöntemleri yazın.
Winston Ewert,

2
Bazı durumlarda, Getters ve Setters en iyi yöntemdir. Bazen sağlayabileceğiniz en iyi arayüz. Ancak, çoğu durumda değildir. Çoğu durumda, uygulama ayrıntılarını diğer sınıflara sızdırıyorsunuzdur.
Winston Ewert

-1

Öncelikle, yorumlayacağım iki tür nesne vardır: değer ve hizmet türleri.

Hizmet türleri asla ayarlayıcılara sahip olmamalı, ihtiyaç duydukları bağımlılık ne olursa olsun elde edilememelidir. Bağımlılıkları geçmenin en iyi yolu, tüm örneklerin başlangıçtan itibaren tamamen düz, basit bir şekilde oluşturulduğu bir kurucu ya da fabrika aracılığıyladır.

Değer türleri de değişmez olmalıdır, diğer taraftan, bunun ORM gibi pratik olmadığı veya bir widget'tan nesneye gibi başka bir eşlemenin olduğu zamanlar vardır. Sistemin etrafında bir katmandan veya bir parçadan diğerine geçen diğer tüm değer tipleri değişmez olmalı ve ayarlayıcılara sahip olmamalıdır.


Üçüncü bir tip öneriyorum: amacı bir veya daha fazla değer tutmak olan değişken bir konteyner; Bir çok durumda, bir kabın mantık ya da onaylama yoluna sahip olması beklenmemelidir. Altı pozitif tamsayı hesaplamak için bir yönteme ihtiyaç duyan kod, altı tamsayı için bir kabı, sonuçları burada saklayacak olan yönteme aktarabilir. Rakamların pozitif olmasını sağlama sorumluluğu, genellikle konteynere değil, arayan veya aranan yönteme dayanmalıdır.
supercat,

-1

Bir Getter / Setter, başka herhangi bir kamu yönteminin haklı olduğu gibi haklı. Gerekçe temelde, sınıfımızın diğer sınıflarla nasıl etkileşime girdiğini tanımlayan dış dünyaya bir arayüz sağlamak istediğimizdir. Bunu esas olarak yapıyoruz, çünkü ayrı varlıklar arasındaki eşleşmeyi azaltmak istiyoruz. Bağlantının azaltılması birçok nedenden dolayı iyi bir şeydir:

  • Şu anki kodumdan aynı sınıf arayüzünü kullanabilirim, ancak bu arada sınıf yeni yöntemler ekledi (ancak eski arayüzü korudu).
  • Bir sınıfın iç temsilini, tüketicilerini etkilemeden değiştirebilir
  • Hata olasılığını azaltın: dahili verilerinizi özel yaparsanız, harici kodun dahili verilerinizle karışmayacağından emin olabilirsiniz


-4

Programlama dilinizi otomatik olarak geliştiren firma tarafından geliştirilen IDE'nin "Nesne Oryantasyonunun Prensipleri" ni ihlal etmediğini umuyorum.

Demek ki, ne zaman kamuya açık bir değişkene sahipseniz, bir alıcı ve bir alıcı kullanın ve altınsınız. Son derece nesne yönelimli kapsülleme ilkesinin gerekli unsuru gibi görünüyor - çok fazla önemsiz kod gibi görünse bile.

Bunları kullanmanın nedeni, doğru kapsüllemenin henüz gerçekleşmiş olabileceği ve nesnenizle birlikte maymun mayının nesnesini hissetmesini sağlayan tabakayı soyutladığınız sürece, nesneyi haklı bile bilmeden kaldırabileceğiniz mi?

Söylemek yeterli, bölünmüş bir ev dayanamıyor, OO'nun kiracılarından biri kendiliğinden açılmıyor ve hem kapsülleme hem de erken optimizasyona hizmet edemiyorsunuz.


4
ve setFoo () ve getFoo () 'u çağırmak için her değişken kullandığımda çok fazla kod ekleyerek ne kazandım?
Winston Ewert,

7
İşte mesele, kapsüllenme olduğunu sanmıyorum. Hala nesnenin durumunu başka yerlerden değiştiriyorsunuz. Sadece daha ayrıntılı olarak yapıyorsun. Kapsülleme kazanmak için, bu değere sahip olan sınıftaki değer manipülasyonunu merkezileştirmeniz gerekir. Başka bir şey sadece OO giyiminde usule ilişkin koddur. (Bunda mutlaka yanlış bir şey yok, ama olan bu).
Winston Ewert,

2
Kapsülleme avantajı, belirli değerlerle ilgili tüm mantığın bir yerde (az ya da çok) olmasıdır. Bunu alıcılarla ve ayarlayıcılarla anlamıyorum. Bu nedenle, onlar için çok fazla fayda sağladığımı sanmıyorum.
Winston Ewert,

1
Ancak, alıcılar ve ayarlayıcılar ile daha sonra verileri halka açık erişim yoluyla özgürce değiştiren bir kodum olmasını tercih edeceğim. Bu şekilde en azından gelen verilerin doğrulamasını ekleyebilirim.
Winston Ewert

3
Ben kesinlikle aykırı bir hayranı değilim. Ancak benim itirazım, değişkenlerini özel kılan ve daha sonra hiçbir fark yaratmadan serbestçe sonuçlanan alıcılar ve belirleyiciler diyen insanlar. Sınıfınızda alıcı / ayarlayıcı kullanmak istiyorsanız sorun değil. Soru neden? Farkında olduğum öncelikli fayda, daha önce hataları yakalamak için veriler üzerinde bazı doğrulamalar yapabilmenizdir. Verileri yöneten tüm kodlar aynı yerde olduğunda bu daha az yardımcı olur. Ancak yine de yardımcı olabilir. İdeal olarak, özellikleri destekleyen ve ayrıntılardan kaçınabilecek bir dile sahipsiniz.
Winston Ewert

-4

Burada daha genel cevaplar alacağımızı düşündüm

Alıcılar ve ayarlayıcılar genel olarak son derece OOP'dur (herhangi bir şeyin yanlış olduğunu söyleyen herhangi biri, bu kadar basit).

Aşırı mühendis olmadığınızı hatırlamanız gerekse de, asla gerekmeyen bir alıcı veya ayarlayıcı yapmayın. Başka bir sınıf tarafından kullanmayacağınız herhangi bir bilgi için, alıcı veya ayarlayıcınız olmamalıdır.

Bununla birlikte, alanları kamuya açmamanın ve bunun yerine alıcıların ve ayarlayıcıların olmasının nedeni çoğunlukla:

  • Alanları kullanarak uygun testler yapmak mümkün değildir. Alıcılar / alıcılar bu konuda çok daha iyi.

  • Alanları gerçek zamanlı programlama ortamında doğru kullanmak imkansızdır. Senkronize alıcı / ayarlayıcılar gitme yoludur.

  • Arabirim konusu (zaten açıklanmayacağım, açıklamayacağım)

  • Sistemi doğru bir şekilde yeniden kullanırken kullanımı daha kolaydır.

  • Sınıfınızı kullanan hangi sınıfları ve bir alanı bir alıcı / ayarlayıcıdan daha fazla değiştirirseniz neyin kırılacağını bilmek çok daha zordur.

Bu yüzden, alıcı / belirleyici yerine halka açık bir alan kullandığınız tek zaman resmi bir proje yapmadığınız, bunun yerine sadece eğlence için yaptığınız ve alıcı / belirleyicileri rahatsız edemediğiniz zamandır.


2
Test edilebilirlik için +1. Daha önce kimsenin bahsetmediği için şok oldum. Özelliklerin bir başka kullanışlı özelliği de onları ayıklamaktır. (kodda bir kesme noktası eklemek, alanlar için donanım / bellek kesme noktaları gerektirdiğinden daha kolaydır).
Mark H

9
Alıcı ve belirleyicilere yapılan itiraz, ruhları ve niyetleri görmezden gelirken OOP yasalarını takip etmek için sık sık kullanılmalarıdır. OOP, diğer nesnelerin içindekilerle çarpmasına izin vermemelisin diyor. Bunu yapmanıza izin veren alıcıları ve ayarlayıcıları tanımlarsanız, OOP'yi ihlal edersiniz.
Winston Ewert,

6
Alıcıların ve ayarlayıcıların basit kamusal alanlara göre birçok yararı olduğuna katılıyorum. Ancak, testin onlarla nasıl daha iyi olduğu konusunda net değilim. Açıklar mısın
Winston Ewert,

4
@Skarion: Cevabınıza katılmıyorum. İki seçenek sunuyor gibi görünüyorsunuz: ya alıcılar / ayarlayıcılar kullanmak ya da alanları halka açmak. Ancak üçüncü bir seçenek var: alıcı / ayarlayıcı kullanmak veya tarlaları göstermek! Neden bir iç alanın durumunu test etmeniz gerekiyor? Nesnenizin genel API'sini test etmiyor musunuz?
Andres F.
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.