SOLID, एनीमिक डोमेन, निर्भरता इंजेक्शन से परहेज?


33

यद्यपि यह एक प्रोग्रामिंग भाषा अज्ञेय प्रश्न हो सकता है, मैं .NET पारिस्थितिकी तंत्र को लक्षित करने वाले उत्तरों में रुचि रखता हूं।

यह परिदृश्य है: मान लीजिए कि हमें सार्वजनिक प्रशासन के लिए एक सरल कंसोल एप्लिकेशन विकसित करने की आवश्यकता है। आवेदन वाहन कर के बारे में है। उनके (केवल) निम्नलिखित व्यावसायिक नियम हैं:

1. ए) यदि वाहन एक कार है और आखिरी बार उसके मालिक ने 30 दिन पहले कर का भुगतान किया था तो मालिक को फिर से भुगतान करना होगा।

1. बी) यदि वाहन एक मोटरबाइक है और पिछली बार उसके मालिक ने 60 दिन पहले कर का भुगतान किया था तो मालिक को फिर से भुगतान करना होगा।

दूसरे शब्दों में, अगर आपके पास एक कार है तो आपको हर 30 दिन में भुगतान करना होगा या यदि आपके पास एक मोटरबाइक है तो आपको हर 60 दिन का भुगतान करना होगा।

सिस्टम में प्रत्येक वाहन के लिए, एप्लिकेशन को उन नियमों का परीक्षण करना चाहिए और उन वाहनों (प्लेट नंबर और मालिक की जानकारी) को प्रिंट करना चाहिए जो उन्हें संतुष्ट नहीं करते हैं।

मुझे क्या चाहिए:

2. एक) ठोस सिद्धांतों (विशेष रूप से ओपन / बंद सिद्धांत) के अनुरूप।

जो मैं नहीं चाहता वह है (मुझे लगता है):

2. बी) एक एनीमिक डोमेन, इसलिए व्यावसायिक तर्क को व्यावसायिक संस्थाओं के अंदर जाना चाहिए।

मैंने इसकी शुरुआत की:

public class Person
// You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
{
    public string Name { get; set; }

    public string Surname { get; set; }
}

public abstract class Vehicle
{
    public string PlateNumber { get; set; }

    public Person Owner { get; set; }

    public DateTime LastPaidTime { get; set; }

    public abstract bool HasToPay();
}

public class Car : Vehicle
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 30;
    }
}

public class Motorbike : Vehicle
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 60;
    }
}

public class PublicAdministration
{
    public IEnumerable<Vehicle> GetVehiclesThatHaveToPay()
    {
        return this.GetAllVehicles().Where(vehicle => vehicle.HasToPay());
    }

    private IEnumerable<Vehicle> GetAllVehicles()
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main(string[] args)
    {
        PublicAdministration administration = new PublicAdministration();
        foreach (var vehicle in administration.GetVehiclesThatHaveToPay())
        {
            Console.WriteLine("Plate number: {0}\tOwner: {1}, {2}", vehicle.PlateNumber, vehicle.Owner.Surname, vehicle.Owner.Name);
        }
    }
}

2. एक: खुले / बंद सिद्धांत की गारंटी है; यदि वे चाहते हैं कि साइकिल टैक्स आपको वाहन से विरासत में मिले, तो आप हसपाय पद्धति को ओवरराइड करें और आपका काम हो जाए। सरल वंशानुक्रम के माध्यम से संतुष्ट खुला / बंद सिद्धांत।

"समस्याएं" हैं:

3. ए) एक वाहन को यह जानना होगा कि क्या उसे भुगतान करना है? एक PublicAdministration चिंता नहीं है? यदि सार्वजनिक प्रशासन कार कर परिवर्तन के लिए नियम बनाता है, तो कार को क्यों बदलना पड़ता है? मुझे लगता है कि आपको पूछना चाहिए: "तो फिर आपने वाहन के अंदर हसोटो विधि क्यों डाली?", और उत्तर है: क्योंकि मैं PublicAdministration के अंदर वाहन के प्रकार (टाइपोफ़) के लिए परीक्षण नहीं करना चाहता। क्या आप एक बेहतर विकल्प देखते हैं?

