Soyut bir sınıfta arayüzler


30

İş arkadaşım ve ben, temel sınıflar ve arayüzler arasındaki ilişki hakkında farklı görüşler var. Bir sınıfın, bir arayüzün uygulanması gerektiğinde kullanılabiliyorsa, bir sınıfın bir arayüz uygulamaması gerektiğine inanıyoruz. Başka bir deyişle, böyle bir kod görmeyi seviyorum:

interface IFooWorker { void Work(); }

abstract class BaseWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker, IFooWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

DbWorker, IFooWorker arayüzünü alan şeydir, çünkü arayüzün hızlı bir şekilde uygulanmasıdır. Sözleşmeyi tamamen yerine getiriyor. İş arkadaşım neredeyse aynı olanı tercih ediyor:

interface IFooWorker { void Work(); }

abstract class BaseWorker : IFooWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

Temel sınıfın arayüzü aldığı ve bundan dolayı temel sınıfın tüm mirasçıları da bu arayüzdendir. Bu beni rahatsız ediyor, ancak “temel sınıfın dışında arayüzün bir uygulaması olarak tek başına duramaz” gibi somut nedenlerle gelemiyorum.

Metodunun lehine ve aleyhte olanlar benimkine göre neler ve neden biri diğerine karşı kullanılmalı?


Öneriniz, elmas kalıtımına çok benzer , bu da daha fazla kafa karışıklığına neden olabilir.
Spoike

@Spoike: Bunu nasıl görebiliriz?
Niing,

