Arabirim ayırma ilkesi somut yöntemlere uygulanır mı?


10

Arabirim ayırma ilkesi, hiçbir istemcinin kullanmadığı yöntemlere bağımlı olmaya zorlanmamasını önerdiğinden, bir istemci arabirim yöntemleri için boş bir yöntem uygulamamalıdır, aksi takdirde bu arabirim yöntemi başka bir arabirime yerleştirilmelidir.

Peki somut yöntemlere ne dersiniz? Her müşterinin kullanamayacağı yöntemleri ayırmalı mıyım? Aşağıdaki sınıfı düşünün:

public class Car{
    ....

    public boolean isQualityPass(){
        ...
    }

    public int getTax(){
        ...
    }

    public int getCost(){
        ...
    }
}

public class CarShop{
    ...
    public int getCarPrice(int carId){
        Car car=carList[carId];
        int price=car.getTax() + car.getCost()... (some formula);
        return price;
    }
}

Yukarıdaki kodda, CarShop isQualityPass () yöntemini yeni bir sınıfa ayırmam gerekirse, Car'da isQualityPass () yöntemini kullanmaz:

public class CheckCarQualityPass{
    public boolean isQualityPass(Car car){
    }
}

CarShop bağlantılarını azaltmak için? Çünkü bir kez isQualityPass () ekstra bağımlılık gerekiyorsa düşünüyorum, örneğin:

public boolean isQualityPass(){
    HttpClient client=...
}

CarShop, aslında HttpClient'i asla kullanmasa bile HttpClient'e bağlı olacaktır. Yani sorum şu: Arayüz ayırma prensibine göre, her müşterinin kullanamayacağı somut yöntemleri ayırmalı mıyım, böylece bu yöntemler kuplajı azaltmak için sadece müşteri gerçekten kullandığında müşteriye bağlıdır?


2
Genellikle bir araba "kaliteyi" ne zaman geçtiğini biliyor mu? Ya da kendi başına kapsüllenebilecek bir iş kuralı olabilir mi?
Laiv

2
İSS'deki kelime ara yüzünün , arayüzlerle ilgili olduğu anlamına gelir . Bu nedenle, Carsınıfınızda (tüm) kullanıcıların bilmesini istemediğiniz bir yönteminiz varsa , sınıfın uyguladığı (birden fazla) arabirim oluşturun ve Carbu arabirim yalnızca arabirimler bağlamında yararlı yöntemler bildirir .
Timothy Truckle

@Laiv Eminim yakında bundan çok daha fazlasını bilen araçlar göreceğiz. ;)
birleşik modelleme sandviçi

1
Bir araba, üreticisinin bilmesini istediğini bilecektir. Volkswagen ne demek istediğimi biliyor :-)
Laiv

1
Bir arayüzden bahsediyorsunuz, ancak örneğinizde arayüz yok. Arabayı bir arayüze dönüştürmekten ve söz konusu arayüze hangi yöntemleri dahil etmekten bahsediyoruz?
Neil

Yanıtlar:


6

Örneğinizde, CarShopbağımlı değildir isQualityPassve bir yöntem için boş bir uygulama yapmak zorunda değildir. İlgili bir arayüz bile yok. Yani "ISS" terimi burada eşleşmiyor. Ve böyle isQualityPassbir yöntem Car, ek sorumluluklar veya bağımlılıklar ile aşırı yüklenmeden , nesneye iyi uyan bir yöntem olduğu sürece , bu iyidir. Sadece yöntemi kullanmayan bir istemci olduğu için, bir sınıfın genel yöntemini başka bir yere yeniden düzenlemeye gerek yoktur.

Ancak, Cardoğrudan bir etki alanı sınıfının böyle bir şeye bağlı olması HttpClient, istemcinin yöntemi kullandığı veya kullandığı yöntemden bağımsız olarak muhtemelen iyi bir fikir değildir. Mantığın ayrı bir sınıfa taşınmasına CheckCarQualityPass"İSS" denmez, buna "endişelerin ayrılması" denir . Yeniden kullanılabilir bir araba nesnesinin endişesi, herhangi bir harici HTTP çağrısı yapmak olmamalıdır, en azından doğrudan değil, bu yeniden kullanılabilirliği ve ayrıca test edilebilirliği çok fazla sınırlar.

Eğer isQualityPasskolayca başka bir sınıfa üzerinden taşınamaz, alternatif yapmak olacaktır Httpsoyut bir arayüz üzerinden çağrı IHttpClientenjekte edilir Carya da içine (kapsüllenmiş HTTP isteği ile) bütün "QualityPass" kontrol stratejisi enjekte inşaat zamanda Carnesne . Ancak bu IMHO sadece ikinci en iyi çözümdür, çünkü azaltmak yerine genel karmaşıklığı arttırır.


isQualityPass yöntemini çözmek için Strateji modeli ne olacak?
Laiv

@Laiv: teknik olarak, bu işe yarayacak, elbette (düzenlememe bakın), ancak daha karmaşık bir Carnesneye neden olacaktır . Bir çözüm için ilk tercihim olmazdı (en azından bu uydurulmuş örnek bağlamında değil). Ancak, daha mantıklı olabilir "gerçek" kodu, bilmiyorum.
Doc Brown

6

Yani sorum şu: Arayüz ayırma prensibine göre, her müşterinin kullanamayacağı somut yöntemleri ayırmalı mıyım, böylece bu yöntemler kuplajı azaltmak için sadece müşteri gerçekten kullandığında müşteriye bağlıdır?

Arabirim ayırma ilkesi, ihtiyacınız olmayan şeylere erişime izin vermemekle ilgili değildir. İhtiyacınız olmayan şeye erişim konusunda ısrar etmemekle ilgilidir.

