Soyut sınıf ve Java'da Arayüz


88

Bana bir soru soruldu, cevabımın burada gözden geçirilmesini istedim.

S: Hangi senaryoda, arayüz (ler) i uygulamak yerine soyut bir sınıfı genişletmek daha uygundur?

C: Şablon yöntem tasarım modelini kullanıyorsak.

Doğrumuyum ?

Soruyu net bir şekilde ifade edemediysem özür dilerim.
Soyut sınıf ve arayüz arasındaki temel farkı biliyorum.

1) Gereksinim, belirli bir işlem için her alt sınıfta aynı işlevselliği uygulamamız (yöntemi uygulama) ve diğer bazı işlemler için farklı işlevsellik (yalnızca yöntem imzaları) uygulamamız gerektiğinde soyut sınıf kullanın

2) imzayı aynı (ve uygulamayı farklı) olarak koymanız gerekiyorsa arabirimi kullanın, böylece arabirim uygulamasına uyabilirsiniz.

3) en fazla bir soyut sınıfı genişletebiliriz, ancak birden fazla arayüz uygulayabiliriz

Soruyu tekrarlayarak: Yukarıda belirtilenlerin dışında, özellikle soyut sınıfı kullanmamız gereken başka senaryolar var mı (bir tanesi, şablon yöntem tasarım modelinin kavramsal olarak sadece buna dayandığını görüyor)?

Arayüz ve Soyut sınıf

Bu ikisi arasında seçim yapmak gerçekten ne yapmak istediğinize bağlıdır, ancak neyse ki bizim için Erich Gamma bize biraz yardımcı olabilir.

Her zaman olduğu gibi, bir değiş tokuş vardır, bir arayüz size temel sınıfa göre özgürlük verir, soyut bir sınıf size daha sonra yeni yöntemler ekleme özgürlüğü verir . - Erich Gamma

Sen gidip diğer bir çok şey değiştirmek zorunda kalmadan bir Arabirimi değiştiremezsiniz tek yolu bu her zaman iyi bir şey olmayabilir yepyeni Arayüz oluşturmak olacaktır kaçınmak için, kodunuzda.

Abstract classesöncelikle yakından ilişkili nesneler için kullanılmalıdır. Interfacesilgisiz sınıflar için ortak işlevsellik sağlamada daha iyidir.




Bu kopya değil. OP, bir arayüz uygulamak yerine soyut sınıfın ne zaman genişletileceğini bilmek ister . Ne zaman soyut sınıf veya arayüz yazacağını bilmek istemiyor. Soyut sınıfı ve arayüzü zaten yazılmış. Hd, genişletilip uzatılmayacağını bilmek istiyor.
Shiplu Mokaddim

1
@ shiplu.mokadd.im Farkı olmayan bir ayrımdır. Soyut bir sınıfı genişletmeden kullanamazsınız. Buradaki nitelemeniz tamamen anlamsız görünüyor.
user207421

Yanıtlar:


87

Arayüzler Ne Zaman Kullanılmalı

Bir arayüz, birisinin arayüzünüzü uygulamak için sıfırdan başlamasına veya arayüzünüzü orijinal veya birincil amacı arayüzünüzden oldukça farklı olan başka bir kodda uygulamasına izin verir. Onlar için arayüzünüz sadece tesadüfi, paketinizi kullanabilmek için kodlarına eklenmesi gereken bir şey. Dezavantajı, arayüzdeki her yöntemin halka açık olması gerektiğidir. Her şeyi ifşa etmek istemeyebilirsiniz.

Abstract sınıfları Ne Zaman Kullanılmalı

Soyut bir sınıf, aksine, daha fazla yapı sağlar. Genellikle bazı varsayılan uygulamaları tanımlar ve tam bir uygulama için yararlı bazı araçlar sağlar. İşin püf noktası, onu kullanan kodun sınıfınızı temel olarak kullanması gerektiğidir. Paketinizi kullanmak isteyen diğer programcılar kendi sınıf hiyerarşilerini bağımsız olarak zaten geliştirdiyse, bu oldukça rahatsız edici olabilir. Java'da, bir sınıf yalnızca bir temel sınıftan miras alabilir.