3. बी) हो सकता है कि कर भुगतान एक वाहन चिंता का विषय है, या हो सकता है कि मेरा प्रारंभिक व्यक्ति-वाहन-कार-मोटरबाइक-पब्लिक एडिशन डिजाइन सिर्फ सादा गलत है, या मुझे एक दार्शनिक और एक बेहतर व्यवसाय विश्लेषक की आवश्यकता है। एक समाधान यह हो सकता है: HasToPay पद्धति को किसी अन्य वर्ग में ले जाएं, हम इसे कर भुगतान कह सकते हैं। फिर हम दो कर भुगतान व्युत्पन्न वर्ग बनाते हैं; CarTaxPayment और MotorbikeTaxPayment। फिर हम वाहन वर्ग में एक अमूर्त भुगतान संपत्ति (प्रकार कर के रूप में) जोड़ते हैं और हम कार और मोटरबाइक वर्गों से सही कर भुगतान उदाहरण वापस करते हैं:

public abstract class TaxPayment
{
    public abstract bool HasToPay();
}

public class CarTaxPayment : TaxPayment
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 30;
    }
}

public class MotorbikeTaxPayment : TaxPayment
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 60;
    }
}

public abstract class Vehicle
{
    public string PlateNumber { get; set; }

    public Person Owner { get; set; }

    public DateTime LastPaidTime { get; set; }

    public abstract TaxPayment Payment { get; }
}

public class Car : Vehicle
{
    private CarTaxPayment payment = new CarTaxPayment();
    public override TaxPayment Payment
    {
        get { return this.payment; }
    }
}

public class Motorbike : Vehicle
{
    private MotorbikeTaxPayment payment = new MotorbikeTaxPayment();
    public override TaxPayment Payment
    {
        get { return this.payment; }
    }
}

और हम पुरानी प्रक्रिया को इस तरह लागू करते हैं:

    public IEnumerable<Vehicle> GetVehiclesThatHaveToPay()
    {
        return this.GetAllVehicles().Where(vehicle => vehicle.Payment.HasToPay());
    }

लेकिन अब यह कोड संकलित नहीं करेगा क्योंकि CarTaxPayment / MotorbikeTaxPayment / TaxPayment के अंदर कोई LastPaidTime सदस्य नहीं है। मैं CarTaxPayment और MotorbikeTaxPayment को व्यावसायिक संस्थाओं के बजाय "एल्गोरिदम कार्यान्वयन" की तरह देखना शुरू कर रहा हूं। किसी तरह अब उन "एल्गोरिदम" को लास्टपेडटाइम वैल्यू की जरूरत है। निश्चित रूप से, हम वैल्यू को टैक्सपेयमेंट के कंस्ट्रक्टर को पास कर सकते हैं, लेकिन यह वाहन एनकैप्सुलेशन या जिम्मेदारियों का उल्लंघन करेगा, या जो ओओपी इंजीलवादी इसे कहते हैं, वह नहीं होगा?

3.c) मान लीजिए कि हमारे पास पहले से ही एक इकाई ढांचा ObjectContext है (जो हमारे डोमेन ऑब्जेक्ट का उपयोग करता है; व्यक्ति, वाहन, कार, मोटरबाइक, PublicAdministration)। आप PublicAdministration.GetAllVehicles विधि से एक ObjectContext संदर्भ प्राप्त करने के लिए कैसे करेंगे और इसलिए फ़ंक्शनलिटी को लागू करेंगे?

3.d) अगर हमें CarTaxPayment.HasToPay के लिए समान ObjectCtetext संदर्भ की आवश्यकता है, लेकिन MotorbikeTaxPayment.HasToPay के लिए एक अलग, जो "इंजेक्शन लगाने" या आप भुगतान कक्षाओं में उन संदर्भों को कैसे पास करेंगे? इस मामले में, एक एनीमिक डोमेन (और इस प्रकार कोई सेवा ऑब्जेक्ट) से परहेज करना, हमें आपदा की ओर नहीं ले जाता है?

