Terminoloji: Dilin yapısına referans alırız interface
olarak arayüzü ve bir tür ya da nesnesi olarak arayüzüne yüzeyi (daha iyi bir terim eksikliği için).
Gevşek bağlantı, bir nesnenin beton tipi yerine soyutlamaya bağlı olmasıyla elde edilebilir.
Doğru.
Bu, iki ana nedenden dolayı gevşek bağlantıya izin verir: 1 - soyutlamaların beton tiplerinden daha az değişme olasılığı vardır, bu da bağımlı kodun kırılma olasılığının daha düşük olduğu anlamına gelir. 2 - çalışma zamanında farklı beton türleri kullanılabilir, çünkü hepsi soyutlamaya uyar. Yeni beton türleri daha sonra mevcut bağımlı kodu değiştirmeye gerek kalmadan eklenebilir.
Pek doğru değil. Mevcut diller genellikle bir soyutlamanın değişeceğini öngörmemektedir (bununla başa çıkmak için bazı tasarım modelleri olmasına rağmen). Genel şeylerden özelliklerini ayırmak olduğunu soyutlama. Bu genellikle bir soyutlama katmanı ile yapılır . Bu katman, bu soyutlama üzerine inşa edilen kodu kırmadan diğer bazı spesifikasyonlara değiştirilebilir - gevşek bağlantı elde edilir. OOP olmayan örnek: Bir sort
rutin, sürüm 1'deki Quicksort'tan sürüm 2'deki Tim Sort'a değiştirilebilir. Bu nedenle, yalnızca sıralanan sonuca (yani sort
soyutlamaya dayanan ) kod gerçek sıralama uygulamasından ayrılır.
Yukarıda yüzey olarak adlandırdığım şey, soyutlamanın genel kısmıdır . Şimdi OOP'ta bir nesnenin bazen birden fazla soyutlamayı desteklemesi gerekir. Oldukça optimal olmayan bir örnek: Java java.util.LinkedList
, hem List
“sıralı, dizine eklenebilir koleksiyon” soyutlamasıyla ilgili Queue
arayüzü destekler ve (kaba terimlerle) “FIFO” soyutlamasıyla ilgili arayüzü destekler .
Bir nesne birden fazla soyutlamayı nasıl destekleyebilir?
C ++ arayüze sahip değildir, ancak çoklu kalıtım, sanal yöntemler ve soyut sınıflara sahiptir. Daha sonra bir soyutlama, sanal yöntemleri tanımlayan, ancak sanal yöntemleri tanımlamayan soyut bir sınıf (yani hemen somutlaştırılamayan bir sınıf) olarak tanımlanabilir. Bir soyutlamanın özelliklerini uygulayan sınıflar, o soyut sınıftan miras alabilir ve gerekli sanal yöntemleri uygulayabilir.
Buradaki sorun, çoklu kalıtım, sınıfların bir yöntem uygulaması (MRO: yöntem çözüm sırası) için aranma sırasının “çelişkilere” yol açabileceği elmas sorununa yol açabilmesidir. Bunun iki yanıtı var:
Aklı başında bir emir tanımlayın ve mantıklı olarak doğrusallaştırılamayan emirleri reddedin. C3 MRO oldukça mantıklı ve iyi çalışıyor. 1996 yılında yayımlandı.
Kolay rotayı takip edin ve birden fazla mirası reddetme
Java ikinci seçeneği aldı ve tek davranışsal miras seçti. Bununla birlikte, bir nesnenin birden fazla soyutlamayı destekleme yeteneğine hala ihtiyacımız var. Bu nedenle, yöntem tanımlarını desteklemeyen, yalnızca bildirimleri destekleyen arabirimler kullanılmalıdır.
Sonuç olarak, MRO açıktır (sırayla her bir üst sınıfa bakın) ve nesnemiz, herhangi bir sayıda soyutlama için birden fazla yüzeye sahip olabilir.
Bu oldukça tatmin edici değildir, çünkü çoğu zaman biraz davranış yüzeyin bir parçasıdır. Bir Comparable
arayüz düşünün :
interface Comparable<T> {
public int cmp(T that);
public boolean lt(T that); // less than
public boolean le(T that); // less than or equal
public boolean eq(T that); // equal
public boolean ne(T that); // not equal
public boolean ge(T that); // greater than or equal
public boolean gt(T that); // greater than
}
Bu çok kullanıcı dostudur (birçok uygun yöntemle güzel bir API), ancak uygulanması sıkıcıdır. Arayüzün cmp
diğer metotları sadece gerekli olan metot açısından otomatik olarak içermesini ve uygulamasını istiyoruz. Mixins , ama daha da önemlisi Özellikler [ 1 ], [ 2 ] bu problemi çoklu miras tuzaklarına düşmeden çözer.
Bu, bir özellik kompozisyonu tanımlanarak yapılır, böylece özellikler aslında MRO'da yer almaz - bunun yerine tanımlanan yöntemler uygulama sınıfında oluşturulur.
Comparable
Arayüz olarak Scala ifade edilebilir
trait Comparable[T] {
def cmp(that: T): Int
def lt(that: T): Boolean = this.cmp(that) < 0
def le(that: T): Boolean = this.cmp(that) <= 0
...
}
Bir sınıf bu özelliği kullandığında, diğer yöntemler sınıf tanımına eklenir:
// "extends" isn't different from Java's "implements" in this case
case class Inty(val x: Int) extends Comparable[Inty] {
override def cmp(that: Inty) = this.x - that.x
// lt etc. get added automatically
}
Böyle Inty(4) cmp Inty(6)
olur -2
ve Inty(4) lt Inty(6)
olur true
.
Birçok dilde bazı özellikler desteklenir ve “Metaobject Protokolü (MOP)” olan herhangi bir dilde ek özellikler bulunabilir. Son Java 8 güncelleştirmesi, özelliklere benzer varsayılan yöntemler ekledi (arabirimlerdeki yöntemlerin geri dönüş uygulamaları olabilir, böylece bu yöntemleri uygulamak için sınıfların uygulanması isteğe bağlıdır).
Ne yazık ki, özellikler oldukça yeni bir buluştur (2002) ve bu nedenle daha büyük ana akım dillerde oldukça nadirdir.