Arabirimler, bunları uygulayan sınıfa ait değildir. Onları kullanan nesnelere aittirler.

public class CarShop{
    ...
    public int getCarPrice(int carId){
        Car car=carList[carId];
        int price=car.getTax() + car.getCost()... (some formula);
        return price;
    }
}

Burada kullanılan getTax()ve getCost(). Israr edilen her şeye erişilebilir Car. Sorun Carısrar ediyor, erişimin isQualityPass()gerekli olmadığı anlamına geliyor .

Bu düzeltilebilir. Somut olarak düzeltilip düzeltilemeyeceğini soruyorsunuz. Yapabilir.

public class CarShop{
    ...
    public int getCarPrice(int carId){
        CarLiability carLiability=carLiabilityList[carId];
        int price=carLiability.getTax() + carLiability.getCost()... (some formula);
        return price;
    }
}

Bu kodların hiçbiri CarLiabilitybir arabirim mi yoksa somut bir sınıf mı olduğunu bile bilmiyor . Bu iyi birşey. Bilmek istemiyor.

Eğer bir arayüz ise onu Caruygulayabilir. Olsa bile, çünkü bu ISP ihlal etmez isQuality()ise Car CarShopbunda ısrar etmez. Bu iyi.

Eğer somutsa, isQuality()ya hiç mevcut olmayabilir ya da başka bir yere taşınmış olabilir. Bu iyi.

Ayrıca CarLiability, etrafına Cariş delege eden somut bir paket olabilir. Yani sürece CarLiabilitygöstermiyor isQuality()sonra CarShopgayet iyi. Tabii ki bu sadece kutuyu yola CarLiabilitykoydu Carve aynı şekilde ISS'yi nasıl takip edeceğini CarShopbulmak zorunda.

Kısacası, ISP nedeniyle isQuality()kaldırılması gerekmez Car. İhtiyaç duyulan zımni ihtiyaç isQuality()ortadan kaldırılmalı CarShopçünkü CarShopbuna ihtiyaç duymaz, bu yüzden istememelidir.


4

Arabirim ayırma ilkesi somut yöntemlere uygulanır mı?

Peki somut yöntemlere ne dersiniz? Her müşterinin kullanamayacağı yöntemleri ayırmalı mıyım?

Pek sayılmaz. Gizlemek için farklı yolları vardır Car.isQualityPassden CarShop.

1. Erişim değiştiriciler

Gönderen Demeter'in Kanunu açısından, biz düşünebiliriz Carve CardShopolmamaya arkadaşlar . Bir sonrakini yapmak bizi meşrulaştırıyor.

package com.my.package.domain.model
public class Car{
    ...
    protected boolean isQualityPass(){...}
}

package com.my.package.domain.services
public class CarShop{
    ...
}

Her iki bileşenin de farklı paketlerde olduğunu unutmayın. Artık korunan davranışlar CarShopüzerinde görünürlük yok . (Yukarıdaki örnek çok basit görünüyorsa beni önceden affedin).Car

2. Arayüz Ayrımı

ISS biz somut sınıfları ile, soyutlamaları ile çalışmak öncül çalışır. ISS uygulamasını ve rol arayüzlerini zaten bildiğinizi varsayacağım .

Gerçek Caruygulamalara rağmen , hiçbir şey bizim ISS uygulamamızı engellemiyor.

//role interfaces 
public interface Billable{
   public int getCosts();
   public int getTaxs();
}

//role interfaces
public interface QualityAssurance{
   public boolean isQualityPass();
}

public class Car implements Billable, QualityAssurance{
   ...
}

public class CarShop {
  ...
  public int getPrice(Billable billable){
     return billable.getCosts() * billable.getTaxs();
  }
}

Burada ne yaptım. Ben arasındaki etkileşimin indirgediğimizi Carve CarShopiçinden Billable arayüz rolü . İmzadaki değişikliğin farkında olun getPrice. Argümanı kasten değiştirdim. Ben CarShopsadece mevcut rol arayüzlerinden birine "bağlı / bağlı" olduğunu açıklamak istedim . Gerçek uygulamayı takip edebilirdim ama gerçek uygulama detaylarını bilmiyorum ve asıl getPrice(String carId)somut sınıf üzerinden erişime (görünürlük) sahip olduğundan korkuyorum . Varsa, ISS ile yapılan tüm işler işe yaramaz hale gelir çünkü döküm yapmak ve yalnızca Billable arabirimi ile çalışmak geliştiricinin elindedir . Ne kadar metodik olursak olalım, ayartma her zaman orada olacaktır.

3. Tek sorumluluk

Korkarım Carve arasındaki bağımlılık HttpClientyeterli olup olmadığını söyleyecek bir pozisyonda değilim , ancak @DocBrown ile katılıyorum, bir tasarım incelemesine değer bazı uyarılar getiriyor. Ne Demeter Yasası ne de İSS tasarımınızı bu noktada "daha iyi" yapamaz. Sorunu maskeleyecekler, düzeltmeyecekler.

DocBrown Strateji Deseni'ni olası bir çözüm olarak önerdim . Desenin karmaşıklık kattığını kabul ettim, ama aynı zamanda herhangi bir yeniden tasarımın da olacağını düşünüyorum . Bu bir değiş tokuş, ne kadar fazla ayrıştırma istiyorsak, o kadar hareketli parçalara sahibiz (genellikle). Her neyse, her ikisinin de yeniden tasarım ile hemfikir olduğunu düşünüyorum.

Özetliyor

Hayır, somut yöntemleri dış sınıflara taşımanıza gerek yoktur, çünkü onları erişilebilir kılmazlar. Sayısız tüketici olabilir. Yeni bir tüketici her oyuna girdiğinde tüm somut yöntemleri dış sınıflara taşır mısınız? Umarım yapmazsın.

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.