इस सरल परिदृश्य के लिए आपके डिज़ाइन विकल्प क्या हैं? स्पष्ट रूप से मैंने जो उदाहरण दिखाए हैं वे एक आसान काम के लिए "बहुत जटिल" हैं, लेकिन साथ ही यह विचार एसओएलआईडी सिद्धांतों का पालन करना है और एनीमिक डोमेन को रोकना है (जिनमें से नष्ट करने के लिए कमीशन किया गया है)।

जवाबों:


15

मैं कहूंगा कि न तो एक व्यक्ति और न ही एक वाहन को पता होना चाहिए कि क्या भुगतान देय है।

समस्या डोमेन reexamining

यदि आप समस्या वाले डोमेन "कार वाले लोगों" को देखते हैं: कार खरीदने के लिए आपके पास किसी प्रकार का अनुबंध है जो एक व्यक्ति से दूसरे व्यक्ति में स्वामित्व स्थानांतरित करता है, तो न तो कार और न ही व्यक्ति उस प्रक्रिया में बदलता है। आपके मॉडल में पूरी तरह से कमी है।

सोचा प्रयोग

एक शादीशुदा जोड़े की मानें तो आदमी कार का मालिक है और वह टैक्स चुका रहा है। अब आदमी मर जाता है, उसकी पत्नी को कार विरासत में मिलती है और वह करों का भुगतान करेगा। फिर भी, आपकी प्लेटें वही रहेंगी (कम से कम मेरे देश में वे)। यह अभी भी वही कार है! आपको अपने डोमेन में वह मॉडल बनाने में सक्षम होना चाहिए।

=> स्वामित्व

एक कार जो किसी के पास नहीं है वह अभी भी एक कार है लेकिन कोई भी इसके लिए करों का भुगतान नहीं करेगा। वास्तव में, आप कार के लिए करों का भुगतान नहीं कर रहे हैं लेकिन कार के मालिक होने के विशेषाधिकार के लिए । तो मेरा प्रस्ताव होगा:

public class Person
{
    public string Name { get; set; }

    public string Surname { get; set; }

    public List<Ownership> getOwnerships();

    public List<Vehicle> getVehiclesOwned();
}

public abstract class Vehicle
{
    public string PlateNumber { get; set; }

    public Ownership currentOwnership { get; set; }

}

public class Car : Vehicle {}

public class Motorbike : Vehicle {}

public abstract class Ownership
{
    public Ownership(Vehicle vehicle, Owner owner);

    public Vehicle Vehicle { get;}

    public Owner CurrentOwner { get; set; }

    public abstract bool HasToPay();

    public DateTime LastPaidTime { get; set; }

   //Could model things like payment history or owner history here as well
}

public class CarOwnership : Ownership
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 30;
    }
}

public class MotorbikeOwnership : Ownership
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 60;
    }
}

public class PublicAdministration
{
    public IEnumerable<Ownership> GetVehiclesThatHaveToPay()
    {
        return this.GetAllOwnerships().Where(HasToPay());
    }

}

यह सही से बहुत दूर है और शायद सही सी # कोड भी नहीं है, लेकिन मुझे उम्मीद है कि आपको यह विचार मिल जाएगा (और कोई इसे साफ कर सकता है)। केवल नकारात्मक पक्ष यह है कि आपको CarOwnershipCarऔर ए के बीच सही बनाने के लिए संभवतः एक कारखाने या कुछ की आवश्यकता होगीPerson