İkisi Ne Zaman Kullanılmalı

Her iki dünyanın en iyisini, bir arayüz ve soyut bir sınıf sunabilirsiniz. Uygulayıcılar, eğer seçerlerse sizin soyut sınıfınızı görmezden gelebilir. Bunu yapmanın tek dezavantajı, yöntemleri arayüz adlarıyla çağırmak, onları soyut sınıf adlarıyla çağırmaktan biraz daha yavaştır.


Bence OP, bir arayüz uygulamak yerine soyut sınıfı ne zaman genişleteceğini bilmek istiyor
Shiplu Mokaddim

@ shiplu.mokadd.im Aslında OP çok özel bir soru sordu ve cevabı ya 'evet' ya da 'hayır'.
user207421

4
Haklısın. Ancak SO'da, uygun bir açıklama ile evet / hayır cevabı veriyoruz.
Shiplu Mokaddim

1
@ shiplu.mokadd.im Bunun size sorusunu yanlış ifade etmeniz için nasıl izin verdiğini anlamıyorum.
user207421

Sadece bu tek ifadeye dayanarak If we are using template method design patternsöyleyemeyiz YESveyaNO
DivineDesert

31

soruyu yineleyerek: yukarıda belirtilenlerin dışında, özellikle soyut sınıf kullanmamız gereken başka bir senaryo var (bir tanesi, şablon yöntem tasarım modelinin kavramsal olarak yalnızca buna dayandığıdır)

Evet, JAXB kullanıyorsanız. Arayüzleri sevmez. Ya soyut sınıflar kullanmalı ya da bu sınırlamayı jeneriklerle aşmalısınız.

Kişisel bir blog gönderisinden :

Arayüz:

  1. Bir sınıf birden çok arabirim uygulayabilir
  2. Bir arayüz hiçbir şekilde herhangi bir kod sağlayamaz
  3. Bir arayüz yalnızca genel statik son sabitleri tanımlayabilir
  4. Bir arabirim, örnek değişkenlerini tanımlayamaz
  5. Yeni bir yöntem eklemenin, sınıfların uygulanmasında dalgalanma etkileri vardır (tasarım bakımı)
  6. JAXB arayüzlerle başa çıkamaz
  7. Bir arabirim soyut bir sınıfı genişletemez veya uygulayamaz
  8. Tüm arayüz yöntemleri herkese açıktır

Genel olarak, sözleşmeleri tanımlamak için arayüzler kullanılmalıdır (nasıl başarılacağı değil, neye ulaşılacağı).

Soyut Sınıf:

  1. Bir sınıf en fazla bir soyut sınıfı genişletebilir
  2. Soyut bir sınıf kod içerebilir
  3. Soyut bir sınıf, hem statik hem de örnek sabitleri (son) tanımlayabilir
  4. Soyut bir sınıf, örnek değişkenleri tanımlayabilir
  5. Mevcut soyut sınıf kodunun değiştirilmesinin sınıfları genişletme üzerinde dalgalanma etkileri vardır (uygulama bakımı)
  6. Soyut bir sınıfa yeni bir yöntem eklemenin sınıfları genişletme üzerinde dalgalanma etkisi yoktur
  7. Soyut bir sınıf bir arabirim uygulayabilir
  8. Soyut sınıflar özel ve korumalı yöntemler uygulayabilir

(Kısmi) uygulama için soyut sınıflar kullanılmalıdır. API sözleşmelerinin uygulanması gereken yolu sınırlandırmak için bir araç olabilirler.


3
Arayüz # 8 için Java 8'de, defaultve staticyöntemleriniz de olabilir.
Acemi Kullanıcı


