I have been studying Design Patterns and I am looking to implement them into my latest project.
I am working on a Windows Service that regularly checks a database table for a new entry.
Depending on the entry found, the service will perform a number of processes.
Possible processes include:
1) Generate report and send email with report attached
2) Run query and log data to another table
3) Send notification email
What design pattern is best suited? I have been considering the Factory Pattern.
My design process so far…
1) Create Interface
2) Create Abstract class which implements the Interface
3) Abstract Methods:
- CheckTable()
- GenerateReport()
- SendEmail()
4) Factory Design Pattern:
- The client(windows service) asks the Factory for a new object (based of the database entry found)
- The factory instantiates this and returns to the client
- The client then calls the relevant methods to send email or run query.
Does this look correct? Or am I making this more difficult than it is?
Or should I be using the Observor Pattern?
UPDATE:
OK. I have taken your advice and looked for the simplest way of doing this.
Is the below correct? I have created an Interface and then a class to implement this Interface.
There could be a number of different reports/emails to generate. Should these be added as new methods in the Interface?
Do I need an Abstract class?
// interface
internal interface IJobs
{
void SendEmail();
void PublishData();
void GenerateTestReport(string userID, DateTime period);
}
// concrete class
public sealed class JobsFactory : IJobs
{
#region SINGLETON
private static JobsFactory INSTANCE;
private JobsFactory() { }
public static JobsFactory GetInstance()
{
if (INSTANCE == null)
{
INSTANCE = new JobsFactory();
}
return INSTANCE;
}
#endregion
private readonly WorkbookFactory _workbookFactory = WorkbookFactory.GetInstance();
#region IJobs Members
public void SendEmail()
{
// send email
}
public void PublishData()
{
// publish data
}
public void GenerateTestReport(string userID, DateTime period)
{
string reportTestFilePath = this._workbookFactory.BuildTestReportWorkbook(userID, period);
}
#endregion
}
4
I’ll tell you a story. Many years ago, when I was a young, inexperienced programmer and GoF had not long before published their Design Patterns book, and Java was a new language and the only user interface library generally available for it was AWT, and AWT applications all looked ugly as hell, my company decided to switch development from C++ to Java. But AWT was out of the question: our applications were required to look and feel like native Win 32 apps, and you simply couldn’t achieve that with AWT back then. So, I was tasked with learning JNI and implementing a framework that would let us build native windows user interfaces using Java.
I had not long before read about Design Patterns, and was eager to use them, so I looked at my project and thought about which ones would fit where. The idea I was most proud of was this: I’d have a native Window object that encapsulated a win32 window handle, but in order to allow the application to attach behaviours to the window, I’d use Chain of Responsibility. This would let applications use existing behaviours and combine them in new ways, and everything would be great.
So I implemented Chain of Responsibility, and it was a bit more complex than just having a single Behaviour object that managed everything, but I wrote a handful of tests using it and everything worked beautifully.
Then we deployed the framework and started to write real applications using it, and you know what? Not once did we ever use the facility to chain multiple behaviours in a single window.
The lesson here is simple: don’t start by using the Design Pattern catalogue to shop for extra flexibility in your application. Start by thinking about what flexibility you are really likely to need, and then about how you can implement that flexibility. It might be that a standard pattern is the best way to achieve that. It might be there’s a simpler, more direct way. It may even be the case that you have a rigid, well-defined problem that is small enough that you can design the entire solution simply without needing any scope to change behaviour later, in which case anything even approximating a design pattern would likely be overkill.
To borrow a phrase from Kent Beck, “do the simplest thing that could possibly work”. If that happens to end up looking like a pattern, that’s great. But don’t worry if it doesn’t.
2
I’d just start out using no patterns.
var records = CheckTable();
foreach(var record in records)
{
GenerateReport(record);
SendEmail(record);
}
Start simple, not everything needs a pattern. If you start doing a lot of different tasks, or allow tasks to be configurable in the order and the number of tasks run per record, then think about abstracting it out by refactoring.
Since you need to do what seems to be polling, you could take a look at the Observer Pattern
. This would allow your service to call your methods so that they can take appropriate action.
That being said, as it has been mentioned in the comments, you seem to have design patterns the other way round. The task should lead you to a design pattern. Trying to wrap your requirements around a particular design pattern is not the best way to approach design.