मुझे लगता है कि वाहन को अपने लिए भुगतान किए गए करों को रिकॉर्ड करना चाहिए, और व्यक्तियों को अपने सभी वाहनों के लिए भुगतान किए गए करों को रिकॉर्ड करना चाहिए। एक टैक्स कोड इसलिए लिखा जा सकता है कि अगर कार पर कर का भुगतान 1 जून को किया जाता है और इसे 10 जून को बेचा जाता है, तो नया मालिक 10 जून, 1 जुलाई या 10 जुलाई को कर के लिए उत्तरदायी हो सकता है (और भले ही यह हो वर्तमान में एक तरीका यह बदल सकता है)। यदि 30-दिवसीय नियम स्वामित्व परिवर्तन के माध्यम से भी कार के लिए स्थिर है, लेकिन जिन कारों पर किसी का बकाया नहीं है, वे करों का भुगतान नहीं कर सकते हैं, तो मैं सुझाव दूंगा कि जब कोई कार जो 30 या उससे अधिक दिनों के लिए अज्ञात थी, तो खरीदी जाती है, कर भुगतान ...
सुपरकैट

... एक काल्पनिक "अज्ञात वाहन कर क्रेडिट" व्यक्ति से दर्ज करें, ताकि बिक्री के समय के रूप में कर देयता या तो शून्य या तीस दिन होगी, चाहे वाहन कितने समय तक अज्ञात रहा हो।
सुपरकैट

4

मुझे लगता है कि इस तरह की स्थिति में, जहां आप चाहते हैं कि व्यावसायिक नियम लक्ष्य वस्तुओं के बाहर मौजूद हों, प्रकार के लिए परीक्षण स्वीकार्य से अधिक है।

निश्चित रूप से, कई स्थितियों में आपको एक रणनीति पैटर का उपयोग करना चाहिए और वस्तुओं को खुद को संभालने देना चाहिए, लेकिन यह हमेशा वांछनीय नहीं है।

वास्तविक दुनिया में, एक क्लर्क वाहन के प्रकार को देखता है और उसी के आधार पर उसके कर डेटा को देखता है। आपके सॉफ़्टवेयर को एक ही Busienss नियम का पालन क्यों नहीं करना चाहिए?


ठीक है, कहते हैं कि आपने मुझे आश्वस्त किया और GetVehiclesThatHaveToPay विधि से हम वाहन के प्रकार का निरीक्षण करते हैं। LastPaidTime के लिए किसे जिम्मेदार होना चाहिए? LastPaidTime एक वाहन चिंता या एक PublicAdministration एक है? क्योंकि अगर यह एक वाहन है, तो क्या उस व्यावसायिक तर्क को वाहन में नहीं रहना चाहिए? आप मुझे प्रश्न 3.c के बारे में क्या बता सकते हैं?

@DavidRobertJones - आदर्श रूप से, मैं वाहन लाइसेंस के आधार पर भुगतान इतिहास लॉग में अंतिम भुगतान देखूंगा। एक कर भुगतान एक कर चिंता है, वाहन चिंता नहीं।
एरिक फनकेनबस

5
@DavidRobertJones मुझे लगता है कि आप अपने रूपक के साथ खुद को भ्रमित कर रहे हैं। आपके पास एक वास्तविक वाहन नहीं है जो एक वाहन के सभी कामों को करने की आवश्यकता है। इसके बजाय, आपने नाम दिया है, सादगी के लिए एक TaxableVehicle (या कुछ समान) एक वाहन। आपका संपूर्ण डोमेन कर भुगतान है। चिंता मत करो कि वास्तविक वाहन क्या करते हैं। और, यदि आवश्यक हो तो रूपक को छोड़ दें और अधिक उपयुक्त के साथ आएं।

3

जो मैं नहीं चाहता वह है (मुझे लगता है):

2. बी) एक एनीमिक डोमेन, जिसका अर्थ व्यावसायिक संस्थाओं के अंदर व्यावसायिक तर्क है।

आपके पास यह पीछे है। एनीमिक डोमेन वह है जो लॉजिक व्यावसायिक संस्थाओं के बाहर है। तर्क को लागू करने के लिए अतिरिक्त कक्षाओं का उपयोग करने के कई कारण हैं, एक बुरा विचार है; और केवल एक जोड़े के लिए आपको ऐसा क्यों करना चाहिए।