10

Burada pek çok harika cevap var, ancak sık sık BOTH arayüzlerini ve soyut sınıfları kullanmanın en iyi yol olduğunu görüyorum. Bu uydurma örneği düşünün:

Bir yatırım bankasında yazılım geliştiricisiniz ve bir pazara sipariş veren bir sistem oluşturmanız gerekiyor. Sizin arayüzü bir ticaret sistemi şeylerin çoğu genel bir fikir yakalar yapar ,

1) Trading system places orders
2) Trading system receives acknowledgements

ve bir arayüzde yakalanabilir, ITradeSystem

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

Artık satış masasında ve diğer iş kollarında çalışan mühendisler , mevcut uygulamalarına sipariş verme işlevi eklemek için sisteminizle arayüz oluşturmaya başlayabilir . Ve daha inşa etmeye bile başlamadın! Bu, arayüzlerin gücüdür.

Öyleyse devam edin ve hisse senedi tüccarları için bir sistem oluşturun ; Sisteminizin ucuz hisse senedi bulma özelliği olduğunu ve denemeye çok hevesli olduklarını duydular! Bu davranışı adı verilen bir yöntemle yakalıyorsunuz findGoodDeals(), ancak aynı zamanda piyasalara bağlanmakla ilgili birçok dağınık şey olduğunu da fark ediyorsunuz . Örneğin, bir SocketChannel,

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

Somut uygulamalar gibi bu dağınık yöntemlerin birçoğu olacak connectToMarket(), ama findGoodDeals()aslında tüm tüccarlar ilgilendi.

Şimdi burada soyut sınıflar devreye giriyor. Patronunuz, döviz tüccarlarının da sisteminizi kullanmak istediklerini size bildirir. Döviz piyasalarına baktığınızda, sıhhi tesisatın borsalarla neredeyse aynı olduğunu görüyorsunuz. Aslında, connectToMarket()döviz piyasalarına bağlanmak için kelimesi kelimesine yeniden kullanılabilir. Ancak findGoodDeals()para arenasında çok farklı bir kavramdır. Bu yüzden kod tabanını okyanusun öteki ucundaki döviz kurucusu çocuğa devretmeden önce, önce bir abstractsınıfa yeniden düzenleme findGoodDeals()yaparsınız,

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

Hisse senedi alım satım sisteminiz findGoodDeals()önceden tanımladığınız gibi uygular ,

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

ancak şimdi FX ustası çocuk, sadece findGoodDeals()para birimleri için bir uygulama sağlayarak kendi sistemini kurabilir ; soket bağlantılarını ve hatta arayüz yöntemlerini yeniden uygulaması gerekmez!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

Bir arabirime programlama güçlüdür, ancak benzer uygulamalar genellikle yöntemleri neredeyse aynı yollarla yeniden uygular. Soyut bir sınıf kullanmak, arayüzün gücünü korurken, yeniden yorumlamaları önler.

Not: Neden findGreatDeals()arayüzün bir parçası olmadığını merak edebilirsiniz . Arayüzün bir ticaret sisteminin en genel bileşenlerini tanımladığını unutmayın. Başka bir mühendis, iyi anlaşmalar bulmayı umursamadıkları TAMAMEN FARKLI bir ticaret sistemi geliştirebilir. Arayüz, satış masasının sistemlerine de arayüz vermesini garanti eder, bu nedenle arayüzünüzü "harika fırsatlar" gibi uygulama konseptleriyle karıştırmamak tercih edilir.


6

Soyut sınıflar mı yoksa arayüzler mi kullanmalısınız?

Bu ifadelerden herhangi biri sizin kullanım durumunuz için geçerliyse soyut sınıfları kullanmayı düşünün:

Birbiriyle yakından ilişkili birkaç sınıf arasında kod paylaşmak istiyorsunuz.

