मेरे कार्य का लक्ष्य एक छोटी प्रणाली को डिजाइन करना है जो अनुसूचित आवर्ती कार्यों को चला सकती है। एक आवर्ती कार्य कुछ ऐसा है "प्रशासक को हर घंटे सुबह 8:00 बजे से शाम 5:00 बजे, सोमवार से शुक्रवार तक ईमेल भेजें"।
मेरा एक बेस क्लास है, जिसे रिकरिंगटैस्क कहा जाता है ।
public abstract class RecurringTask{
// I've already figured out this part
public bool isOccuring(DateTime dateTime){
// implementation
}
// run the task
public abstract void Run(){
}
}
और मेरे पास कई कक्षाएं हैं जो RecurringTask से विरासत में मिली हैं । उनमें से एक SendEmailTask कहा जाता है ।
public class SendEmailTask : RecurringTask{
private Email email;
public SendEmailTask(Email email){
this.email = email;
}
public override void Run(){
// need to send out email
}
}
और मेरे पास एक ईमेल सेवा है जो मुझे ईमेल भेजने में मदद कर सकती है।
अंतिम वर्ग RecurringTaskScheduler है , यह कैश या डेटाबेस से कार्यों को लोड करने और कार्य को चलाने के लिए ज़िम्मेदार है।
public class RecurringTaskScheduler{
public void RunTasks(){
// Every minute, load all tasks from cache or database
foreach(RecuringTask task : tasks){
if(task.isOccuring(Datetime.UtcNow)){
task.run();
}
}
}
}
यहाँ मेरी समस्या है: मुझे ईमेल सेवा कहां डालनी चाहिए ?
OPTION1 : इंजेक्षन EmailService में SendEmailTask
public class SendEmailTask : RecurringTask{
private Email email;
public EmailService EmailService{ get; set;}
public SendEmailTask (Email email, EmailService emailService){
this.email = email;
this.EmailService = emailService;
}
public override void Run(){
this.EmailService.send(this.email);
}
}
इस बात पर पहले से ही कुछ चर्चाएँ हैं कि क्या हमें एक सेवा को एक इकाई में इंजेक्ट करना चाहिए, और अधिकांश लोग सहमत हैं कि यह एक अच्छा अभ्यास नहीं है। इस लेख को देखें ।
Option2: यदि ... RecurringTaskScheduler में एल्स
public class RecurringTaskScheduler{
public EmailService EmailService{get;set;}
public class RecurringTaskScheduler(EmailService emailService){
this.EmailService = emailService;
}
public void RunTasks(){
// load all tasks from cache or database
foreach(RecuringTask task : tasks){
if(task.isOccuring(Datetime.UtcNow)){
if(task is SendEmailTask){
EmailService.send(task.email); // also need to make email public in SendEmailTask
}
}
}
}
}
मुझे बताया गया है कि यदि ... ऊपर की तरह कास्ट और कास्ट OO नहीं है, और अधिक समस्याएं लाएगा।
Option3: रन के हस्ताक्षर को बदलें और ServiceBundle बनाएं ।
public class ServiceBundle{
public EmailService EmailService{get;set}
public CleanDiskService CleanDiskService{get;set;}
// and other services for other recurring tasks
}
इस वर्ग को RecurringTaskScheduler में इंजेक्ट करें
public class RecurringTaskScheduler{
public ServiceBundle ServiceBundle{get;set;}
public class RecurringTaskScheduler(ServiceBundle serviceBundle){
this.ServiceBundle = ServiceBundle;
}
public void RunTasks(){
// load all tasks from cache or database
foreach(RecuringTask task : tasks){
if(task.isOccuring(Datetime.UtcNow)){
task.run(serviceBundle);
}
}
}
}
SendEmailTask की रन विधि होगी
public void Run(ServiceBundle serviceBundle){
serviceBundle.EmailService.send(this.email);
}
मैं इस दृष्टिकोण के साथ कोई बड़ी समस्या नहीं देखता हूं।
विकल्प 4 : आगंतुक पैटर्न।
मूल विचार एक आगंतुक बनाता है जो सेवाबंडल की तरह सेवाओं को एन्क्रिप्ट करेगा ।
public class RunTaskVisitor : RecurringTaskVisitor{
public EmailService EmailService{get;set;}
public CleanDiskService CleanDiskService{get;set;}
public void Visit(SendEmailTask task){
EmailService.send(task.email);
}
public void Visit(ClearDiskTask task){
//
}
}
और हमें Run मेथड के सिग्नेचर को भी बदलना होगा । SendEmailTask की रन विधि है
public void Run(RecurringTaskVisitor visitor){
visitor.visit(this);
}
यह विज़िटर पैटर्न का एक विशिष्ट कार्यान्वयन है, और विज़िटर को RecurringTaskScheduler में इंजेक्ट किया जाएगा ।
संक्षेप में: इन चार दृष्टिकोणों में, मेरे परिदृश्य के लिए कौन सा सबसे अच्छा है? और क्या इस समस्या के लिए Option3 और Option4 के बीच कोई बड़ा अंतर है?
या आप इस समस्या पर बेहतर विचार रखते हैं? धन्यवाद!
अपडेट 5/22/2015 : मुझे लगता है कि एंडी का जवाब मेरे इरादे को अच्छी तरह से बताता है; यदि आप अभी भी समस्या के बारे में उलझन में हैं, तो मैं पहले उनकी पोस्ट पढ़ने का सुझाव देता हूं।
मुझे अभी पता चला है कि मेरी समस्या मैसेज डिस्पैच समस्या से काफी मिलती-जुलती है, जिसके कारण Option5 की ओर रुख किया जाता है।
Option5 : मेरी समस्या को संदेश डिस्पैच में बदलें ।
मेरी समस्या और संदेश डिस्पैच समस्या के बीच एक-से-एक मानचित्रण है:
संदेश डिस्पैचर : IMessage प्राप्त करें और अपने संबंधित हैंडलर को IMessage की उप कक्षाएं भेजें । → पुनरावर्तीटैस्क्यूलेटर
IMessage : एक इंटरफ़ेस या एक सार वर्ग। → आवर्ती
MessageA : कुछ अतिरिक्त जानकारी होने, IMessage से फैली हुई है । → SendEmailTask
MessageB : IMessage का एक और उपवर्ग । → क्लीनडिस्कटस्क
MessageAHandler : प्राप्त कर लेते हैं MessageA , यह → SendEmailTaskHandler, जो EmailService शामिल संभाल, और एक ई-मेल भेजते हैं जब यह SendEmailTask प्राप्त करता है
MessageBHandler : MessageAHandler के रूप में ही , लेकिन इसके बजाय MessageB हैंडल करें । → CleanDiskTaskHandler
सबसे कठिन हिस्सा यह है कि विभिन्न हैंडलर्स को विभिन्न प्रकार के IMessage कैसे भेजें । यहाँ एक उपयोगी लिंक है ।
मुझे वास्तव में यह दृष्टिकोण पसंद है, यह मेरी इकाई को सेवा के साथ प्रदूषित नहीं करता है, और इसमें कोई ईश्वर वर्ग नहीं है ।
SendEmailTask
मेरे लिए एक इकाई से अधिक एक सेवा की तरह लगता है। मैं विकल्प 1 के लिए बिना किसी हिचकिचाहट के जाऊंगा।
accept
आगंतुकों को। विज़िटर के लिए प्रेरणा यह है कि आपके पास कुछ एग्रीगेट में कई प्रकार के प्रकार हैं, जिन्हें विज़िट करने की आवश्यकता है, और प्रत्येक नई कार्यक्षमता (ऑपरेशन) के लिए उनके कोड को संशोधित करना सुविधाजनक नहीं है। मैं अब भी नहीं देखता कि वे समग्र वस्तुएं क्या हैं, और सोचते हैं कि आगंतुक उचित नहीं है। यदि यह मामला है, तो आपको अपने प्रश्न (जो आगंतुक को संदर्भित करता है) को संपादित करना चाहिए।