केवल एक कोड गंध के साथ एक अंतरफलक है?


10

(मैंने इस प्रश्न को देखा है , लेकिन पहला उत्तर ऑटो प्रॉपर्टी के बारे में डिज़ाइन से अधिक है, और दूसरा कहता है कि उपभोक्ता से डेटा स्टोरेज कोड छिपाएं , जो मुझे यकीन नहीं है कि मुझे क्या चाहिए / मेरा कोड है) इसलिए मैं कुछ अन्य राय सुनना चाहूंगा)

मैं दो बहुत ही इसी तरह की संस्थाओं, है HolidayDiscountऔर RentalDiscount, कि के रूप में लंबाई छूट प्रतिनिधित्व करते हैं 'अगर यह रहता है कम से कम numberOfDays, एक percentछूट लागू होता है'। तालिकाओं में अलग-अलग मूल संस्थाओं के लिए fks हैं, और विभिन्न स्थानों में उपयोग किए जाते हैं, लेकिन जहां उनका उपयोग किया जाता है, अधिकतम अधिकतम छूट प्राप्त करने के लिए एक सामान्य तर्क है। उदाहरण के लिए, एक HolidayOfferसंख्या है HolidayDiscounts, और इसकी लागत की गणना करते समय, हमें लागू छूट का पता लगाने की आवश्यकता है। किराए के लिए और RentalDiscounts

चूंकि तर्क समान है, मैं इसे एक ही स्थान पर रखना चाहता हूं। निम्नलिखित विधि, विधेय और तुलनित्र क्या करते हैं:

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());
    }
}

चूंकि केवल आवश्यक जानकारी ही दिनों की संख्या है, इसलिए मैं एक इंटरफ़ेस के साथ समाप्त करता हूं

public interface LengthDiscount {

    Integer getNumberOfDays();
}

और दो संस्थाओं

@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;
    }
}

इंटरफ़ेस में एक एकल गेट्टर विधि है जिसे दो संस्थाएं लागू करती हैं, जो बेशक काम करती हैं, लेकिन मुझे संदेह है कि यह एक अच्छा डिजाइन है। यह किसी भी व्यवहार का प्रतिनिधित्व नहीं करता है, एक मूल्य पकड़े यह एक संपत्ति नहीं है। यह एक सरल मामला है, मेरे पास कुछ इसी तरह के और अधिक जटिल मामले हैं (3-4 गेटर्स के साथ)।

मेरा सवाल यह है कि क्या यह एक बुरा डिज़ाइन है? एक बेहतर तरीका क्या है?


4
एक इंटरफ़ेस का उद्देश्य कनेक्शन का एक पैटर्न स्थापित करना है, न कि व्यवहार का प्रतिनिधित्व करना। यह कर्तव्य कार्यान्वयन में विधियों के लिए आता है।
रॉबर्ट हार्वे

आपके कार्यान्वयन के रूप में, बॉयलरप्लेट का एक बहुत कुछ है (कोड जो वास्तव में कुछ भी नहीं करता है, संरचना प्रदान करने के अलावा)। क्या आप वाकई इसके लिए आवश्यक हैं?
रॉबर्ट हार्वे

यहां तक ​​कि इंटरफ़ेस के तरीके केवल 'गेटर्स' हैं इसका मतलब यह नहीं है कि आप कार्यान्वयन पर 'सेटलर्स' को लागू नहीं कर सकते हैं (यदि सभी में सेटर है, तो आप अभी भी एक सार का उपयोग कर सकते हैं)
рüффп

जवाबों:


5

मैं कहूंगा कि आपका डिज़ाइन थोड़ा गुमराह करने वाला है।

एक संभावित समाधान एक इंटरफ़ेस बनाने के लिए होगा जिसे कहा जाता है IDiscountCalculator

decimal CalculateDiscount();

अब किसी भी वर्ग को छूट प्रदान करने की आवश्यकता है जो इस इंटरफ़ेस को लागू करेगा। यदि छूट दिनों की संख्या का उपयोग करता है, तो ऐसा ही हो, इंटरफ़ेस वास्तव में परवाह नहीं करता है क्योंकि कार्यान्वयन विवरण है।

यदि सभी छूट वर्गों को इस डेटा सदस्य की आवश्यकता है, तो दिनों की संख्या शायद किसी प्रकार के सार आधार वर्ग से संबंधित है। यदि यह वर्ग विशेष है, तो बस एक संपत्ति की घोषणा करें जिसे सार्वजनिक या निजी रूप से आवश्यकता के आधार पर एक्सेस किया जा सकता है।