Soyut sınıfınızı genişleten sınıfların birçok ortak yöntemi veya alanı olmasını veya genel (korumalı ve özel gibi) dışında erişim değiştiriciler gerektirmesini beklersiniz.

Statik olmayan veya nihai olmayan alanları bildirmek istiyorsunuz. Bu, ait oldukları nesnenin durumuna erişebilen ve onu değiştirebilen yöntemler tanımlamanıza olanak tanır.

Bu ifadelerden herhangi biri sizin kullanım durumunuz için geçerliyse arayüz kullanmayı düşünün:

İlişkisiz sınıfların arayüzünüzü uygulamasını beklersiniz. Örneğin, Comparable ve Cloneable arayüzleri birçok ilgisiz sınıf tarafından uygulanır.

Belirli bir veri türünün davranışını belirtmek istiyorsunuz, ancak davranışını kimin uyguladığıyla ilgilenmiyorsunuz.

Birden çok tür mirasından yararlanmak istiyorsunuz.

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


4

Java 8 sürümüyle arayüze yeni yetenekler eklenmesiyle son üç yılda işler çok değişti.

Arayüzdeki oracle dokümantasyon sayfasından :

Arabirim, yalnızca sabitleri, yöntem imzalarını, varsayılan yöntemleri, statik yöntemleri ve iç içe geçmiş türleri içerebilen, sınıfa benzer bir başvuru türüdür . Yöntem gövdeleri yalnızca varsayılan yöntemler ve statik yöntemler için mevcuttur.

Sorunuzda aktardığınız gibi, soyut sınıf, iskelet yaratmanız gereken şablon yöntem kalıbı için en uygunudur. Arayüz burada kullanılamaz.

Arayüz yerine soyut sınıfı tercih etmek için bir husus daha:

Temel sınıfta uygulamanız yoktur ve sadece alt sınıfların kendi uygulamalarını tanımlaması gerekir. Durumu alt sınıflarla paylaşmak istediğiniz için arayüz yerine soyut sınıfa ihtiyacınız var.

Soyut sınıf, ilgili sınıflar arasında "bir" ilişki kurar ve arayüz, ilişkisiz sınıflar arasında "bir" özelliğe sahiptir .


Java-8 sürümünden önceki java dahil çoğu programlama dili için geçerli olan sorunuzun ikinci bölümü ile ilgili olarak

Her zaman olduğu gibi, bir değiş tokuş vardır, bir arayüz size temel sınıfla ilgili özgürlük verir, soyut bir sınıf size daha sonra yeni yöntemler ekleme özgürlüğü verir. - Erich Gamma

Kodunuzdaki diğer birçok şeyi değiştirmek zorunda kalmadan bir Arayüzü değiştiremezsiniz.

Soyut sınıfın yukarıdaki iki noktayla daha önce arayüz olmasını tercih ediyorsanız, varsayılan yöntemler arayüzlere güçlü yetenekler eklediğinden şimdi yeniden düşünmeniz gerekir.

Varsayılan yöntemler, kitaplıklarınızın arabirimlerine yeni işlevler eklemenize ve bu arabirimlerin eski sürümleri için yazılan kodla ikili uyumluluk sağlamanıza olanak tanır.

Arayüz ve soyut sınıf arasından birini seçmek için oracle dokümantasyon sayfası şunları alıntılayın:

Soyut sınıflar arayüzlere benzer. Bunları örnekleyemezsiniz ve bunlar, uygulama ile veya uygulama olmadan bildirilen bir yöntem karışımı içerebilir. Bununla birlikte, soyut sınıflarla, statik ve nihai olmayan alanları bildirebilir ve genel, korumalı ve özel somut yöntemleri tanımlayabilirsiniz.

Arabirimlerle, tüm alanlar otomatik olarak genel, statik ve nihaidir ve bildirdiğiniz veya tanımladığınız tüm yöntemler (varsayılan yöntemler olarak) geneldir. Ek olarak, soyut olsun veya olmasın yalnızca bir sınıfı genişletebilirsiniz, oysa istediğiniz sayıda arabirim uygulayabilirsiniz.

