Arayüz ve Kalıtım: Her iki dünyanın en iyisi mi?


10

Arayüzleri 'keşfettim' ve onları sevmeye başladım. Bir arayüzün güzelliği, bir sözleşme olması ve bu sözleşmeyi yerine getiren herhangi bir nesne, arayüzün gerekli olduğu her yerde kullanılabilir.

Bir arabirimdeki sorun, sıradan özellikler için bir acı olan ve DRY'yi yenen varsayılan bir uygulamaya sahip olamamasıdır. Bu da iyidir, çünkü uygulamayı ve sistemi birbirinden ayırır. Elde kalıtım, daha sıkı bir bağlantı sağlar ve kapsülleme kırılma potansiyeline sahiptir.

Durum 1 (Özel üyelerle miras, iyi kapsülleme, sıkıca bağlı)

class Employee
{
int money_earned;
string name;

public:
 void do_work(){money_earned++;};
 string get_name(return name;);
};


class Nurse : public Employee: 
{
   public:
   void do_work(/*do work. Oops, can't update money_earned. Unaware I have to call superclass' do_work()*/);

};

void HireNurse(Nurse *n)
{
   nurse->do_work();
)

Durum 2 (sadece bir arayüz)

class IEmployee
{
     virtual void do_work()=0;
     virtual string get_name()=0;
};

//class Nurse implements IEmployee.
//But now, for each employee, must repeat the get_name() implementation,
//and add a name member string, which breaks DRY.

Durum 3: (her iki dünyanın en iyisi?)

Durum 1'e benzer . Ancak, (varsayımsal olarak) C ++ 'ın saf sanal olan yöntemler dışında geçersiz kılma yöntemlerine izin vermediğini düşünün .

Bu nedenle, Durum 1'de , do_work () geçersiz kılmak derleme zamanı hatasına neden olur. Bunu düzeltmek için do_work () öğesini saf sanal olarak ayarladık ve increment_money_earned () için ayrı bir yöntem ekledik. Örnek olarak:

class Employee
{
int money_earned;
string name;

public:
 virtual void do_work()=0;
 void increment_money_earned(money_earned++;);
 string get_name(return name;);
};


class Nurse : public Employee: 
{
   public:
   void do_work(/*do work*/ increment_money_earned(); ); .
};

Ama bunun bile sorunları var. Ya 3 ay sonra, Joe Coder bir Doktor Çalışanı oluşturur, ancak do_work () 'de increment_money_earned ()' i çağırmayı unutursa?


Soru:

  • Vaka 3 , Vaka 1'den daha üstün mü ? Bunun nedeni 'daha iyi kapsülleme' veya 'daha gevşek bir şekilde bağlanmış' ya da başka bir sebep mi?

  • Case 3 , DRY ile uyumlu olduğu için Case 2'den daha üstün mü ?


2
... soyut sınıfları mı yeniden keşfediyorsunuz?
ZJR

Yanıtlar:


10

Üst sınıfı çağırmayı unutma problemini çözmenin bir yolu, kontrolü üst sınıfa geri vermektir! Nasıl (ve derlemek;)) göstermek için ilk örnek jiggered. Ah, ben de farz do_work()içinde Employeeolması gerekiyordu virtualilk örnekteki.

#include <string>

using namespace std;

class Employee
{
    int money_earned;
    string name;
    virtual void on_do_work() {}

    public:
        void do_work() { money_earned++; on_do_work(); }
        string get_name() { return name; }
};

class Nurse : public Employee
{
    void on_do_work() { /* do more work. Oh, and I don't have to call do_work()! */ }
};

void HireNurse(Nurse* nurse)
{
    nurse->do_work();
}

Şimdi do_work()geçersiz kılınamaz. Eğer uzatmak istiyorsanız, üzerinde kontrol on_do_work()olan bunu yapmak zorunda do_work().

Bu, elbette, ikinci örneğinizdeki arayüzle de Employeegenişletilirse kullanılabilir. Seni doğru anlarsam, bu Vaka 3'ü yapar ama varsayımsal C ++ kullanmak zorunda kalmadan düşünüyorum! KURU ve güçlü bir kapsülleme var.


3
Ve bu da "şablon yöntemi" olarak bilinen tasarım modelidir ( en.wikipedia.org/wiki/Template_method_pattern ).
Joris Timmermans

Evet, bu Durum 3 uyumludur. Bu umut verici görünüyor. Ayrıntılı olarak inceleyecektir. Ayrıca, bu bir tür olay sistemidir. Bu 'desen' için bir isim var mı?
MustafaM

