Yanıtlar:
İki fark düşünebilirim
Scala'da Programlama'da "Sürekli mi yoksa sürekli mi?" bu soruyu ele alıyor. 1st ed çevrimiçi kullanılabilir olduğundan, burada her şeyi alıntı yapmanın sorun olmadığını umuyorum. (Herhangi bir ciddi Scala programcısı kitabı satın almalıdır):
Yeniden kullanılabilir bir davranış koleksiyonu uyguladığınızda, bir özellik mi yoksa soyut bir sınıf mı kullanmak istediğinize karar vermeniz gerekir. Kesin bir kural yoktur, ancak bu bölüm dikkate alınması gereken birkaç kural içermektedir.
Davranış tekrar kullanılmayacaksa , onu somut bir sınıf haline getirin. Sonuçta yeniden kullanılabilir bir davranış değildir.
İlişkisiz birden çok sınıfta yeniden kullanılabiliyorsa , onu bir özellik haline getirin. Sınıf hiyerarşisinin farklı bölümlerine yalnızca özellikler karıştırılabilir.
Java kodundan miras almak istiyorsanız soyut bir sınıf kullanın. Kodlu özelliklerin Java analogu yakın olmadığından, Java sınıfındaki bir özellikten miras almak garip olma eğilimindedir. Bu arada, bir Scala sınıfından miras almak bir Java sınıfından miras almak gibidir. Bir istisna olarak, yalnızca soyut üyelere sahip bir Scala özelliği doğrudan bir Java arayüzüne dönüşür, bu nedenle Java kodunun miras almasını bekleseniz bile bu özellikleri tanımlamaktan çekinmeyin. Java ve Scala ile birlikte çalışma hakkında daha fazla bilgi için Bölüm 29'a bakın.
Derlenmiş biçimde dağıtmayı planlıyorsanız ve dış grupların kendisinden miras alan sınıflar yazmasını bekliyorsanız, soyut bir sınıf kullanmaya eğilebilirsiniz. Sorun, bir özellik bir üye kazandığında veya kaybettiğinde, kendisinden miras kalan tüm sınıfların, değişmemiş olsalar bile yeniden derlenmesi gerektiğidir. Dış istemciler davranıştan miras almak yerine yalnızca davranışı çağırırlarsa, bir özellik kullanmak iyidir.
Verimlilik çok önemliyse , sınıf kullanmaya yönelin. Çoğu Java çalışma zamanı, bir sınıf üyesinin sanal yöntem çağrılmasını bir arabirim yöntemi çağrısından daha hızlı bir işlem yapar. Özellikler arayüzlere derlenir ve bu nedenle hafif bir performans yükü ödeyebilir. Bununla birlikte, bu seçimi sadece söz konusu özelliğin bir performans darboğazı oluşturduğunu ve bunun yerine bir sınıf kullanmanın aslında sorunu çözdüğüne dair kanıtınız varsa yapmalısınız.
Hala bilmiyorsanız , yukarıdakileri düşündükten sonra, bir özellik olarak yapmaya başlayın. Daha sonra istediğiniz zaman değiştirebilirsiniz ve genel olarak bir özellik kullanmak daha fazla seçeneği açık tutar.
@Mushtaq Ahmed'in belirttiği gibi, bir özellik bir sınıfın birincil kurucusuna iletilen herhangi bir parametreye sahip olamaz.
Başka bir fark, tedavisidir super
.
Sınıflar ve özellikler arasındaki diğer fark, sınıflarda
super
çağrıların statik olarak bağlı olmasına rağmen, özelliklerde dinamik olarak bağlı olmalarıdır. Eğer yazarsanızsuper.toString
bir sınıfta, sen çağrılır hangi yöntemin uygulanması iyi biliyorum. Ancak aynı özelliği bir özelliğe yazdığınızda, özelliği tanımladığınızda süper çağrı için çağrılacak yöntem uygulaması tanımsız olur.
Daha fazla ayrıntı için Bölüm 12'nin geri kalanına bakın.
Düzenleme 1 (2013):
Soyut sınıfların davranış biçiminde özelliklerle karşılaştırıldığında küçük bir fark vardır. Doğrusallaştırma kurallarından biri, sınıfların kalıtım hiyerarşisini koruduğu, bu da soyut sınıfları zincirde daha sonra itme eğilimi gösterirken, özellikler mutlu bir şekilde karıştırılabilir. Bazı durumlarda, aslında sınıf doğrusallaştırmasının ikinci konumunda olması tercih edilir bunun için soyut sınıflar kullanılabilir. Görmek . Scala'daki kısıtlayıcı sınıf doğrusallaştırması (mixin sırası) .
Düzenleme 2 (2018):
Scala 2.12 itibariyle, trait'in ikili uyumluluk davranışı değişmiştir. 2.12'den önce, bir özelliğin üye eklenmesi veya kaldırılması, sınıflar değişmemiş olsa bile, özelliği devralan tüm sınıfların yeniden derlenmesini gerektiriyordu. Bunun nedeni özelliklerin JVM'de kodlanma biçimidir.
Scala 2.12 itibariyle, özellikler Java arayüzlerine derlendiğinden, gereksinim biraz rahatladı. Özellik aşağıdakilerden herhangi birini yaparsa, alt sınıfları yine de yeniden derleme gerektirir:
- alanları tanımlama (
val
veyavar
bir sabit tamam -final val
sonuç türü olmadan)- çağrı
super
- gövdedeki başlatıcı ifadeleri
- bir sınıfı genişletmek
- sağ üst bölgede uygulamaları bulmak için doğrusallaştırmaya güvenmek
Ancak özellik yapmazsa, artık ikili uyumluluğu bozmadan güncelleyebilirsiniz.
If outside clients will only call into the behavior, instead of inheriting from it, then using a trait is fine
- Birisi buradaki farkın ne olduğunu açıklayabilir mi? extends
vs with
?
extends
ve arasında kesinlikle bir anlamsal fark yoktur with
. Tamamen sözdizimseldir. Birden fazla şablondan miras alırsanız, birincisi alır extend
, diğerleri alır , hepsi with
bu. with
Virgül olarak düşün class Foo extends Bar, Baz, Qux
.
Ne kadar değerli olursa olsun, Odersky ve arkadaşlarının Scala'daki Programlaması, şüpheniz olduğunda özellikleri kullanmanızı önerir. Daha sonra gerektiğinde bunları soyut sınıflara dönüştürebilirsiniz.
Birden fazla soyut sınıfı doğrudan genişletememeniz, ancak birden çok özelliği bir sınıfa karıştırabilmeniz dışında, bir özellikteki süper çağrılar dinamik olarak bağlı olduğundan (daha önce karıştırılmış bir sınıf veya özellikten bahsediyorsa) özelliklerin istiflenebilir olduğunu belirtmek gerekir. mevcut olan).
Thomas'ın Soyut Sınıf ve Özellik Arasındaki Farktaki cevabından :
trait A{
def a = 1
}
trait X extends A{
override def a = {
println("X")
super.a
}
}
trait Y extends A{
override def a = {
println("Y")
super.a
}
}
scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1@6e9b6a
scala> xy.a
Y
X
res0: Int = 1
scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1@188c838
scala> yx.a
X
Y
res1: Int = 1
Gelen Programlama Scala yazarlar soyut sınıflar klasik nesne yönelimli "is-a" ilişkisi özellikleri kompozisyonun bir Scala-yönlü iken yapmak söylüyorlar.
Soyut sınıflar davranış içerebilir - Yapıcı argümanlarıyla (bu özelliklerin yapamayacağı) parametreleştirilebilir ve çalışan bir varlığı temsil edebilir. Bunun yerine özellikler tek bir özelliği, tek bir işlevin arayüzünü temsil eder.
trait Enumerable
çok sayıda yardımcı işlevle tanımladığınızda , onlara davranış demezdim, sadece bir özellikle bağlantılı işlevler.