@ Yorumda verdiğim bağlantıyı eklemek, basit bir sınıf diyagramına ve bunun ne olduğuna dair tek bir açıklamalı bir açıklamaya sahiptir. "elmas" problemi olarak adlandırılır, çünkü kalıtım yapısı temel olarak bir elmas şekli (yani (️) şeklinde çizilir.
Spoike

@Spoike: bu soru neden elmas kalıtımına neden olacak?
Niing

1
@Niing: BaseWorker ve IFooWorker'ı aynı yöntemle Workmiras almak, elmas mirası konusudur (bu durumda her ikisi de Workyöntem üzerinde bir sözleşme yapar ). Java'da, arabirimin yöntemlerini uygulamanız gerekir, bu nedenle Workprogramın hangi yöntemi kullanması gerektiği bu şekilde önlenir. Bununla birlikte, C ++ gibi diller sizin için bunu açıklamıyor.
Spoike

Yanıtlar:


24

Bir sınıfın, bir arayüzün uygulanması gerektiğinde kullanılabiliyorsa, bir sınıfın bir arayüz uygulamaması gerektiğine inanıyoruz.

BaseWorkerbu gereksinimi yerine getirir. Sırf bir BaseWorkernesneyi doğrudan somutlayamıyor olmanız , sözleşmeyi yerine getiren bir BaseWorker işaretçiye sahip olamayacağınız anlamına gelmez . Gerçekten de, bu soyut sınıfların bütün mesele budur.

Ayrıca, gönderdiğiniz basitleştirilmiş örnekten söylemek zordur, ancak sorunun bir kısmı, arabirimin ve soyut sınıfın gereksiz olması olabilir. Eğer uygulayan diğer sınıflar yoksa IFooWorkeranlamına değil kaynaklanıyor BaseWorker, hiç bir arayüze gerek yoktur. Arayüzler, çoklu kalıtımı kolaylaştıran ek sınırlamaları olan sadece soyut sınıflardır.

Yine basitleştirilmiş bir örnekten söylemek zor olmak gerekirse, açıkça türetilmiş bir sınıftan tabana atıfta bulunarak korunan bir yöntemin kullanılması ve arayüz uygulamasını açıklamak için açık bir yerin bulunmaması, miras yerine uygun olmayan bir miras kullandığınızın uyarı işaretleridir. bileştirme, kompozisyon. Bu miras olmadan, bütün sorunuz tartışılmaz hale geliyor.


1
+1 BaseWorkerdoğrudan gerçekleştirilemediğinden, verilenlerin BaseWorker myWorkeruygulanmadığı anlamına gelmediğine işaret etmek için +1 IFooWorker.
Avner Shahar-Kashtan

2
Arayüzlerin sadece soyut sınıflar olduğuna katılmıyorum. Soyut sınıflar genellikle bazı uygulama detaylarını tanımlar (aksi takdirde bir arayüz kullanılmış olabilir). Bu detaylar sizin beğeninize göre değilse, şimdi temel sınıfın her kullanımını başka bir şeyle değiştirmeniz gerekir. Arayüzler sığdır; bağımlılıklar ve bağımlılar arasındaki "tak ve sok" ilişkisini tanımlarlar. Bu nedenle, herhangi bir uygulama detayına sıkı bağlantı, artık bir endişe kaynağı değildir. Eğer arayüzü miras alan bir sınıf beğeninize göre değilse, çıkartın ve tamamen başka bir yere koyun; kodun daha az umrunda olabilir.
KeithS

5
Her ikisinin de avantajları vardır, ancak tipik olarak arayüz, temel uygulamaları tanımlayan soyut bir sınıf olup olmadığı olsun, bağımlılık için her zaman kullanılmalıdır. Arayüz ve soyut sınıfın birleşimi her iki dünyanın da en iyisini verir; Arayüz sığ yüzey tak ve sok ilişkisini sürdürürken, soyut sınıf faydalı ortak kod sağlar. İsteğin altında arabirimin altındaki herhangi bir seviyeyi çıkarabilir ve değiştirebilirsiniz.
KeithS

By "pointer" Bir demek bir nesnenin örneğini (bir işaretçi başvuru olacaktır)? Arayüzler sınıf değildir, türdür ve çoklu kalıtımın eksik bir alternatifi olarak görev yapabilir, yerine geçmez - yani "bir sınıftaki birden fazla kaynaktan gelen davranışı dahil ederler".
samis

46

İş arkadaşınla aynı fikirdeyim.

Her iki örnekte de BaseWorker, soyut yöntem Work () 'i tanımlar; bu, tüm alt sınıfların IFooWorker'ın sözleşmesini karşılayabileceği anlamına gelir. Bu durumda, BaseWorker'ın arayüzü uygulaması gerektiğini ve bu uygulamanın alt sınıfları tarafından miras alınacağını düşünüyorum. Bu, her bir alt sınıfın gerçekten bir IFooWorker (DRY ilkesi) olduğunu açıkça belirtmek zorunda kalmanızı önler.

Work () 'ı bir BaseWorker yöntemi olarak tanımlamıyorsanız ya da IFooWorker, BaseWorker'ın alt sınıflarının istemeyeceği veya ihtiyaç duymayacağı başka yöntemlere sahip olsaydı, o zaman (açıkça) aslında hangi alt sınıfların IFooWorker'ı uyguladığını belirtmeniz gerekirdi.


11
+1 de aynı şeyi gönderdi. Üzgünüm, ancak iş arkadaşınızın bu durumda haklı olduğunu düşünüyorum, eğer bir sözleşmeyi yerine getirmeyi garanti ederse, garantinin bir ara yüz, soyut bir sınıf veya somut bir sınıf tarafından yerine getirilip getirilmediği, bu sözleşmeyi devralması gerekir. Basitçe söylemek gerekirse: Kefil, garanti ettiği sözleşmeyi devralmalıdır.
Jimmy Hoffa

2
Genel olarak aynı fikirdeyim, ancak "temel", "standart", "varsayılan", "genel" vb. Gibi kelimelerin bir sınıf adındaki kod kokuları olduğunu belirtmek isterim. Eğer bir soyut temel sınıf bir arayüzle hemen hemen aynı isme sahipse, ancak bu zayıf kelimelerden biri varsa, bu genellikle yanlış bir soyutlamanın işaretidir; arayüzleri şey tanımlamak yapar ne tip kalıtım tanımlarınızı olduğunu . Eğer bir IFoove bir BaseFoovarsa IFoo, uygun bir şekilde ince taneli bir arayüz değildir veya BaseFookompozisyonun daha iyi bir seçim olabileceği bir miras kullanıyor demektir.
Aaron,

@Aaronaught İyi bir nokta olsa da, IFoo uygulamalarının tamamının veya çoğunun miras alması gereken (bir hizmet veya DAO uygulamanız gibi) kalması gereken bir şey olmasına rağmen.
Matthew Flynn

2
Öyleyse, temel sınıfın uygulanmasının olası bir sınıf ağacı olduğunu belirtmek için temel sınıf aranmamalı MyDaoFooSqlFooya da ya HibernateFooda her neyse IFoo? Bir temel sınıf belirli bir kütüphaneye veya platforma bağlanırsa ve bu adda hiç bir şey ifade
etmezse

@Aaronaught - Evet. Tamamen katılıyorum.
Matthew Flynn

11

Genel olarak iş arkadaşınızla aynı fikirdeyim.

Modelinizi ele alalım: Arayüz, temel sınıf ayrıca IFooWorker yöntemlerinin ortaya çıkmasını zorlasa da, sadece çocuk sınıfları tarafından uygulanır. Öncelikle, gereksiz; alt sınıfın arayüzü uygulayıp uygulamaması, BaseWorker'in maruz kalan yöntemlerini geçersiz kılmaları gerekir ve aynı şekilde herhangi bir IFooWorker uygulamasının da BaseWorker'dan herhangi bir yardım alıp almadıklarını göstermesi gerekir.

Bu ayrıca, hiyerarşinizi belirsizleştirir; "Tüm IFooWorkers BaseWorker'lar" mutlaka doğru bir ifade değildir ve "Tüm BaseWorkers IFooWorker'lar" dır. Bu nedenle, IFooWorker veya BaseWorker'ın herhangi bir uygulaması olabilecek bir örnek değişken, parametre veya dönüş türü tanımlamak istiyorsanız (her ikisinde de kalıtımın nedenlerinden biri olan ortak işlevsellikten yararlanarak) bunların her şeyi kapsayan olması garanti edilir; Bazı BaseWorkers, IFooWorker tipi bir değişkene atanamaz ve bunun tersi de geçerlidir.

İş arkadaşınızın modelini kullanmak ve değiştirmek çok daha kolaydır. "Tüm BaseWorker'lar IFooWorkers'tır" şimdi gerçek bir ifadedir; Herhangi bir BaseWorker örneğini herhangi bir IFooWorker bağımlılığına verebilirsiniz, problem yok. Tersine "Tüm IFooWorkers BaseWorker'lar" ifadesi doğru değil; Bu, BaseWorker'ı BetterBaseWorker ile değiştirmenize izin verir ve tüketen kodunuz (IFooWorker'a bağlıdır) farkı söylemek zorunda kalmazsınız.


