3

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.

3
  • 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, 2016 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, 2016 at 17:10
  • "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" Yes and no. There are two kinds of factories. There are factories whose responsibility is choosing the right concrete class (which is what you're getting at), but you can also have a factory that creates a known subtype, but the factory's responsibility is to construct this hard-to-construct object for the consumer (i.e. the factory's skill is in knowing how to put it together, instead of deciding what to put together).
    – Flater
    Apr 12, 2021 at 10:08

3 Answers 3

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.

7
  • 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, 2016 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, 2016 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, 2016 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, 2016 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, 2016 at 17:28
0

It appears that abstract factory shouldn't accept parameters else that would mean the client does* know the details. I have been attempting the same for years but I'm finding its incorrect e.g.

// EmailMsgFactory implements MsgFactory
// SmtpMsgFactory implements MsgFactory

// but here you would still need specific params e.g. email vs 
// vs ftp vs slack; also the actual message build.
// assuming injected
message = MsgFactory::buildMessage(new MsgParam([em-specif]));
msngr = MsgFactory::buildMsngr(new MsngrParam([em-specif]));
msngr->send();

Which from what I am understanding is breaking the purpose of the pattern; however, in my opinion, obviously an object or method will need params - so I'm a lil confused.

If you try to put those variables in e.g. a global context area, that would sound even worse.

0

In your app, there’s a button “send email” and another button “send SMS”. There must be a difference in the code implementing the actions of these buttons, right?

So what’s the difference? Very nonabstract; One calls new EmailMessage() and the other call new SMSMessage(). More abstract: EmailMessageFactor->newMessage vs SMSMessageFCtory->newMessage. More abstract: MessageFactory->newMessage (“Email”) vs MessageFactory->newMessage(“SMS”). Entirely up to you.

Now you have a message. Here it would be better if your messages all implemented some interface or protocol, and that’s what you program against. You’d never know what the actual class of your message instance is.

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.