Sadece alıcıları olan bir arayüz kod kokusu mu?


10

( Bu soruyu gördüm , ancak ilk cevap, tasarımdan daha fazla otomatik özelliklerle ilgili ve ikincisi , veri depolama kodunu tüketiciden gizlediğini söylüyor , istediğimden emin değilim / kodum ne yapıyor, başka bir fikir duymak istiyorum)

Ben iki çok benzer varlıkları, sahip HolidayDiscountve RentalDiscount'o en azından sürerse olarak uzunluk indirimler temsil numberOfDays, bir percentindirim uygulanabilir.' Tablolarda farklı üst varlıklar için fks'ler vardır ve farklı yerlerde kullanılırlar, ancak kullanıldıkları yerde, uygulanabilir maksimum indirimi almak için ortak bir mantık vardır. Örneğin, HolidayOffera'nın bir sayısı vardır HolidayDiscountsve maliyetini hesaplarken geçerli indirimi bulmamız gerekir. Aynı kiralık ve RentalDiscounts.

Mantık aynı olduğundan, onu tek bir yerde tutmak istiyorum. Aşağıdaki yöntem, yüklem ve karşılaştırıcı bunu yapar:

Optional<LengthDiscount> getMaxApplicableLengthDiscount(List<LengthDiscount> discounts, int daysToStay) {
    if (discounts.isEmpty()) {
        return Optional.empty();
    }
    return discounts.stream()
            .filter(new DiscountIsApplicablePredicate(daysToStay))
            .max(new DiscountMinDaysComparator());
}

public class DiscountIsApplicablePredicate implements Predicate<LengthDiscount> {

    private final long daysToStay;

    public DiscountIsApplicablePredicate(long daysToStay) {
        this.daysToStay = daysToStay;
    }

    @Override
    public boolean test(LengthDiscount discount) {
        return daysToStay >= discount.getNumberOfDays();
    }
}

public class DiscountMinDaysComparator implements Comparator<LengthDiscount> {

    @Override
    public int compare(LengthDiscount d1, LengthDiscount d2) {
        return d1.getNumberOfDays().compareTo(d2.getNumberOfDays());
    }
}

İhtiyaç duyulan tek bilgi gün sayısı olduğundan, bir arayüzle

public interface LengthDiscount {

    Integer getNumberOfDays();
}

Ve iki varlık

@Entity
@Table(name = "holidayDiscounts")
@Setter
public class HolidayDiscount implements LengthDiscount {

    private BigInteger percent;

    private Integer numberOfDays;

    public BigInteger getPercent() {
        return percent;
    }

    @Override
    public Integer getNumberOfDays() {
        return numberOfDays;
    }

}

@Entity
@Table(name = "rentalDiscounts")
@Setter
public class RentalDiscount implements LengthDiscount {

    private BigInteger percent;

    private Integer numberOfDays;

    public BigInteger getPercent() {
        return percent;
    }

    @Override
    public Integer getNumberOfDays() {
        return numberOfDays;
    }
}

Arayüz, iki varlığın uyguladığı, elbette işe yarayan tek bir alıcı yöntemine sahiptir, ancak iyi bir tasarım olduğundan şüpheliyim. Değer tutmanın bir özellik olmadığı göz önüne alındığında hiçbir davranışı temsil etmez. Bu oldukça basit bir durum, birkaç tane daha benzer, daha karmaşık durum var (3-4 alıcılı).

Sorum şu: Bu kötü bir tasarım mı? Daha iyi bir yaklaşım nedir?


4
Bir arayüzün amacı, davranışı temsil etmek için değil, bir bağlantı modeli oluşturmaktır. Bu görev, uygulamadaki yöntemlere düşer.
Robert Harvey

Uygulamanıza gelince, çok sayıda kaynatma plakası var (yapı sağlamaktan başka hiçbir şey yapmayan kod). Hepsine ihtiyacınız olduğundan emin misiniz?
Robert Harvey

Arayüzün yöntemleri bile sadece 'alıcılar', uygulama üzerinde 'ayarlayıcıları' uygulayamayacağınız anlamına gelmez (eğer ayarlayıcı varsa, yine de bir soyut kullanabilirsiniz)
рüффп