Bu cevabın sesini seviyorum ama son kısmı pek takip etme. BetterBaseWorker'ın IFooWorker'ı uygulayan bağımsız bir soyut sınıf olacağını öne sürüyorsunuz, böylece varsayımsal eklentim basitçe "Ah oğlum! Daha İyi İşçi sonunda çıktı!" Diyebilir. ve herhangi bir BaseWorker referansını BetterBaseWorker olarak değiştirin ve bir gün arayın (belki gereksiz kodumun büyük parçalarını çıkarmama izin veren harika yeni döndürülen değerlerle oynayın)?
Anthony,

Az ya da çok, evet. Bunun en büyük avantajı, bunun yerine BetterBaseWorkers olarak değiştirilmesi gereken BaseWorker'a yapılan referans sayısını azaltmanızdır; kodunuzun çoğu doğrudan beton sınıfına referans vermez, bunun yerine IFooWorker'ı kullanın, bu nedenle bu IFooWorker bağımlılıklarına atananları değiştirdiğinizde (sınıfların özellikleri, yapıcıların parametreleri veya yöntemleri) IFooWorker'ı kullanan kod hiçbir fark görmemelidir kullanımda.
KeithS

6

Bu cevaplara bir uyarı ekleyeceğim. Temel sınıfın arayüze bağlanması, o sınıfın yapısında bir kuvvet yaratır. Temel örneğinizde, ikisinin birleştirilmesi gereken bir fikir değil, ancak bu her durumda geçerli olmayabilir.

