Bir yöntemi yeniden adlandırmak kapsüllemeyi koruyabilir mi?


9

Alıcılar / ayarlayıcılar ne zaman haklı olduğu hakkında bu sayfayı okuyordum ve OP aşağıdaki kod örneğini verdi:

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);        
}

Kabul edilen cevap :

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

Kapsülleme, get / set olarak putCheese()/ olarak yeniden adlandırılarak nasıl korunur takeCheese()? Açıkçası bir değer alıyorsunuz / ayarlıyorsunuz, neden onu get / set olarak bırakmıyorsunuz?

Aynı cevapta şunları da belirtir:

Alıcılara ve pasörlere sahip olmak başlı başına kapsüllenmeyi bozmaz. Enkapsülasyonu bozan şey, herhangi bir düşünce vermeden her veri üyesi için (java lingo'daki her alan) otomatik olarak bir alıcı ve ayarlayıcı eklemektir.

Bu durumda, sadece bir değişkenimiz var cheeseve peyniri buzdolabına alıp iade etmek isteyebilirsiniz, bu nedenle bu durumda bir get / set çifti haklı çıkar.


7
putCheesebuzdolabına peynir ekler ve takeCheesekaldırır - bunlar nesne alanı alıcıları ve ayarlayıcıları ((düşük düzey) bilgisayar programlama soyutlamaları) yerine (daha yüksek seviye) etki alanı odaklı soyutlamalardır.
Erik Eidt

Yanıtlar:


17

Bence bu noktayı kaçırıyorsun. Setter ve alıcıyı yeniden adlandırmanız gerektiğini söylemez, ancak buzdolabından öğe ekleyip kaldıran yöntemlere sahip olmaktır. yani

public class Fridge
{
    private int numberOfCheeseSlices;

    public void AddCheeseSlices(int n)
    {
         if(n < 0) { 
             throw new Exception("you cant add negative cheese!");
         }
         if(numberOfCheeseSlices + n > this.capacityOfFridge) { 
             throw new Exception("TOO MUCH CHEESE!!");
         }
         ..etc
         this.numberOfCheeseSlices += n;
    }
}

Şimdi özel değişken kapsüllenmiştir. Sadece istediğim herhangi bir şeye ayarlayamıyorum, sadece yöntemleri kullanarak buzdolabından peynir dilimleri ekleyebilir ve çıkarabilirim, bu da istediğim peynir iş mantığı kurallarının uygulanmasını sağlar.


2
Doğru, ama yine setCheese()de ayarlayıcıda aynı mantığa sahip olarak bırakabilirsiniz . Her neyse benim için, yöntemi yeniden adlandırarak bir ayarlayıcı kullandığınız gerçeğini gizlemeye çalışıyorsunuz, ancak açık bir şekilde alıcı / bir şey ayarlıyorsunuz.
QueenSvetlana

21
@QueenSvetlana bir pasör değil. Bu bir ameliyat. Buzdolabına "işte başka bir peynir" söylüyorsunuz ve onu iç, kapsüllenmiş peynir sayısına ekliyor. Bir pasör "şimdi 5 peyniriniz var" derdi. Bunlar sadece farklı isimler değil, işlevsel olarak farklı operasyonlardır.
Ant P

1
setCheese diyebilirsiniz, ancak bu, peynirin değerini ayarlamadığı için kafa karıştırıcı olurdu.
Ewan

6
Burada bir tamsayı taşması hatası olduğunu unutmayın. Zaten 0'dan fazla peynir varsa, AddCheese(Integer.MAX_VALUE)başarısız olmalı, ama olmayacak.
user253751

3
Bu tamamen ..etc bölümünde ele alınacaktır
Ewan

5

Harfler ve ayarlayıcılar tanımı gereği her seferinde kapsüllemeyi keserler . Ne olabilir tartışılabilir bazen bunu yapmak zorunda olmasıdır. Yoldan çekilince, işte benim cevaplarım:

Kapsülleme, getCet / putCheese () / takeCheese () olarak yeniden adlandırılarak nasıl korunur?

Aradaki fark anlambilimdedir, yani yazdıklarınızın anlamı. Kapsülleme sadece iç durumu korumakla kalmaz, aynı zamanda iç durumu gizlemekle de ilgilidir . İç durum dışarıda bile bilinmemelidir, bunun yerine nesnenin bu durumu manipüle etmek / kullanmak için işle ilgili yöntemler (bazen "davranış" olarak adlandırılır) sunması beklenir.

Yani getve setteknik terimler ve "buzdolabı" etki alanı ile ilgisi yok gibi görünüyor, putve takeaslında bir anlam ifade edebilir.

Ancak , ister putveya takeyapmak fiili anlamda hala gereksinimlerine bağlıdır ve objektif karar alınamaz. Sonraki noktaya bakın:

Bu durumda, sadece bir değişkenimiz var, peynir ve peyniri buzdolabına alıp iade etmek isteyebilirsiniz, bu nedenle bu durumda bir get / set çifti haklı çıkar.

Bu, daha fazla bağlam olmadan nesnel olarak belirlenemez. go_shopping()Örneğiniz başka bir yerde bir yöntem içeriyor . Bu ne olursa Fridgeo mu daha içindir değil ihtiyaç getya setne ihtiyacı olduğunu Fridge.go_shopping(). Bu şekilde gereksinimlerden türetilmiş bir yönteminiz olur, ihtiyacı olan tüm "veriler" yereldir ve sadece ince örtülü bir veri yapısı yerine gerçek davranışınız olur .

Unutmayın, jenerik, tekrar kullanılabilir bir yapı oluşturmuyorsunuz Fridge. Sadece Fridgegereksinimleriniz için bir bina inşa ediyorsunuz. Yapılması gerekenden daha fazlasını yapmak için harcanan her çaba aslında boşa harcanıyor.


10
Getters and setters break encapsulation every single time- Bu benim zevkime göre biraz fazla ifade edildi. Yöntemler (alıcılar ve ayarlayıcılar dahil) kapılar bir konserde olduğu gibi aynı amaca sahiptir: mekandan düzenli olarak giriş ve çıkışa izin verirler.
Robert Harvey

8
"Harfler ve ayarlayıcılar tanımı gereği her seferinde kapsüllemeyi kesiyor" - hangi tanımla? Ben de bununla ilgili bir sorunum var, çünkü getters ve setters diğer kamu üyeleri gibi genel arayüzün sadece bir parçası; yalnızca tasarım gereği içsel olarak kabul edilen uygulama ayrıntılarını (yani programcının (veya bir ekibin kararı)) ortaya çıkarmaları durumunda kapsüllemeyi keserler . Alıcıların ve ayarlayıcıların çoğu zaman gelişigüzel bir şekilde eklenmesi, kuplaj kontrolünün sonradan düşünülmesi ile tamamen başka bir konudur.
Filip Milovanović

2
@ FilipMilovanović Fuar noktası. Yanıtta belirttiğim gibi, nesne kapsüllemelerini gizlemek için "kapsülleme" kullanılır (== nesne durumu == örnek değişkenleri). Harfler ve ayarlayıcılar nesne içlerini yayınlar . Dolayısıyla bu tanımlarla sürekli çatışma içerisindedirler. Şimdi, bazen olsun biz ihtiyacımız kapsülleme ayrı ele alınmalıdır farklı bir konu olduğunu kırmak için. Açıkça söylemek gerekirse, ayarlayıcıların / alıcıların her zaman kapsüllemeyi kırdıklarını söyleyerek, eğer yardımcı olursa, her zaman "yanlış" demiyorum.
Robert Bräutigam

5
alıcılar ve ayarlayıcılar "kapsüllemeyi her zaman tam anlamıyla kırmaz". Mektuplar ve ayarlayıcılar genellikle doğrudan altındaki üyelere atıfta bulunmaz, bir tür işlem gerçekleştirmez veya yalnızca özel olarak tanımlanır, yalnızca alıcıya sahip olabilirsiniz veya yalnızca ayarlayıcıya sahip olabilirsiniz. Alıcı ve ayarlayıcılar üye erişiminden başka bir şey yapmadığında ve her ikisi de aynı alanlar için tanımlandığında kapsüllemeyi keser. ABI'leri / API'leri dahili değişikliklerle kırmak istemeyen ve istemci yeniden derlemesinden kaçınmak istemeyen kütüphane koruyucular için bile bu gerekli olabilir.
whn

4
Tamam, alıcılar ve pasör sadece% 99 oranında kapsülleme kırmak. Mutlu? Ve, kapsüllenmiş nesnenin türünü ortaya çıkararak, kesinlikle kapsüllemeyi bozarlar. Bir kez sahip public int getFoo()olduğunuzda, pratikte başka bir türe geçmek neredeyse imkansızdır.
user949300

3

Neredeyse bunların hepsi kapsüllemenin temel bir yanlış anlaşılmasını ve nasıl uygulandığını göstermektedir.

Kapsülleme işlemini kırdığınız ilk yanıt yanlıştır. Uygulamanızın arttırma / azaltma veya ekleme / çıkarma yerine buzdolabındaki peynir değerini ayarlaması gerekebilir. Ayrıca, ne diyor olursanız olun, özniteliklere erişme ve / veya değiştirme gereksiniminiz varsa, bunları sağlayarak kapsüllemeyi kırmazsınız, anlambilim değildir. Son olarak, kapsülleme gerçekten "gizleme" ile ilgili değildir, sınıfın dışında olması ya da manipüle edilmesi gerekmeyen durum ve değerlere erişimi kontrol etmek ve buna gerek duyulanlara vermek ve dahili olarak sunulan görevi yerine getirmekle ilgilidir.

Bir alıcı veya ayarlayıcı, bir değer almak veya ayarlamak için meşru bir ihtiyaç olduğunda kapsüllemeyi kesmez. Bu yüzden yöntemler herkese açık hale getirilebilir.

Kapsülleme, verileri ve bu verileri doğrudan tek bir mantıksal yerde, sınıfta değiştirmeye yönelik yöntemlerle ilgilidir.

Bu özel durumda, uygulamada peynir değerinin değiştirilmesine açıkça ihtiyaç vardır. Bunun nasıl yapıldığına bakılmaksızın, yöntemler sınıfta kapsüllendiği sürece get / set veya add / remove ile nesne yönelimli stili izliyorsunuz.

Açıklığa kavuşturmak için, yöntem adı veya mantıksal yürütme ne olursa olsun erişim sağlayarak kapsüllemenin nasıl bozulduğuna bir örnek vereceğim.

Diyelim ki buzdolabınızın "kullanım ömrü" var, buzdolabı artık çalışmaya başlamadan önce sadece birtakım keneler (tartışma uğruna buzdolabı tamir edilemez). Mantıksal olarak, bir kullanıcının (veya uygulamanızın geri kalanının) bu değeri değiştirmesi mümkün değildir. Özel olmalı. Yalnızca "isWorking" olarak bilinen farklı bir genel özellik söylenerek görülebilir. Ömrü sona erdiğinde, dahili buzdolabı setleri yanlış olarak çalışır.

Geri sayım ömrünün yürütülmesi ve isWorking anahtarının çevrilmesi tamamen buzdolabının içindedir, dışarıdaki hiçbir şey işlemi etkileyemez / yapamaz. isÇalışma yalnızca görünür olmalıdır, bu nedenle bir alıcı kapsüllemeyi bozmaz. Ancak, ömür boyu sürecin öğeleri için erişimcilerin eklenmesi kapsüllemenizi bozacaktır.

Çoğu şey gibi, kapsüllemenin tanımı da gerçek değildir, görecelidir. X'i sınıf dışında görebilmeniz gerekir mi? Y'yi değiştirebilmeniz gerekir mi? Bu sınıfta nesneniz için geçerli olan her şey mi yoksa işlevsellik birden fazla sınıfa mı yayılmış?


Buna pragmatik olarak bakalım. Kodun bu şekilde tasarlanması veya "meşru" bir neden olması durumunda kapsüllemenin bozuk olmadığını söylüyorsunuz . Bu temelde hiçbir zaman kapsüllemenin bozulduğunu asla söyleyemeyeceğimiz anlamına gelir, çünkü geliştiricinin yalnızca bu şekilde "amaçladığını" veya "meşru" bir nedeni olduğunu söylemek zorundadır. Yani bu tanım temelde işe yaramaz, değil mi?
Robert Bräutigam

Hayır, kapsüllemenin erişim sağlayarak kırılmadığını söylüyorum. Ve bir programcının söylediği şeyle ilgisi yoktur, ancak uygulamanın ihtiyaçları nelerdir. Bir uygulamanın nesneleri manipüle etmek için erişimi olması gerekir, kapsülleme erişimi kontrol etmekle ilgilidir. Bir uygulamanın bir nesnenin özniteliğini "ayarlaması" gerekebilir, ancak bu "küme" işlemini gerçekleştirmek için gereken mantık ve / veya hesaplamalar nesne sınıfında kapsüllenmelidir.
user343330

Bence bu temelde farklı olduğumuz yer, diyorsunuz ki: "Bir uygulamanın bir nesnenin niteliğini" ayarlaması gerekebilir ... ". Ben öyle düşünmüyorum. Bir öznitelik ayarlamayı veya almayı içeren bir tasarım seçmek geliştiriciye bağlıdır. Bu bir seçim! Bir şeyi kodlamanın birçok yolu vardır, bunların hepsi örnek değişken değerlerini almayı veya ayarlamayı içermez.
Robert Bräutigam

Olabilir ... Genellikle tasarım, bir programcı tarafından seçilip seçilmediği iş ortamına dayanarak bir ihtiyacı karşılamaya dayanır. Her iki durumda da, uygulamanın bir nesnenin parçası olan bir değeri manipüle etmek için temel bir ihtiyacı varsa, bu işlevselliği bir şekilde erişilebilir hale getirmeniz gerekir. İş yapmak için bir giriş noktası sağlamak kapsüllemeyi bozmaz. Bir satış uygulaması alın. Bir noktada işleminizin vergi hesaplaması gerekir, bunu işlem nesnesinde kapsüllenmiş olarak tutacaktır, ancak uygulama işlemi
bildirebilmelidir. CalcTax

Ayarlayıcılar, sadeliklerinden dolayı kötü örneklerdir, bir nesne özniteliğinin, işi yapan ve sonra object.attribute = x diyerek sınıf dışında bir şeyle güncellenmesine neden olan çok daha fazla iş yapan bir işlev açısından düşünün. Birincisi uygun erişimi sağlarken iyi kapsülleme, ikincisi değildir. Alıcılara gelince, uygulamanın nesne sınıfında bulunamayan başka bir şey yapmak için bir nesnenin bu parçasını bilmesi gerekir mi? evet ise, teşhir etmek kapsüllemenizi bozmaz. eğer
hayırsa

1

Sadece bir yöntemi yeniden adlandırmak değil. İki yöntem farklı şekilde çalışır.

(Bunu aklında hayal et)

get_cheese ve set_cheese peynirleri ortaya çıkarır. putCheese () ve takeCheese () peyniri gizli tutar ve onu yönetmeye özen gösterir ve kullanıcıya bununla başa çıkma yolu verir. Gözlemci peyniri görmüyor, sadece onu işlemek için iki yöntem görüyor.

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.