@MadKeithV bunun 'şablon yöntemi' olduğundan emin misiniz?
MustafaM

@illmath - evet, uygulama ayrıntılarının bir kısmını sanal korumalı / özel yöntemlere devreten sanal olmayan bir genel yöntemdir.
Joris Timmermans

@illmath Daha önce bir şablon yöntemi olarak düşünmemiştim ama bunun temel bir örnek olduğuna inanıyorum. Yazarı kendi adını hak ettiğine inandığı yerde okumak isteyebileceğiniz bu makaleyi buldum : Sanal Olmayan Arayüz
Deyim

1

Bir arabirimdeki sorun, sıradan özellikler için bir acı olan ve DRY'yi yenen varsayılan bir uygulamaya sahip olamamasıdır.

Kendi düşünceme göre, arayüzlerin varsayılan bir uygulama olmadan sadece saf yöntemlere sahip olması gerekir. Arayüzler bazı varlıklara nasıl erişileceğini gösterir, çünkü DRY ilkesini hiçbir şekilde bozmaz. Sadece referanslar için, burada DRY açıklamasına bakıyorum :
"Her bilgi parçasının bir sistem içinde tek, açık, yetkili bir temsili olmalıdır."

Öte yandan, SOLID size her sınıfın bir arayüze sahip olması gerektiğini söyler.

Vaka 3, Vaka 1'den daha üstün mü? Bunun nedeni 'daha iyi kapsülleme' veya 'daha gevşek bir şekilde bağlanmış' ya da başka bir nedenden mi?

Hayır, durum 3 durum 1'den daha üstün değildir. Fikrinizi telafi etmek zorundasınız. Varsayılan bir uygulamaya sahip olmak istiyorsanız bunu yapın. Saf bir yöntem istiyorsanız o zaman onunla devam et.

Ya 3 ay sonra, Joe Coder bir Doktor Çalışanı oluşturur, ancak do_work () 'de increment_money_earned ()' i çağırmayı unutursa?

Sonra Joe Coder, başarısız birim testlerini göz ardı etmek için hak ettiği şeyi almalıdır. Bu sınıfı test etti, değil mi? :)

40.000 kod satırı olabilecek bir yazılım projesi için en iyi durum hangisidir?

Bir beden herkese uymuyor. Hangisinin daha iyi olduğunu söylemek mümkün değil. Birinin diğerinden daha uygun olacağı bazı durumlar vardır.

Belki kendi tasarımınızı icat etmek yerine bazı tasarım modellerini öğrenmelisiniz .


Sanal olmayan arayüz tasarım deseni aradığınızı fark ettim , çünkü durum 3 sınıfınız böyle görünüyor.


Yorum için teşekkürler. Niyetimi daha açık hale getirmek için Vaka 3'ü güncelledim.
MustafaM

1
Seni burada -1 yapmam gerekecek. Tüm arabirimlerin saf olması veya tüm sınıfların bir arabirimden miras alması gerektiğini söylemek için hiçbir neden yoktur .
DeadMG

@DeadMG ISS
BЈовић

@VJovic: SOLID ile "Her şey bir arayüzden miras almalı" arasında büyük bir fark var.
DeadMG

"Bir beden herkese uymuyor" ve "bazı tasarım modellerini öğren" doğrudur - cevabınızın geri kalanı, bir bedenin herkese uymadığı yönündeki önerilerinizi ihlal eder.
Joris Timmermans

0

Arayüzler C ++ 'da varsayılan uygulamalara sahip olabilir. Bir işlevin varsayılan bir uygulamasının yalnızca diğer sanal üyelere (ve bağımsız değişkenlere) bağlı olmadığını, dolayısıyla herhangi bir bağlantıyı artırmayacağını söyleyen hiçbir şey yoktur.

Durum 2 için, DRY burada yerini alıyor. Kapsülleme, programınızı değişik uygulamalardan, değişikliklerden korumak için vardır, ancak bu durumda farklı uygulamalarınız yoktur. Yani YAGNI kapsülleme.

Aslında, çalışma zamanı arayüzleri genellikle derleme zamanı eşdeğerlerinden daha düşük kabul edilir. Derleme zamanı durumda, olabilir hem davayı 1 ve sayısız başka avantajları söz değil aynı bundle- davayı 2. Ya da çalışma zamanında bile Employee : public IEmployee, aynı avantajı etkili bir şekilde yapabilirsiniz . Bu tür şeylerle başa çıkmanın birçok yolu vardır.