Java'nın koleksiyon çerçeve sınıflarını alın:

abstract class AbstractList
class LinkedList extends AbstractList implements Queue

Aslında Kuyruk sözleşme ile uygulanan LinkedList içine endişe itmedi AbstractList .

İki dava arasındaki fark nedir? BaseWorker'in amacı her zaman (adı ve arayüzü ile bildirildiği gibi) IWorker'da işlemleri gerçekleştirmek içindi . Amacı AbstractList ve bu Kuyruğu ıraksak, ancak eski bir descenant hala ikincisi sözleşme uygulayabilir.


Bu zamanın yarısı olur. Her zaman arayüzü temel sınıfta uygulamayı tercih ediyor ve ben de her zaman son betona uygulamayı tercih ediyorum. Sunulan senaryo sık sık gerçekleşir ve temeldeki arayüzlerin beni rahatsız etmesinin bir parçasıdır.
Bryan Boettcher

1
Doğru, insta ve ben bu şekilde arayüzlerin kullanımını birçok geliştirme ortamında gördüğümüz kalıtımın aşırı yüzü olarak görüyoruz. GoF'in tasarım desen kitaplarında söylediği gibi, mirasa göre kompozisyonu tercih etmek ve arayüzü temel sınıftan uzak tutmak, bu prensibi teşvik etmenin yollarından biridir.
Mihai Danila

1
Uyarı alıyorum, ancak OP'nin soyut sınıfının arayüzle eşleşen soyut yöntemler içerdiğini göreceksiniz: bir BaseWorker dolaylı olarak bir IFooWorker. Açık hale getirmek bu gerçeği daha kullanışlı hale getirir. Queue'da bulunan ve AbstractList'e dahil edilmeyen çok sayıda yöntem vardır; ancak, bir AbstractList, çocukları olsa bile, bir Queue değildir. AbstractList ve Queue ortogonal.
Matthew Flynn

Bu görüş için teşekkür ederiz; OP'nin davasının bu kategoriye girdiğine katılıyorum, ancak daha derin bir kural arayışında daha büyük bir tartışma olduğunu düşündüm ve okuduğum bir eğilim hakkında gözlemlerimi paylaşmak istedim (hatta kendim de gördüm) kısa bir süre için) kalıtımın aşırı kullanımı, belki de OOP'un araç kutusundaki araçlardan biri olduğundan.
Mihai Danila,

Dang, altı yıl oldu. :)
Mihai Danila

2

Soruyu soracağım, IFooWorkeryeni bir yöntem eklemek gibi , ne zaman değişiklik yaparsınız ?

Eğer BaseWorkerarayüzü uygularsa, varsayılan olarak soyut olsa bile, yeni yöntemi bildirmek zorunda kalacaktır. Öte yandan, arabirimi uygulamazsa, yalnızca türetilmiş sınıflarda derleme hataları alırsınız.

O nedenle ben temel sınıf arabirimini uygulamak yapmak istiyorum o zamandan beri, belki türetilmiş sınıfları dokunmadan temel sınıfta yeni yöntem için tüm işlevselliğini uygulamak mümkün.


1

İlk önce soyut bir temel sınıfın ne olduğunu ve bir arayüzün ne olduğunu düşünün. Birini veya diğerini ne zaman ve ne zaman kullanmayacağınızı düşünün.

İnsanların her ikisinin de benzer kavramlar olduğunu düşünmeleri yaygındır, aslında ortak bir röportaj sorusu (ikisi arasındaki fark ??)

