Enkapsülasyonun bir amacı vardır, fakat aynı zamanda kötüye de kullanılabilir.
Düzinelerce (yüzlerce olmasa) alan içeren sınıflara sahip Android API gibi bir şey düşünün. Bu alanların kullanılması, API tüketicisinin gezinmesini ve kullanılmasını zorlaştırır; ayrıca, kullanıcının nasıl kullanılması gerektiği ile çelişebilecek alanlarla ne isterse yapabileceği konusunda yanlış bir fikir verir. Bu yüzden, kapsülleme, bu anlamda sürdürülebilirlik, kullanılabilirlik, okunabilirlik ve çılgın böceklerden kaçınmak için mükemmeldir.
Öte yandan, tüm alanların ortak olduğu C / C ++ 'dan bir yapı gibi POD veya düz eski veri türleri de yararlı olabilir. Lombok'taki @tata notları tarafından üretilenler gibi işe yaramaz alıcı / ayarlayıcılara sahip olmak, "Kapsülleme modelini" korumanın bir yoludur. Java’daki alıcı / ayarlayıcıları “işe yaramaz” olarak almamızın birkaç nedeni, yöntemlerin bir sözleşme sunmasıdır .
Java'da, bir arayüzde alanlar olamaz, bu nedenle bu arayüzün tüm uygulayıcılarının sahip olduğu ortak bir özellik belirtmek için alıcıları ve ayarlayıcıları kullanırsınız. Kotlin veya C # gibi daha yeni dillerde, mülk kavramını belirleyiciyi ve alıcıyı ilan edebileceğiniz alanlar olarak görüyoruz. Sonunda, işe yaramaz alıcılar / alıcılar, Oracle'a özellikler eklemediği sürece Java'nın yaşamak zorunda olduğu daha fazla eskidir. Örneğin, JetBrains tarafından geliştirilen başka bir JVM dili olan Kotlin, temel olarak @tata anonsunun Lombok'ta yaptığı şeyi yapan veri sınıflarına sahiptir.
Ayrıca burada birkaç örnek:
class DataClass
{
private int data;
public int getData() { return data; }
public void setData(int data) { this.data = data; }
}
Bu kötü bir kapsülleme durumudur. Alıcı ve alıcı, etkili bir şekilde işe yaramaz. Kapsülleme çoğunlukla kullanılır, çünkü bu Java gibi dillerde standarttır. Kod bazında tutarlılığı korumanın yanı sıra aslında yardımcı olmuyor.
class DataClass implements IDataInterface
{
private int data;
@Override public int getData() { return data; }
@Override public void setData(int data) { this.data = data; }
}
Bu iyi bir kapsülleme örneğidir. Kapsülleme bir sözleşmeyi uygulamak için kullanılır, bu durumda IDataInterface. Bu örnekte kapsüllemenin amacı, bu sınıftaki tüketicinin arayüz tarafından sağlanan yöntemleri kullanmasını sağlamaktır. Alıcı ve ayarlayıcı hiçbir şey fantezi yapmasa da, DataClass ve diğer IDataInterface uygulayıcıları arasında ortak bir özellik tanımladık. Böylece böyle bir yöntem olabilir:
void doSomethingWithData(IDataInterface data) { data.setData(...); }
Şimdi, kapsülleme hakkında konuşurken sözdizimi sorununa da değinmenin önemli olduğunu düşünüyorum. Çoğu zaman insanların kapsüllemenin kendisinden ziyade kapsüllemeyi zorlamak için gerekli olan sözdiziminden şikayet ettiğini görüyorum. Akla gelen bir örnek Casey Muratori'dendir ( burada rantını görebilirsiniz ).
Kapsülleme kullanan ve pozisyonunu 1 birim hareket ettirmek isteyen bir oyuncu sınıfınız olduğunu varsayalım. Kod şöyle görünür:
player.setPosX(player.getPosX() + 1);
Kapsülleme olmadan şöyle görünürdü:
player.posX++;
Burada, enkapsülasyonların ek faydaları olmadan daha fazla yazmaya yol açtığını ve bunun birçok durumda doğru olabileceğini, ancak bir şeyin farkına varabileceğini savunuyor. Argüman, kapsülleme değil, sözdizimine karşıdır. Kapsülleme kavramına sahip olmayan C dillerinde bile, genellikle '_' veya 'my' ile önceden belirlenmiş veya eklenmiş yapılardaki değişkenleri görürsünüz ya da API tüketicileri tarafından, sanki API tüketicileri tarafından kullanılmaması gerektiğini belirtmek için ne olursa olsun. özel.
Maddenin gerçeği, kapsülleme, kodun daha sürdürülebilir ve kullanımı kolay olmasına yardımcı olabilir. Bu sınıfı düşünün:
class VerticalList implements ...
{
private int posX;
private int posY;
... //other members
public void setPosition(int posX, int posY)
{
//change position and move all the objects in the list as well
}
}
Değişkenler bu örnekte halka açıksa, bu API'nin bir tüketicisi posX ve posY ne zaman ve ne zaman setPosition () kullanılacağıyla ilgili olarak karıştırılır. Bu ayrıntıları gizleyerek tüketicinin API'nizi sezgisel bir şekilde daha iyi kullanmasına yardımcı olursunuz.
Sözdizimi olsa da birçok dilde bir sınırlamadır. Bununla birlikte, yeni diller bize publice üyelerinin güzel sözdizimini ve enkapsülasyonun yararlarını sağlayan özellikler sunar. MSVC kullanıyorsanız, özellikleri C #, Kotlin'de, hatta C ++ 'da bulacaksınız. Kotlin'de bir örnek.
sınıf VerticalList: ... {var posX: Int set (x) {alan = x; ...} var posY: Int (y) ayarlayın {field = y; ...}}
Burada Java örneğindekiyle aynı şeyi başardık, ancak posX ve posY komutlarını ortak değişkenlermiş gibi kullanabiliriz. Değerlerini değiştirmeye çalıştığımda, set () setçığının gövdesi çalıştırılacak.
Örneğin Kotlin'de bu, alıcıların, ayarlayıcıların, hashcode'un, eşit değerlerin ve toString'in uygulandığı Java Bean'in eşdeğeri olacaktır:
data class DataClass(var data: Int)
Bu sözdiziminin Java Bean'i bir satırda yapmamıza izin verdiğine dikkat edin. Java gibi bir dilin kapsülleme uygulamasındaki sorunu doğru bir şekilde fark ettiniz, ancak bu Java'nın kapsüllemenin kendisinin hatası değil.
Alıcıları ve ayarlayıcıları oluşturmak için Lombok'un @ Verisini kullandığını söyledin. Adı, @ Verisi dikkat edin. Çoğunlukla yalnızca veri depolayan ve seri hale getirilmiş ve seri hale getirilmiş veri sınıflarında kullanılmak içindir. Bir oyundan tasarruf dosyası gibi bir şey düşünün. Ancak diğer senaryolarda, bir UI öğesinde olduğu gibi, en kesin şekilde ayarlayıcıları istersiniz, çünkü yalnızca bir değişkenin değerini değiştirmek beklenen davranışı elde etmek için yeterli olmayabilir.
"It will create getters, setters and setting constructors for all private fields."
- Bu aracı tanımladığınız gibi , kapsülleme koruyor gibi geliyor . (En azından gevşek, otomatik, biraz anemik model anlamında). Sorun tam olarak nedir?