Daha fazla ayrıntı için bu ilgili sorulara bakın:

Arayüz ve Soyut Sınıf (genel OO)

Bir Arayüz ve Soyut sınıf arasındaki farkı nasıl açıklamalıydım?

Özetle: Denge artık arayüzlere doğru daha fazla eğiliyor .

Yukarıda belirtilenlerin dışında, özellikle soyut sınıfı kullanmamız gereken başka senaryolar var mı (bir tanesi, şablon yöntem tasarım modelinin kavramsal olarak yalnızca buna dayandığını görüyor)?

Bazı tasarım desenleri, Şablon yöntemi deseninden ayrı olarak soyut sınıfları (arabirimler üzerinden) kullanır.

Yaratma kalıpları:

Abstract_factory_pattern

Yapısal modeller:

Dekoratör_pattern

Davranış kalıpları:

Mediator_pattern


Bu: "Soyut sınıf kurar", "ilgili sınıflar arasında bir ilişki ve arabirim sağlar" ilgisiz sınıflar arasında bir yeteneğe sahiptir. "
Gabriel

3

Doğru değilsin Pek çok senaryo var. Bunu tek bir 8 kelimelik kurala indirgemek mümkün değil.


1
Gibi belirsiz olmadıkça; Mümkün
olduğunca

@PeterLawrey Evet, döngüsel argümanların sizi yavaşlatmasına izin vermeyin ;-)
user207421

Sonuçta bu "yığın taşması" dır. ;) Demek istediğim, daha basit arayüzü kullanabiliyorsanız, bunu yapın. Aksi takdirde, soyut bir sınıf kullanmaktan başka seçeneğiniz yoktur. Ben bunu çok karmaşık görmüyorum.
Peter Lawrey

bence daha yapıcı bir fikir verebilirsin. bazı temsili senaryolar hakkında konuşmak gibi /
Adams. H

3

En kısa cevap, uzat aradığınız işlevselliklerden bazıları zaten uygulandığında soyut sınıfı .

Arayüzü uygularsanız, tüm yöntemi uygulamanız gerekir. Ancak soyut sınıf için uygulamanız gereken yöntem sayısı daha az olabilir.

Gelen şablon tasarım deseni bir davranış tanımlanmış olmalıdır. Bu davranış, soyut olan diğer yöntemlere bağlıdır. Alt sınıf oluşturarak ve bu yöntemleri tanımlayarak, aslında ana davranışı tanımlarsınız. Arayüz hiçbir şeyi tanımlamadığı için temel davranış bir arayüzde olamaz, sadece bildirir. Yani bir şablon tasarım deseni her zaman soyut bir sınıfla birlikte gelir. Davranışın akışını sağlam tutmak istiyorsanız, soyut sınıfı genişletmelisiniz, ancak ana davranışı geçersiz kılmamalısınız.


Ek referans Saf Sanal Fonksiyon ilgili daha fazla analiz katacak Özet Sınıf & Arayüz Convergence'e , Pure virtual functions can also be used where the method declarations are being used to define an interface - similar to what the interface keyword in Java explicitly specifies. In such a use, derived classes will supply all implementations. In such a design pattern, the abstract class which serves as an interface will contain only pure virtual functions, but no data members or ordinary methods. Part (1/2)
Abhijeet

Kısım (2/2) Soyut Sınıf ve Arayüzün diverjansı yukarıdaki son satırda no data members or ordinary methods[Özet Sınıfında] açıklanmaktadır.
Abhijeet

3

Bence temel fark şu an interface can't contain non abstract methods while an abstract class can. Dolayısıyla, alt sınıflar ortak bir davranışı paylaşıyorsa, bu davranış süper sınıfta uygulanabilir ve böylece alt sınıflarda miras alınabilir.