Yani soyut bir temel sınıf size, metotların varsayılan uygulamaları olan arayüzlerin sağlayamayacağı bir şey verir. (Başka şeyler var, C # 'da örneğin bir arabirimde değil, soyut bir sınıfta statik yöntemlere sahip olabilirsiniz).

Örnek olarak, bunun yaygın bir kullanımı ID'yle kullanılabilir. Soyut sınıf, IDisposable'ın Dispose yöntemini uygular; bu, temel sınıfın türetilmiş bir sürümünün otomatik olarak tek kullanımlık olacağı anlamına gelir. Daha sonra çeşitli seçeneklerle oynayabilirsiniz. Elden çıkar, türetilmiş sınıfları uygulamaya zorlayarak soyut yapın. Sanal bir varsayılan uygulama sağlayın; bu nedenle, sanallaştırmazlar ya da sanallaştırmazlar ya da soyutlaştırmazlar ve örneğin BeforeDispose, AfterDispose, OnDispose veya Disposing gibi sanal yöntemler çağırırlar.

Bu nedenle, tüm türetilmiş sınıfların arayüzü desteklemesi gerektiğinde, temel sınıfa girer. Bu arabirime yalnızca bir veya daha fazlasına ihtiyaç duyulursa türetilmiş sınıfa geçilir.

Bunların hepsi aslında basitleştirme üzerine brüt. Diğer bir alternatif, türetilmiş sınıfların arayüzleri bile uygulamaması, aynı zamanda bir adaptör deseni ile sağlamasıdır. Son zamanlarda gördüğüm bir örnek IObjectContextAdapter oldu.


1

Soyut bir sınıfla bir arayüz arasındaki ayrımı tam olarak kavramaktan hala yıllarım. Ne zaman temel kavramları ele aldığımı düşündüğümde stackexchange'e gidiyorum ve iki adım geri gidiyorum. Ancak konu ve OP'lerin sorusu üzerine birkaç düşünce:

İlk:

Bir arabirimin iki ortak açıklaması vardır:

  1. Arabirim, herhangi bir sınıfın uygulayabileceği yöntemlerin ve özelliklerin bir listesidir ve bir arabirim uygulayarak, bir sınıf, bu yöntemleri (ve imzalarını) garanti eder ve bu özellikler (ve türleri), bu sınıfa "müdahale ederken" kullanılabilir o sınıfın bir nesnesi. Arayüz bir sözleşmedir.

  2. Arayüzler, hiçbir şey yapamayan / yapamayan soyut sınıflardır. Bunlar yararlıdır çünkü bu ortalama ebeveyn sınıflarının aksine, birden fazla uygulayabilirsiniz. Mesela, BananaBread sınıfının bir nesnesi olabilirim ve BaseBread'den miras kaldım, ama bu hem IWithNuts hem de ITastesYummy arayüzlerini uygulayamayacağım anlamına gelmiyor. IDoesTheDishes arayüzünü bile uygulayabilirim, çünkü sadece ekmek değilim, biliyor musunuz?

Soyut bir sınıfın iki ortak açıklaması vardır:

  1. Soyut bir sınıf, bilirsin, yapabileceği şey değil. Bu, öz gibi, aslında gerçek bir şey değil. Bekle, bu yardımcı olacak. Bir tekne soyut bir sınıftır, ancak seksi bir Playboy Yacht, BaseBoat'ın alt sınıfı olacaktır.

  2. Soyut sınıflar üzerine bir kitap okudum ve belki de o kitabı okumalısınız, çünkü muhtemelen onu alamazsınız ve eğer o kitabı okumadıysanız yanlış yaparsınız.

Bu arada, Citers kitabı her zaman etkileyici görünüyor, yine de kafam karışmış olsa bile.

İkinci:

SO'da, birileri bu sorunun daha basit bir versiyonunu sordu, klasik, "Neden arayüzleri kullanıyorsunuz? Fark nedir? Neyi özlüyorum?" Bir cevap, basit bir örnek olarak bir hava kuvvetleri pilotunu kullandı. Arazi oldukça iyi değildi, ancak bir tanesi IFOble arayüzünden takeOff, pilotEject, vs. gibi yöntemlerden bahseden harika yorumlar ortaya koydu. Ve bu gerçekten benim için arayüzlerin neden sadece faydalı olmadığının gerçek dünya örneği olduğunu gösterdi. ama çok önemli. Bir arayüz bir nesneyi / sınıfı sezgisel hale getirir veya en azından olduğu hissini verir. Bir arayüz, nesnenin veya verilerin yararına değil, o nesneyle etkileşime girmesi gereken bir şey için değildir. Klasik Meyve-> Elma-> Fuji veya Şekil-> Üçgen-> Eşkenar miras örnekleri, soyundan gelen belirli bir nesneyi taksonomik olarak anlamak için harika bir modeldir. Tüketiciyi ve işlemcileri, genel nitelikleri, davranışları, nesnenin bir şeyler grubu olup olmadığı hakkında bilgilendirir, yanlış bir yere koyarsanız sisteminizi hortumlar veya duyusal verileri, belirli bir veri deposuna bir konektörü açıklar veya Bordro yapmak için gerekli finansal veriler.

Belirli bir Plane nesnesinin acil iniş için bir yöntemi olabilir veya olmayabilir, ancak acil durumEğerini sadece DumbPlane ile kaplanmış uyanmak ve geliştiricilerin quickLand ile gittiğini öğrenmek için diğer tüm değişken nesneler gibi kabul edersem sinirleneceğim çünkü hepsinin aynı olduğunu düşünüyorlardı. Tıpkı her vida imalatçısının kendi hakkını sıkıca yorumlaması olsaydı ya da TV'mde ses azaltma düğmesinin üstünde ses artırma düğmesi yoksa, nasıl sinirleneceğimi.

Soyut sınıflar, herhangi bir iniş nesnesinin o sınıf olarak nitelemesi için gerekenleri belirleyen modeldir. Bir ördeğin tüm özelliklerine sahip değilseniz, sadece tuhaf bir pengueniniz olan IQuack arayüzünü uygulamanız önemli değildir. Arayüzler, başka hiçbir şeyden emin olamadığınızda bile mantıklı olan şeylerdir. Jeff Goldblum ve Starbuck uzaylı uzayları uçurmayı başardılar çünkü arayüz güvenilir bir şekilde birbirine benziyordu.

Üçüncü:

İş arkadaşınızla aynı fikirdeyim, çünkü bazen en başta belirli yöntemleri uygulamanız gerekebilir. Bir Active Record ORM oluşturuyorsanız, bir kaydetme yöntemine ihtiyacı vardır. Bu, başlatılabilecek alt sınıfa bağlı değildir. Ve eğer ICRUD arayüzü sadece bir soyut sınıfa birleştirilmeyecek kadar taşınabilirse, diğer sınıflar tarafından, o soyut sınıfın soyundan gelen herhangi bir sınıfa aşina olan herkes için güvenilir ve sezgisel hale getirmek için uygulanabilir.

Diğer taraftan, soyut sınıfa bir arayüz bağlamak için ne zaman atlamayacağımızın daha önce çok iyi bir örnek vardı, çünkü tüm liste tipleri bir sıra arayüzü uygulayamayacak (ya da vermemeli). Bu senaryonun yarı yarıya gerçekleştiğini söylediniz, bu da sizin ve iş arkadaşınızın her zaman yarı yarıya yanlış olduğu anlamına gelir ve bu nedenle yapılacak en iyi şey tartışmayı, tartışmayı, düşünmeyi ve doğru oldukları ortaya çıktığında eşleştirmeyi kabul ve kabul etmektir. . Ancak eldeki iş için en iyisi olmasa bile bir felsefeyi izleyen bir geliştirici olmayın.


0

Sizin de önerdiğiniz gibi DbWorker, uygulanması gereken neden başka bir yönü var IFooWorker.

İş arkadaşınızın tarzında, herhangi bir nedenle daha sonra yeniden yapılanma meydana gelirse ve DbWorkersoyut BaseWorkersınıfı genişletmediği kabul edilirse DbWorker, IFooWorkerarayüzü kaybeder . Bu, ancak araları olmasa da, IFooWorkerara yüzünü beklerlerse tüketen müşterileri etkileyebilir .


-1

Başlamak için, arayüzleri ve soyut sınıfları farklı tanımlamayı seviyorum:

Interface: a contract that each class must fulfill if they are to implement that interface
Abstract class: a general class (i.e vehicle is an abstract class, while porche911 is not)

Sizin durumunuzda, tüm işçiler uygular work()çünkü sözleşmenin gerektirdiği şey budur. Bu nedenle, temel sınıfınız Baseworkerbu yöntemi açıkça veya sanal bir işlev olarak uygulamalıdır. Tüm çalışanların ihtiyaç duyduğu basit gerçeklerden dolayı bu yöntemi temel sınıfınıza koymanızı öneririm work(). Bu nedenle, temel sınıfınızın (bu tür bir işaretçi oluşturamasanız bile) onu bir işlev olarak içermesi mantıklıdır.

Şimdi, arayüzü DbWorkertatmin ediyor IFooWorker, ancak bu sınıfın yapması gereken belirli bir yol varsa work(), o zaman gerçekten miras aldığı tanımı aşırı yüklemesi gerekiyor BaseWorker. Arayüzü IFooWorkerdoğrudan uygulamamasının nedeni bunun özel bir şey olmamasıdır DbWorker. O her şey yaptıysak siz benzer sınıfları uygulanacak DbWorkero zaman ihlal olacağını KURU .

İki sınıf aynı işlevi farklı şekillerde uygularsa, en büyük ortak üst sınıfı aramaya başlayabilirsiniz. Çoğu zaman bir tane bulacaksın. Olmazsa, ya bakmaya devam et ya da pes et ve temel bir sınıf yapmak için ortak noktaları olacak ortak şeyleri olmadığını kabul et.


-3

Vay canına, tüm bu cevaplar ve hiçbiri örnekteki arayüzün hiçbir işe yaramadığına işaret etmiyor. Kalıtım ve aynı yöntem için bir arabirim kullanmazsınız, bu anlamsızdır. Birini veya diğerini kullanıyorsun. Bu forumda, birinin veya diğerinin çağrısında bulunan senariosun yararlarını açıklayan cevaplarla ilgili pek çok soru var.


3
Bu bir patent yanlışlığı. Arabirim, uygulamaya bakılmaksızın sistemin davranması beklenen bir sözleşmedir. Miras alınan temel sınıf, bu arayüz için olası birçok uygulamadan biridir. Yeterince büyük ölçekli bir sistem, çeşitli arayüzleri (genellikle jeneriklerle kapatılmış) karşılayan çoklu temel sınıflara sahip olacaktır; bu, tam olarak bu kurulumun ne yaptığını ve neden onları bölmenin yardımcı olduğunu gösteriyor.
Bryan Boettcher,

OOP perspektifinden gerçekten kötü bir örnek. "Temel sınıf sadece bir uygulamadır" dediğiniz gibi (arayüz için bir anlamı olmalı veya olmayacaktı), IFooWorker arayüzünü uygulayan işçi olmayan sınıflar olacağını söylüyorsunuz. O zaman uzman bir fooworker olan bir temel sınıfa sahip olacaksınız (aynı zamanda barworker olabileceğini de düşünmeliyiz) ve temel işçi bile olmayan diğer fooworker'lara sahip olacaksınız! Bu geriye. Birden fazla şekilde.
Martin Maat,

1
Belki de arayüzdeki "İşçi" kelimesini tıkıp kalmışsınızdır. Peki ya "Datasource"? Bir IDatasource <T> varsa, önemsiz bir SqlDatasource <T>, RestDatasource <T>, MongoDatasource <T> değerlerine sahip olabiliriz. İşletme, jenerikler arayüzünün hangi kapanışlarının, soyut veri kaynaklarının kapanış uygulamalarına gittiğine karar verir.
Bryan Boettcher

Mirasın yalnızca DRY adına kullanılması ve mantıklı bir uygulamanın bir temel sınıfa yerleştirilmesi mantıklı olabilir. Ancak geçersiz kılınan herhangi bir yöntemi herhangi bir arabirim yöntemiyle aynı hizaya getirmezsiniz, temel sınıf genel destek mantığını içerir. Eğer sıraya girerlerse, kalıtımın sorununuzu çözdüğünü ve arayüzün hiçbir işe yaramadığını gösterecektir. Kalıtım probleminizi çözemediğinde bir arayüz kullanırsınız, çünkü modellemek istediğiniz genel özellikler tek bir sınıf ağacına uymaz. Ve evet, örnekteki ifade daha da yanlış yapar.
Martin Maat
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.