Case 3: (best of both worlds?)

Similar to Case 1. However, imagine that (hypothetically)

Okumayı bıraktım. YAGNI. C ++, C ++ 'dır ve Standartlar komitesi hiçbir zaman mükemmel nedenlerle böyle bir değişiklik uygulayamaz.


"Farklı uygulamalarınız yok" diyorsunuz. Ama ben yaparım. Çalışanın Hemşire uygulamasına sahibim ve daha sonra başka uygulamalara da sahip olabilirim (Doktor, Kapıcı vb.). Ne demek istediğimi daha net hale getirmek için Vaka 3'ü güncelledim.
MustafaM

@illmath: Ama başka uygulamanız yok get_name. Önerilen uygulamalarınızın tümü, aynı uygulamasını paylaşacaktır get_name. Ayrıca, dediğim gibi, seçim yapmak için hiçbir neden yok, her ikisine de sahip olabilirsiniz. Ayrıca, Durum 3 tamamen değersizdir. Saf olmayan sanalları geçersiz kılabilirsiniz, bu yüzden yapamayacağınız bir tasarımı unutun.
DeadMG

Arayüzler yalnızca C ++ 'da varsayılan uygulamalara sahip olmakla kalmaz, aynı zamanda varsayılan uygulamalara sahip olabilirler ve yine de soyut olabilirler! yani sanal geçersiz IMethod () = 0 {std :: cout << "Ni!" << std :: endl; }
Joris Timmermans

@MadKeithV: Onları satır içinde tanımlayabileceğine inanmıyorum, ama nokta hala aynı.
DeadMG

@MadKeith: Visual Studio, Standard C ++ 'ın özellikle doğru bir temsili gibi.
DeadMG

0

Vaka 3, Vaka 1'den daha üstün mü? Bunun nedeni 'daha iyi kapsülleme' veya 'daha gevşek bir şekilde bağlanmış' ya da başka bir nedenden mi?

Uygulamanızda gördüğüm kadarıyla, Case 3 uygulamanız, daha sonra türetilmiş sınıfta değiştirilebilen saf sanal yöntemleri uygulayabilen soyut bir sınıf gerektirir. Örnek 3 , türetilmiş sınıf do_work'ün uygulamasını gerektiğinde ve gerektiğinde değiştirebileceğinden ve türetilmiş tüm örnekler temel olarak temel soyut türüne ait olacağından daha iyi olacaktır.

40.000 kod satırı olabilecek bir yazılım projesi için en iyi durum hangisidir.

Sadece uygulama tasarımınıza ve ulaşmak istediğiniz hedefe bağlı olduğunu söyleyebilirim. Soyut sınıf ve arayüzler çözülmesi gereken probleme göre uygulanır.

Soruyu düzenle

Ya 3 ay sonra, Joe Coder bir Doktor Çalışanı oluşturur, ancak do_work () 'de increment_money_earned ()' i çağırmayı unutursa?

Her sınıfın beklenen davranışı doğrulayıp onaylamadığını kontrol etmek için birim testleri yapılabilir. Dolayısıyla, uygun birim testleri uygulanırsa, Joe Coder yeni sınıfı uyguladığında hatalar önlenebilir.


0

Arabirimleri kullanmak, her uygulama birbirinin bir kopyasıysa DRY'yi keser. Sen arayüzü hem uygulayarak bu ikilemi çözmek için ve devralma, henüz sınıfların bir dizi aynı arabirimini uygulamak isteyebilirsiniz bazı durumlar vardır, ancak sınıfların her birinde davranış değişir ve bu hala ilkesine tutacak KURU. Açıkladığınız 3 yaklaşımdan herhangi birini kullanmayı seçip seçmediğiniz, belirli bir duruma uymak için en iyi tekniği uygulamak için yapmanız gereken seçimlerle ilgilidir. Öte yandan, muhtemelen zaman içinde, Arayüzleri daha fazla kullandığınızı ve kalıtımı yalnızca tekrarlamayı kaldırmak istediğiniz yere uyguladığınızı göreceksiniz. Bu sadece bu demek değil miras nedeni, ancak tasarımınızın daha sonra değişmesi gerektiğine karar verirseniz ve soyundan gelen sınıflar üzerindeki etkiyi bir değişikliğin etkilerinden en aza indirmek istiyorsanız, seçeneklerinizi açık tutmanıza izin vermek için miras kullanımını en aza indirmek daha iyidir. bir üst sınıfta tanıtacaktır.

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.