इसलिए इसका कारण एनीमिक कहा जाता है: वर्ग में कुछ भी नहीं है ।।

मुझे क्या करना होगा:

  1. अपने सार वाहन वर्ग को एक इंटरफ़ेस के रूप में बदलें।
  2. एक ITaxPayment इंटरफ़ेस जोड़ें जो वाहनों को लागू करना चाहिए। अपने HasToPay को यहां से लटका दें।
  3. MotorbikeTaxPayment, CarTaxPayment, TaxPayment classes निकालें। वे अनावश्यक जटिलताओं / अव्यवस्था हैं।
  4. प्रत्येक वाहन के प्रकार (कार, बाइक, मोटरहोम) को एक न्यूनतम वाहन पर लागू किया जाना चाहिए और यदि उन पर कर लगता है, तो उन्हें ITaxPayment भी लागू करना चाहिए। इस तरह से आप उन वाहनों के बीच में कटौती कर सकते हैं जिन पर कर नहीं लगे हैं और जो हैं ... इस स्थिति को भी मानते हैं।
  5. प्रत्येक वाहन के प्रकार को लागू करना चाहिए, कक्षा की सीमाओं के भीतर, आपके इंटरफेस में परिभाषित तरीके।
  6. इसके अलावा, अपने ITaxPayment इंटरफ़ेस में अंतिम भुगतान तिथि जोड़ें।

आप सही हे। मूल रूप से प्रश्न को इस तरह तैयार नहीं किया गया था, मैंने एक भाग को हटा दिया और अर्थ बदल गया। यह अब तय हो गया है। धन्यवाद!

2

क्यों एक वाहन को यह जानना पड़ता है कि क्या उसे भुगतान करना है? एक PublicAdministration चिंता नहीं है?

नहीं, जैसा कि मैं समझता हूं कि आपका पूरा ऐप कर लगाने के बारे में है। तो इस बात की चिंता कि क्या किसी वाहन पर कर लगाया जाना चाहिए, सार्वजनिक उपक्रम की चिंता नहीं है तो पूरे कार्यक्रम में कुछ और। कहीं और लगाने का कोई कारण नहीं है लेकिन यहां।

public class Car : Vehicle
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 30;
    }
}

public class Motorbike : Vehicle
{
    public override bool HasToPay()
    {
        return (DateTime.Today - this.LastPaidTime).TotalDays >= 60;
    }
}

ये दो कोड स्निपेट केवल स्थिरांक से भिन्न होते हैं। पूरे HasToPay () फ़ंक्शन को ओवरराइड करने के बजाय एक int DaysBetweenPayments()फ़ंक्शन को ओवरराइड करें । निरंतर का उपयोग करने के बजाय कॉल करें। अगर यह सब वास्तव में अलग है, तो मैं कक्षाएं छोड़ दूंगा।

मैं यह भी सुझाव दूंगा कि मोटरबाइक / कार वाहन की श्रेणी की संपत्ति होनी चाहिए, बल्कि उपवर्ग की। यह आपको अधिक लचीलापन देता है। उदाहरण के लिए, मोटरबाइक या कार की श्रेणी को बदलना आसान बनाता है। बेशक बाइक वास्तविक जीवन में कारों में तब्दील होने की संभावना नहीं है। लेकिन आप जानते हैं कि एक वाहन गलत हो रहा है और बाद में बदलने की जरूरत है।

निश्चित रूप से, हम वैल्यू को टैक्सपेयमेंट के कंस्ट्रक्टर को पास कर सकते हैं, लेकिन यह वाहन एनकैप्सुलेशन या जिम्मेदारियों का उल्लंघन करेगा, या जो ओओपी इंजीलवादी इसे कहते हैं, वह नहीं होगा?