Yanıtlar:


5

Tasarımınızın biraz yanlış yönlendirildiğini söyleyebilirim.

Potansiyel bir çözüm, denilen bir arayüz oluşturmak olacaktır IDiscountCalculator.

decimal CalculateDiscount();

Şimdi indirim sağlaması gereken herhangi bir sınıf bu arayüzü uygulayacaktır. İndirim gün sayısını kullanıyorsa, arayüz uygulama ayrıntıları olduğu için gerçekten umursamıyor.

Tüm indirim sınıflarının bu veri üyesine ihtiyacı varsa gün sayısı muhtemelen bir çeşit soyut temel sınıfa aittir. Sınıfa özelse, ihtiyaca bağlı olarak genel veya özel olarak erişilebilen bir mülk beyan edin.


1
Sahip olmayı HolidayDiscountve RentalDiscountuygulamayı tamamen kabul ettiğimden emin değilim IDiscountCalculator, çünkü indirim hesaplayıcıları değiller. Hesaplama bu diğer yöntemde yapılır getMaxApplicableLengthDiscount. HolidayDiscountve RentalDiscountindirimler. Bir indirim hesaplanmaz, hesaplanan veya sadece bir dizi indirim arasından seçilen geçerli bir indirim türüdür.
user3748908

1
Belki Arayüz IDiscountable olarak adlandırılmalıdır. Sınıfların uygulaması gereken her şey olabilir. Tatil / kiralık indirim sınıfları sadece DTO / POCO ise ve hesaplamak yerine sonucu saklamak iyi.
Jon Raynor

3

Sorunuzu cevaplamak için: Bir arayüzde yalnızca alıcılar varsa kod kokusunu tamamlayamazsınız.

Kod kokuları için bulanık bir metrik örneği, birçok yöntemle şişirilmiş arayüzlerdir (alıcılar olsun ya da olmasın). Arayüz ayrımcılığı ilkesini ihlal etme eğilimindedirler.

Anlamsal düzeyde, tek sorumluluk ilkesi de ihlal edilmemelidir. Arayüz sözleşmesinde ele alınan bir konu olmayan birkaç farklı sorun görürseniz ihlal edilme eğilimindeyim. Bunu tanımlamak bazen zordur ve tanımlamak için biraz deneyime ihtiyacınız vardır.

Diğer tarafta, arayüzünüzün ayarlayıcıları tanımlayıp tanımlamadığını bilmeniz gerekir. Çünkü pasörlerin durumu değiştirmesi muhtemeldir, bu onların işi. Burada sorulması gereken soru: Arayüzün arkasındaki nesne geçerli bir durumdan başka bir geçerli duruma geçiş yapıyor mu? Ancak bu esas olarak arayüzün bir sorunu değil, uygulama nesnesinin arayüz sözleşmesinin uygulanmasıdır.

Yaklaşımınızla ilgili tek endişem OR-Mappings üzerinde çalışmanızdır. Bu küçük durumda bu bir sorun değil. Teknik olarak sorun değil. Ancak OR-Mapped nesneleri üzerinde işlem yapmam. Onlara yapılan operasyonlarda kesinlikle dikkate almadığınız çok fazla farklı duruma sahip olabilirler ...

VEYA Eşlenen nesneler geçici olabilir (JPA varsayalım) geçici, kalıcı müstakil değişmemiş, kalıcı iliştirilmiş değişmemiş, kalıcı müstakil değişmiş, kalıcı iliştirilmiş değişmiş olabilir ... bu nesnelerde fasulye geçerliliği kullanırsanız, nesnenin kontrol edilip edilmediğini daha fazla göremezsiniz. Sonuçta OR-Mapped nesnesinin sahip olabileceği 10'dan fazla farklı durum tanımlayabilirsiniz. Tüm operasyonlarınız bu durumları uygun şekilde ele alıyor mu?

Arayüzünüz sözleşmeyi tanımlarsa ve uygulama bunu takip ederse, bu kesinlikle sorun değildir. Ancak OR-eşlemeli nesneler için böyle bir sözleşmeyi yerine getirebileceğinden şüphe duyuyorum.

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.