I've been studying creational design patterns for the past week or so because I have a common use case that keeps coming up, and I can't figure out which pattern fits the bill.
Here is a simplified scenario: I have different types of notifications -- e.g. email, SMS (text message), etc. -- and I don't want the client to know which type to create or how to create it, i.e. the client doesn't know anything about the implementations of INotification.
Below is my attempt at a "factory method" approach.
internal interface INotification { void Send(); } public sealed class EmailNotification : INotification { private EmailAddress _sourceAddress; private EmailAddress _destAddress; public struct EmailAddress { public string LocalPart { get; set; } public string DomainPart { get; set; } public EmailAddress(string localPart, string domainPart) : this() { LocalPart = localPart; DomainPart = domainPart; } } internal EmailNotification(EmailAddress sourceAddress, EmailAddress destAddress) { _sourceAddress = sourceAddress; _destAddress = destAddress; } void INotification.Send() { // send via email technology throw new NotImplementedException(); } } public sealed class SmsNotification : INotification { private PhoneNumber _sourceNumber; private PhoneNumber _destNumber; public struct PhoneNumber { public ushort CountryCode { get; set; } public ushort AreaCode { get; set; } public ushort ExchangeCode { get; set; } public ushort LineNumber { get; set; } public PhoneNumber(ushort countryCode, ushort areaCode, ushort exchangeCode, ushort lineNumber) : this() { CountryCode = countryCode; AreaCode = areaCode; exchangeCode = ExchangeCode; LineNumber = lineNumber; } } internal SmsNotification(PhoneNumber sourceNumber, PhoneNumber destNumber) { _sourceNumber = sourceNumber; _destNumber = destNumber; } void INotification.Send() { // send via SMS tecnology throw new NotImplementedException(); } } internal class NotificationFactory { internal INotification CreateSmsNotification( SmsNotification.PhoneNumber sourceNumber, SmsNotification.PhoneNumber destNumber) { return new SmsNotification(sourceNumber, destNumber); } internal INotification CreateEmailNotification( EmailNotification.EmailAddress sourceAddress, EmailNotification.EmailAddress destAddress) { return new EmailNotification(sourceAddress, destAddress); } } I would use this from the client like this:
var factory = new NotificationFactory(); var notification = factory.CreateEmailNotification( new EmailNotification.EmailAddress("myname", "nothing.com"), new EmailNotification.EmailAddress("yourname", "nothing.com")); notification.Send(); Now, I know that a factory method approach is supposed to involve just one method which takes, e.g., an enumeration in order to determine the type of the return object. I haven't seen any references that use the above approach where there are multiple specialized methods. Am I calling it the wrong pattern? Am I doing it the wrong way (i.e. should I be using a different pattern)?
I have also considered using dependency injection with a DI container, but my understanding is that pattern just makes testing easier and is an alternative to (or reorganization of) the various factory design patterns. Ultimately, I would have the same issue, I believe, in my DI container which is figuring out how to take complex input and decide which sub-class to output.
Maybe I need some combination of factory and builder. I know that a builder is used to output a single type (contrasted with a factory which outputs a certain derived type or interface implementation), but the fact that I have multiple methods involved for creating certain specialized instances seems more like a builder.
Any help would be much appreciated.
INotification. It doesn't know specifically which sub-type it's going to get back. This is the same with a "normal" factory method where you pass an enum value: you (the client) still have to know what value you're passing and thus you have some knowledge of the return product. When I say "don't want the client to know which type to create or how to create it", by "type" I mean the specific implementation ofINotification. The client doesn't know about specific implementations.