ज़रुरी नहीं। एक वस्तु जो एक पैरामीटर के रूप में जानबूझकर अपने डेटा को किसी अन्य ऑब्जेक्ट को पास करती है, एक बड़ा एनकैप्सुलेशन चिंता नहीं है। वास्तविक चिंता इस वस्तु के अंदर पहुंचने वाली अन्य वस्तुओं को डेटा को खींचने या वस्तु के अंदर डेटा को हेरफेर करने की है।


1

आप सही रास्ते पर हो सकते हैं। समस्या यह है, जैसा कि आपने देखा है, कि TaxPayment के अंदर कोई LastPaidTime सदस्य नहीं है । यह वास्तव में जहां यह है, हालांकि इसे सार्वजनिक रूप से उजागर करने की आवश्यकता नहीं है:

public interface ITaxPayment
{
    // Your base TaxPayment class will know the 
    // next due date. But you can easily create
    // one which uses (for example) fixed dates
    bool IsPaymentDue();
}

public interface IVehicle
{
    string Plate { get; }
    Person Owner { get; }
    ITaxPayment LastTaxPayment { get; }
} 

हर बार जब आप भुगतान प्राप्त करते हैं, तो आप ITaxPaymentवर्तमान नीतियों के अनुसार एक नया उदाहरण बनाते हैं, जिसमें पिछले एक की तुलना में पूरी तरह से अलग नियम हो सकते हैं।


बात यह है कि देय भुगतान अंतिम समय पर मालिक द्वारा भुगतान (अलग-अलग वाहन, अलग-अलग देय तिथियां) पर निर्भर करता है। आईटैक्सपाइमेंट कैसे पता करता है कि गणना करने के लिए पिछली बार किसी वाहन (या मालिक) को भुगतान किया गया था?

1

मैं @sebastiangeiger के जवाब से सहमत हूं कि समस्या वास्तव में वाहनों के बजाय वाहन मालिकों के बारे में है। मैं उनके उत्तर का उपयोग करने का सुझाव देने जा रहा हूं लेकिन कुछ बदलावों के साथ। मैं Ownershipकक्षा को एक सामान्य वर्ग बनाऊंगा:

public class Vehicle {}

public abstract class Ownership<T>
{
    public T Item { get; set; }

    public DateTime LastPaidTime { get; set; }

    public abstract TimeSpan PaymentInterval { get; }

    public virtual bool HasToPay
    {
        get { return (DateTime.Today - this.LastPaidTime) >= this.PaymentInterval; }
    }
}

और प्रत्येक वाहन प्रकार के लिए भुगतान अंतराल निर्दिष्ट करने के लिए वंशानुक्रम का उपयोग करें। मैं यह भी सुझाव देता हूं कि TimeSpanसादे पूर्णांक के बजाय दृढ़ता से टाइप की गई कक्षा का उपयोग करें :

public class CarOwnership : Ownership<Vehicle>
{
    public override TimeSpan PaymentInterval
    {
        get { return new TimeSpan(30, 0, 0, 0); }
    }
}

public class MotorbikeOwnership : Ownership<Vehicle>
{
    public override TimeSpan PaymentInterval
    {
        get { return new TimeSpan(60, 0, 0, 0); }
    }
}

अब आप अपने वास्तविक कोड केवल एक वर्ग के साथ सौदा करने की जरूरत है - Ownership<Vehicle>

public class PublicAdministration
{
    List<Ownership<Vehicle>> VehicleOwnerships { get; set; }

    public IEnumerable<Vehicle> GetVehiclesThatHaveToPay()
    {
        return VehicleOwnerships.Where(x => x.HasToPay).Select(x => x.Item);
    }
}

0

मुझे आपसे इसे तोड़ने से नफरत है, लेकिन आपके पास एक एनीमिक डोमेन है , अर्थात वस्तुओं के बाहर व्यावसायिक तर्क। यदि आप इसके लिए जा रहे हैं तो ठीक है, लेकिन आपको किसी से बचने के कारणों के बारे में पढ़ना चाहिए।

समस्या डोमेन को मॉडल न करने की कोशिश करें, लेकिन समाधान मॉडल करें। यही कारण है कि आप समानांतर विरासत पदानुक्रम और अपनी आवश्यकता से अधिक जटिलता के साथ समाप्त हो रहे हैं।