Ayrıca "java'da yazılım mimarisi tasarım örnekleri" kitabından aşağıdakileri aktardım

"Java programlama dilinde çoklu kalıtım için destek yoktur. Bu, bir sınıfın yalnızca tek bir sınıftan miras alabileceği anlamına gelir. Bu nedenle, kalıtım yalnızca kesinlikle gerekli olduğunda kullanılmalıdır. Mümkün olduğunda, ortak davranışı gösteren yöntemler içinde bildirilmelidir. farklı uygulayıcı sınıfları tarafından uygulanacak bir Java arabiriminin biçimi. Ancak arabirimler, yöntem uygulamaları sağlayamama sınırlamasından muzdariptir. Bu, bir arabirimin her uygulayıcısının bir arabirimde bildirilen tüm yöntemleri, bunlardan bazıları yöntemler, işlevselliğin değişmez kısmını temsil eder ve tüm gerçekleyici sınıflarında tam olarak aynı uygulamaya sahiptir.Bu, fazlalık koda yol açar.Aşağıdaki örnek, bu tür durumlarda yedekli yöntem uygulamaları gerektirmeden Özet Üst Sınıf modelinin nasıl kullanılabileceğini gösterir. "


2

Soyut sınıflar, iki önemli açıdan arayüzlerden farklıdır

  • seçilen yöntemler için varsayılan uygulama sağlarlar (cevabınız kapsamındadır)
  • soyut sınıfların durumu (örnek değişkenleri) olabilir - bu nedenle, arayüzler yerine onları kullanmak isteyeceğiniz bir durum daha var

Arayüzlerin değişkenlere sahip olabileceğini tamamlardım ama bunlar varsayılan olarak nihai.
Tomasz Mularczyk

1

Bu iyi bir soru Bunların ikisi birbirine benzemiyor, ancak yeniden yazma gibi aynı nedenden dolayı kullanılabilir. Oluştururken en iyisi Arayüzü kullanmaktır. Sınıfa gelince, hata ayıklama için iyidir.


0

Abstract classes should be extended when you want to some common behavior to get extended. Soyut süper sınıf, ortak davranışa sahip olacak ve alt sınıfların uygulaması gereken soyut yöntemi / özel davranışı tanımlayacaktır.

Interfaces allows you to change the implementation anytime allowing the interface to be intact.


0

Bu benim anlayışım, umarım bu yardımcı olur

Soyut sınıflar:

  1. Devralınan üye değişkenlere sahip olabilir (arayüzlerde yapılamaz)
  2. Oluşturucular olabilir (arayüzler olamaz)
  3. Yöntemleri herhangi bir görünürlüğe sahip olabilir (ör: özel, korumalı, vb - oysa tüm arayüz yöntemleri geneldir)
  4. Tanımlanmış yöntemlere sahip olabilir (uygulama içeren yöntemler)

Arayüzler:

  1. Değişkenler olabilir, ancak hepsi genel statik son değişkenlerdir
    • statik kapsamla asla değişmeyen sabit değerler
    • statik olmayan değişkenler bir örnek gerektirir ve bir arabirimi başlatamazsınız
  2. Tüm yöntemler soyuttur (soyut yöntemlerde kod yoktur)
    • tüm kodun, belirli arabirimi uygulayan sınıfta gerçekten yazılması gerekir

0

Özet ve arayüzün kullanımı:

Birinin "İlişkisi Var" ve diğerinin "İlişkisi Var"

Varsayılan özellikler soyut olarak ayarlanmıştır ve ekstra özellikler arayüz aracılığıyla ifade edilebilir.

Örnek: -> İnsanlarda yemek yemek, uyumak vb. Bazı varsayılan özelliklerimiz vardır, ancak eğer herhangi birinin yüzme, oyun vb. Gibi başka müfredat etkinlikleri varsa bunlar Arayüz ile ifade edilebilir.

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.