यद्यपि यह एक प्रोग्रामिंग भाषा अज्ञेय प्रश्न हो सकता है, मैं .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 के लिए एक अलग, जो "इंजेक्शन लगाने" या आप भुगतान कक्षाओं में उन संदर्भों को कैसे पास करेंगे? इस मामले में, एक एनीमिक डोमेन (और इस प्रकार कोई सेवा ऑब्जेक्ट) से परहेज करना, हमें आपदा की ओर नहीं ले जाता है?
इस सरल परिदृश्य के लिए आपके डिज़ाइन विकल्प क्या हैं? स्पष्ट रूप से मैंने जो उदाहरण दिखाए हैं वे एक आसान काम के लिए "बहुत जटिल" हैं, लेकिन साथ ही यह विचार एसओएलआईडी सिद्धांतों का पालन करना है और एनीमिक डोमेन को रोकना है (जिनमें से नष्ट करने के लिए कमीशन किया गया है)।