कुछ इस तरह से आप उस उदाहरण के लिए की जरूरत है:

public class Vehicle
{
    public Boolean isMotorBike()
    public string PlateNumber { get; set; }
    public String Owner { get; set; }
    public DateTime LastPaidTime { get; set; }
}

public class TaxPaymentCalculator
{
    public List<Vehicle> GetVehiclesThatHaveToPay(List<Vehicle> all)
}

यदि आप SOLID का अनुसरण करना चाहते हैं, जो महान है, लेकिन जैसा कि अंकल बॉब ने खुद कहा, वे सिर्फ इंजीनियरिंग सिद्धांत हैं । वे कड़ाई से लागू करने के लिए नहीं हैं, लेकिन ऐसे दिशानिर्देश हैं जिन पर विचार किया जाना चाहिए।


4
मुझे लगता है कि आपका समाधान विशेष रूप से स्केलेबल नहीं है। आपको प्रत्येक प्रकार के वाहन को जोड़ने के लिए एक नया बूलियन जोड़ने की आवश्यकता होगी। मेरी राय में यह एक खराब विकल्प है।
एरिक Funkenbusch

@ ग्रेट हॉल, मुझे अच्छा लगा कि आपने मेरे "डोमेन" से व्यक्ति वर्ग को हटा दिया। मैं पहली बार में उस वर्ग नहीं होगा, तो इस बारे में खेद है। लेकिन मोटरबाइक का कोई मतलब नहीं है। कौन सा कार्यान्वयन होगा?

1
@DavidRobertJones: मैं मिस्टेर के साथ सहमत हूं, एक isMotorBikeविधि जोड़ना एक अच्छा ओओपी डिज़ाइन विकल्प नहीं है। यह एक प्रकार के कोड के साथ बहुरूपता को बदलने की तरह है (यद्यपि एक बूलियन एक)।
ग्रू

@MystereMan, एक आसानी से bools ड्रॉप और एक इस्तेमाल कर सकते हैंenum Vehicles
radarbob

+1। समस्या डोमेन को मॉडल न करने की कोशिश करें, लेकिन समाधान मॉडल करेंपिथी । यादगार कहा। और सिद्धांत टिप्पणी करते हैं। मैं सख्त शाब्दिक व्याख्या में बहुत सारे प्रयास देखता हूं ; बकवास।
राडारबॉब

0

मुझे लगता है कि आप सही हैं कि भुगतान अवधि वास्तविक कार / मोटरबाइक की संपत्ति नहीं है। लेकिन यह वाहन के वर्ग का एक गुण है।

हालांकि, आप ऑब्जेक्ट के प्रकार पर एक / / का चयन करने की सड़क से नीचे जा सकते हैं, यह बहुत स्केलेबल नहीं है। यदि आप बाद में लॉरी और सेगवे को जोड़ते हैं और बाइक और बस और हवाई जहाज को धक्का देते हैं (संभावना नहीं लगती है, लेकिन आप सार्वजनिक सेवाओं के साथ कभी नहीं जानते हैं) तो स्थिति बड़ी हो जाती है। और अगर आप लॉरी के लिए नियमों को बदलना चाहते हैं, तो आपको इसे उस सूची में ढूंढना होगा।

तो क्यों नहीं इसे बनाने के लिए, सचमुच, एक विशेषता और प्रतिबिंब का उपयोग इसे बाहर खींचने के लिए? कुछ इस तरह:

[DaysBetweenPayments(30)]
public class Car : Vehicle
{
    // actual properties of the physical vehicle
}

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class DaysBetweenPaymentsAttribute : Attribute, IPaymentRequiredCalculator
{
    private int _days;

    public DaysBetweenPaymentAttribute(int days)
    {
        _days = days;
    }

    public bool HasToPay(Vehicle vehicle)
    {
        return vehicle.LastPaid.AddDays(_days) <= DateTime.Now;
    }
}