1
मुझे यकीन नहीं है कि मैं पूरी तरह से होने HolidayDiscountऔर RentalDiscountलागू होने से सहमत हूं IDiscountCalculator, क्योंकि वे छूट कैलकुलेटर नहीं हैं। गणना उस अन्य विधि में की जाती है getMaxApplicableLengthDiscountHolidayDiscountऔर RentalDiscountछूट हैं। छूट की गणना नहीं की जाती है, एक प्रकार की लागू छूट होती है जो गणना की जाती है, या केवल कई छूटों के बीच चयन किया जाता है।
user3748908

1
हो सकता है कि इंटरफ़ेस को IDiscountable कहा जाना चाहिए। जो भी वर्गों को लागू करने की आवश्यकता हो सकती है। यदि अवकाश / किराये की छूट की कक्षाएं सिर्फ डीटीओ / पीओसीओ हैं और गणना करने के बजाय परिणाम ठीक है।
जॉन रेन्नोर

3

अपने प्रश्न का उत्तर देने के लिए: आप एक कोड गंध का निष्कर्ष नहीं निकाल सकते हैं यदि एक इंटरफ़ेस में केवल गेटर्स हैं।

कोड महक के लिए एक फजी मीट्रिक के लिए एक उदाहरण कई तरीकों के साथ फूला हुआ इंटरफेस है (यदि नहीं मिलता है या नहीं)। वे इंटरफ़ेस पृथक्करण सिद्धांत का उल्लंघन करते हैं।

शब्दार्थ स्तर पर एकल जिम्मेदारी सिद्धांत का भी उल्लंघन नहीं किया जाना चाहिए। यदि आप इंटरफ़ेस कॉन्ट्रैक्ट में कई अलग-अलग मुद्दों को देखते हैं, तो आप उल्लंघन कर सकते हैं, जो एक विषय नहीं है। यह कभी-कभी पहचानना मुश्किल होता है और आपको इसे पहचानने के लिए कुछ अनुभव की आवश्यकता होती है।

यदि आपका इंटरफ़ेस निर्धारित करता है तो दूसरी तरफ आपको जागरूक होना चाहिए। ऐसा इसलिए है क्योंकि बसे राज्य बदलने की संभावना रखते हैं, यही उनका काम है। यहां पूछे जाने वाले प्रश्न: क्या इंटरफ़ेस के पीछे की वस्तु एक वैध राज्य से दूसरे वैध राज्य में संक्रमण करती है। लेकिन यह मुख्य रूप से इंटरफ़ेस की समस्या नहीं है, बल्कि कार्यान्वयन ऑब्जेक्ट के इंटरफ़ेस अनुबंध का कार्यान्वयन है।

आपके दृष्टिकोण के साथ एकमात्र चिंता यह है कि आप OR-Mappings पर काम करते हैं। इस छोटे से मामले में यह समस्या नहीं है। तकनीकी रूप से यह ठीक है। लेकिन मैं OR- मैप की गई वस्तुओं पर काम नहीं करूंगा। उनके पास बहुत से अलग-अलग राज्य हो सकते हैं जिन पर आप निश्चित रूप से उन पर किए गए कार्यों पर विचार नहीं करेंगे ...

OR-Mapped ऑब्जेक्ट्स हो सकते हैं (JPA को प्रीसिप्ट करें), लगातार अलग अपरिवर्तित, लगातार अटैच अपरिवर्तित, लगातार डिटैच्ड चेंज, लगातार अटैच चेंज… यदि आप उन ऑब्जेक्ट्स पर बीन वैरिफिकेशन का उपयोग करते हैं जो ऑब्जेक्ट की जांच की गई थी या नहीं, तो आप आगे नहीं कर सकते। आखिरकार आप 10 से अधिक विभिन्न राज्यों की पहचान कर सकते हैं और ओआर-मैप्ड ऑब्जेक्ट हो सकते हैं। क्या आपके सभी ऑपरेशन इन राज्यों को ठीक से संभालते हैं?

यह निश्चित रूप से कोई समस्या नहीं है यदि आपका इंटरफ़ेस अनुबंध को परिभाषित करता है और कार्यान्वयन इसका अनुसरण करता है। लेकिन ओआर-मैप्ड ऑब्जेक्ट्स के लिए मेरे पास उचित संदेह है, इस तरह के अनुबंध को पूरा कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.