2

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.

  • 1
    The requirements are confusing. "don't want the client to know which type to create or how to create it" yet the methods require explicit knowledge of not only what they do, but composition of the objects being constructed within the factory, since member values of the factory constructed objects are required at the factory method level preconstructed. Maybe I'm missing something. – user22018 Mar 24 '16 at 17:05
  • @TechnikEmpire -- The client still doesn't know which type it gets back, because it always gets back an 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 of INotification. The client doesn't know about specific implementations. – rory.ap Mar 24 '16 at 17:10
2

You've done a good job of abstracting the notification, but you haven't applied similar abstraction to the job of creating the notification target.

What you're doing is not a "Factory Method", because, as you are observing, it doesn't use a single method that decides, usually by the parameters supplied, which true class to create. In your code, the client is choosing directly between the methods; whereas in the factory method pattern, the immediate client shouldn't really know or care.

Neither is this an "Abstract Factory" because the client is also supposed to not know or care. In this sense, the abstract factory pattern builds on the factory method pattern.

The code isn't a builder pattern either, because the NotificationFactory directly instantiate the object without any further ado.

Further, your client is required to use new in invoking the NotificationFactory, which has a bit of a smell: you're calling it a factory, but the client actually has to use new (to create the parameters), which is what the factory is designed to obviate. The idea of the factory is to create a loose coupling between the user of the factory and what's being created. Because of the specific new used for the parameters, this makes tight coupling.

What I would suggest is that you analyze your use case and see if there is a need for a factory. If not, simply revert to using new directly.

When need to separate the responsibility for choosing the method of notification from the creation of the instance, then you should introduce a factory.

  • 3
    +1 this is what I was getting at. The fact that the client has to be aware of how to construct the result to any degree is a direct strike against the intent of the pattern. – user22018 Mar 24 '16 at 17:15
  • Thanks to both of you. I'm seeing that now, but I'm still struggling to understand how to modify the approach I'm using. Or is it just the nature of things that my client knows about what it's trying to create? Should I just call constructors from the client in that case? – rory.ap Mar 24 '16 at 17:17
  • 1
    It is ok to construct objects directly. Let the code emerge and refactor when it seems like you've repeated yourself too much. You don't have to start with a (factory) pattern, you can refactor into it when needed. – Erik Eidt Mar 24 '16 at 17:20
  • @ErikEidt -- Can you please clarify "Because of the specific new used for the parameters, this makes tight coupling." Which new are you referring to? The structs? Is that to say only enum values or simple strings or constants, etc. are acceptable for factory method parameters? – rory.ap Mar 24 '16 at 17:25
  • Yes, it's the structs, in particular because these structs are members of the classes that the NotificationFactory is "hiding". So the client is directly referencing the EmailNotification class, and shouldn't have to with a factory pattern. More refactoring and abstraction would have to be done regarding those parameters to get to a good factory pattern. You'd want to push conversion-of-those-strings-into-the-structs to another place (closer to their source). – Erik Eidt Mar 24 '16 at 17:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.