आप एक स्थिर वैरिएबल के साथ भी जा सकते हैं, अगर वह अधिक आरामदायक हो।

डाउनसाइड्स हैं

  • यह थोड़ा धीमा होगा, और मुझे लगता है कि आपको बहुत सारे वाहनों को संसाधित करना होगा। अगर यह एक मुद्दा है तो मैं अधिक व्यावहारिक दृष्टिकोण ले सकता हूं और अमूर्त संपत्ति या इंटरलेक्टेड दृष्टिकोण के साथ रह सकता हूं। (हालांकि, मैं कैशिंग पर विचार करूँगा टाइप भी।)

  • आपको स्टार्टअप पर मान्य करना होगा कि प्रत्येक वाहन उपवर्ग में एक IPaymentRequiredCalculator विशेषता है (या एक डिफ़ॉल्ट की अनुमति है), क्योंकि आप इसे 1000 कारों को संसाधित करने के लिए नहीं चाहते हैं, केवल दुर्घटना के लिए, क्योंकि मोटरबाइक के पास पेमेंटपॉयरोडिक नहीं है।

उल्टा यह है कि यदि आप बाद में एक कैलेंडर माह या वार्षिक भुगतान में आते हैं, तो आप केवल एक नया विशेषता वर्ग लिख सकते हैं। यह OCP की बहुत परिभाषा है।


इसके साथ प्रमुख मुद्दा यह है कि यदि आप किसी वाहन के लिए भुगतानों के बीच दिनों की संख्या को बदलना चाहते हैं, तो आपको पुनर्निर्माण और पुनर्वितरण की आवश्यकता होगी, और यदि भुगतान आवृत्ति इकाई की संपत्ति के आधार पर भिन्न होती है (जैसे इंजन आकार) उस के लिए एक सुंदर तय करना मुश्किल है।
एड जेम्स

@ एडवर्ड: मुझे लगता है कि पहला मुद्दा अधिकांश समाधानों का सच है और यह वास्तव में मुझे चिंतित नहीं करेगा। यदि वे लचीलेपन के उस स्तर को बाद में चाहते हैं, तो मैं उन्हें एक डीबी एप्लिकेशन दूंगा। दूसरे बिंदु पर, मैं पूरी तरह से असहमत हूं। उस बिंदु पर, आप बस वाहन को वैकल्पिक तर्क के रूप में HasToPay () में जोड़ें और इसे अनदेखा करें जहां आपको इसकी आवश्यकता नहीं है।
pdr

मुझे लगता है कि यह ऐप के लिए आपके द्वारा दी गई दीर्घकालिक योजनाओं पर निर्भर करता है, साथ ही क्लाइंट की विशेष आवश्यकताएं, जैसे कि क्या यह डीबी में प्लगिंग के लायक है यदि कोई पहले से मौजूद नहीं है (मुझे लगता है कि बहुत सारे सॉफ्टवेयर डीबी हैं -ड्राइव, जो मुझे पता है कि हमेशा ऐसा नहीं होता है)। हालांकि, दूसरे बिंदु पर, महत्वपूर्ण क्वालिफायर सुरुचिपूर्ण है ; मैं यह नहीं कहूंगा कि एक विशेषता पर एक विधि के लिए एक अतिरिक्त पैरामीटर जोड़ना, फिर उस वर्ग का एक उदाहरण लेता है जो विशेषता संलग्न है एक विशेष रूप से सुरुचिपूर्ण समाधान है। लेकिन, फिर से, यह आपके ग्राहक की आवश्यकताओं पर निर्भर करता है।
एड जेम्स

@EdWoodcock: असल में, मैं सिर्फ इस बारे में सोच रहा था और अंतिम भुगतान तर्क पहले से ही वाहन की संपत्ति होने जा रहा है। आपकी टिप्पणी को ध्यान में रखते हुए, यह उस तर्क को प्रतिस्थापित करने के लायक हो सकता है, बजाय बाद में - संपादित करेगा।
पीडीआर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.