เป้าหมายของงานของฉันคือการออกแบบระบบขนาดเล็กที่สามารถเรียกใช้งานที่เกิดขึ้นซ้ำตามกำหนดเวลา งานที่เกิดซ้ำเป็นเหมือน "ส่งอีเมลไปยังผู้ดูแลระบบทุกชั่วโมงตั้งแต่ 8:00 น. ถึง 17:00 น. วันจันทร์ถึงวันศุกร์"
ฉันได้เรียนฐานที่เรียกว่าRecurringTask
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
}
}
และฉันมีEmailServiceซึ่งสามารถช่วยให้ฉันส่งอีเมลได้
คลาสสุดท้ายคือ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();
}
}
}
}
นี่คือปัญหาของฉัน: ฉันควรใส่EmailServiceที่ไหน?
ตัวเลือกที่ 1 : Inject 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);
}
}
มีการถกเถียงกันอยู่แล้วว่าเราควรอัดฉีดบริการเข้าสู่องค์กรหรือไม่และคนส่วนใหญ่เห็นด้วยว่ามันไม่ใช่วิธีปฏิบัติที่ดี ดูบทความนี้
ตัวเลือก 2:ถ้า ... อื่นใน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:เปลี่ยนลายเซ็นของRunและสร้าง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 : รูปแบบผู้เยี่ยมชม
ความคิดพื้นฐานคือการสร้างผู้เข้าชมซึ่งจะแค็ปซูลให้บริการเช่นเดียวกับServiceBundle
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){
//
}
}
และเราจำเป็นต้องเปลี่ยนลายเซ็นของวิธีการเรียกใช้ เรียกใช้วิธีการSendEmailTaskคือ
public void Run(RecurringTaskVisitor visitor){
visitor.visit(this);
}
มันเป็นเรื่องปกติของการดำเนินงานแบบผู้เข้าชมและผู้เข้าชมจะได้รับการฉีดเข้าไปในRecurringTaskScheduler
โดยสรุป: ในบรรดาสี่แนวทางวิธีใดที่ดีที่สุดสำหรับสถานการณ์ของฉัน และมีความแตกต่างใหญ่ระหว่าง Option3 และ Option4 สำหรับปัญหานี้หรือไม่?
หรือคุณมีความคิดที่ดีเกี่ยวกับปัญหานี้? ขอบคุณ!
Update 5/22/2015 : ฉันคิดว่าคำตอบของ Andy สรุปความตั้งใจของฉันได้ดีจริงๆ หากคุณยังคงสับสนเกี่ยวกับปัญหาตัวเองฉันแนะนำให้อ่านโพสต์ของเขาก่อน
ฉันเพิ่งพบว่าปัญหาของฉันคล้ายกับปัญหาการส่งข้อความซึ่งนำไปสู่ Option5
Option5 : แปลงปัญหาของฉันไปที่ข้อความส่ง
มีการแมปแบบหนึ่งต่อหนึ่งระหว่างปัญหาของฉันและปัญหาการส่งข้อความ :
Message Dispatcher : รับIMessageและส่งคลาสย่อยของIMessageไปยังตัวจัดการที่เกี่ยวข้อง → RecurringTaskScheduler
IMessage : อินเทอร์เฟซหรือคลาสนามธรรม → RecurringTask
MessageA : ขยายจากIMessageโดยมีข้อมูลเพิ่มเติมบางอย่าง → SendEmailTask
MessageB : subclass ของอีกIMessage → CleanDiskTask
MessageAHandler : เมื่อรับMessageAให้จัดการ→ SendEmailTaskHandler ซึ่งมี EmailService และจะส่งอีเมลเมื่อได้รับ SendEmailTask
MessageBHandler : เหมือนกับMessageAHandlerแต่จัดการMessageBแทน → CleanDiskTaskHandler
ส่วนที่ยากที่สุดคือวิธีส่งIMessage ประเภทต่างๆไปยังตัวจัดการที่แตกต่างกัน นี่คือประโยชน์เชื่อมโยง
ผมชอบวิธีการนี้จะไม่ก่อให้เกิดมลพิษนิติบุคคลของฉันกับการบริการและมันก็ไม่ได้มีพระเจ้าระดับ
SendEmailTask
ดูเหมือนจะเป็นบริการมากกว่าเป็นนิติบุคคลสำหรับฉัน ฉันจะไปเลือก 1 โดยไม่ลังเล
accept
ผู้มาเยี่ยมชม แรงจูงใจสำหรับผู้เยี่ยมชมคือคุณมีคลาสหลายประเภทในบางกลุ่มที่ต้องการเข้าชมและไม่สะดวกในการแก้ไขโค้ดสำหรับแต่ละฟังก์ชันการทำงานใหม่ (การทำงาน) ฉันยังไม่เห็นวัตถุรวมเหล่านั้นและคิดว่าผู้เข้าชมไม่เหมาะสม หากเป็นกรณีนี้คุณควรแก้ไขคำถามของคุณ (ซึ่งอ้างอิงถึงผู้เยี่ยมชม)