Core Java

Functional Factory Pattern

Do you want a REALLY quick way to make a Factory object? Then lambdas or other function-passing is what you need! Not only is it quick, it’s really simple. I bet, if you’re a pretty good with Lambdas, you have a pretty good idea on how to do this simply by having read the title. If you’re one of those, stick around; you never know what you could learn.

As a side note: I’m doing code examples in Java AND Python. Why? Because I love both languages and it sure doesn’t hurt to put stuff out there for both.

Primer on the Factory Pattern

If you already know what the Factory Design Pattern is, then you can skip to the next section.

The point of the Factory pattern is to supply objects and methods with a way to instantiate an object without exposing all (or, often, any) of the instantiation logic (what needs to be passed into the constructor).

Example

As a silly example, say there is a class, Scientist, that needs a way to produce new Pens to write down his experiment data with, but he doesn’t want to be bothered with the creation process. To do this, you would give the Scientist a PenFactory, and all the Scientist needs to know is to push the button on the factory to get a new pen.

The PenFactory is a simple object with only a create() method that supplies a new instance of Pen whenever you call it. If the Scientist cared about what color the Pen was, you could supply him with a ColoredPenFactory whose create() method also accepts a color parameter. Then the ColoredPenFactory would have to figure out how to provide a pen with that color.

Expanding the Factory Pattern Idea

The Factory Pattern is a pattern for Object-Oriented code, and is therefore limited to how OO works, but we can take its purpose and try to figure out a way to make it in a functional way, too, which actually makes it a LOT easier.

In fact, a large number of OO design patterns were created due to the lack of ability to pass functions around. Most of these can be replaced simply by passing in a function. A short list of them include Command, Factory, and Strategy. Many others can remove a lot of class hierarchy if they accept functions. Some of these include Template and Visitor.

So, the biggest difference is the idea that the Factory class doesn’t have to be a class; it can be a simple “callable”, too. So let’s dig into some examples.

The OO Pen Factory

Just so you can see the difference between the classic OO pattern and the new function pattern, here are the example classes and interfaces, in OO Java.

public interface Pen {
   void write(String toWrite);
   boolean outOfInk();
}

public interface PenFactory {
   Pen create();
}

public class Scientist {
	
   private PenFactory penerator;
   private Pen pen;
	
   public Scientist(PenFactory penerator) {
      this.penerator = penerator;
      this.pen = penerator.create();
   }
	
   public void writeData(String data) {
      if(pen.outOfInk()) {
         pen = penerator.create();
      }
      pen.write(data);
   }
}

And in OO Python

class Pen(metaclass=ABCMeta):

    def write(self, text):
        pass

    def out_of_ink(self):
        pass


class PenFactory(metaclass=ABCMeta):

    def create(self):
        pass


class Scientist():

    def __init__(self, pen_factory):
        self.penerator = pen_factory
        self.pen = self.penerator.create()

    def write_data(self, data):
        if self.pen.out_of_ink():
            pen = self.penerator.create()
        pen.write(data)

Did you catch how I called the PenFactory instances penerator? I thought it was kind of silly. I hope you enjoyed it too. If not, oh well.

Converting to a Simple Functional Pattern

When it comes to the Java version, you don’t actually NEED to make any changes, since the PenFactory counts as a functional interface, but, there’s no need for it since you can replace any instance of PenFactory with Supplier<Pen>. So, the Scientist class would look like this instead:

public class Scientist {
	
   private Supplier penerator;
   private Pen pen;
	
   public Scientist(Supplier penerator) {
      this.penerator = penerator;
      this.pen = penerator.get();
   }
	
   public void writeData(String data) {
      if(pen.outOfInk()) {
         pen = penerator.get();
      }
      pen.write(data);
   }
}

In Python, you can remove the PenFactory completely and just use any sort of callable that returns a Pen. You’ll also have to change the lines in Scientist that call the factory’s create() method and just replace it with some parenthesis to call it.

class Scientist():

    def __init__(self, pen_factory):
        self.penerator = pen_factory
        self.pen = self.penerator()

    def write_report(self, data):
        if self.pen.out_of_ink():
            self.pen = self.penerator()
        self.pen.write(data)

So, to create an instance of Scientist with lambdas that provide instances of MyPenClass, you would type this in Java:

Scientist albert = new Scientist(() -> new MyPenClass());

or this in Python:

albert = Scientist(lambda: MyPenClass())
# or skip the lambda by passing the "constructor"
thomas = Scientist(MyPenClass)

Factories for Classes with Dependencies

Let’s say I wanted to make a factory for a class whose constructor requires the name of a brand of pens. We’ll call this class BrandPen. How would we make a factory for that? Well, writing the lambdas wouldn’t really be any different, really. How about we look at other ways of defining callables to be passed in, though?

In Java, you can save an instance of the lambda in a variable and pass that in. Or you can use a method reference:

Supplier bicPen = () -> new BrandPen("BiC");
Scientist thomas = new Scientist(bicPen);
// assuming that BrandPen has a static method called bicPen
Scientist nicola = new Scientist(BrandPen::bicPen);

In Python, you could define a function that does it or assign a partial to do it:

def bic_pen():
    return BrandPen("BiC")
# or
bic_pen = partial(BrandPen, "BiC")

nicola = Scientist(bic_pen)

Factories with Dependencies

Oh man, now the Scientist wants to be able to specify the color of the pen that the factory supplies! Well, you could give him different factories for each color and tell him to use each different factory to make the different pens, but there’s simply no room in his lab for so many PenFactorys! We’ll have to give a factory that can be told what color to use.

To do this, we’ll have to change Java’s Supplier<Pen> to a Function<>Color, Pen>. Obviously, you won’t need to change the type in Python, since it’s dynamic and doesn’t require type information.

But the Scientist classes also need to change how they use their factories. In Java, wherever the Scientist is asking for a new instance, it needs to provide a color too, like this:

pen = penerator.apply(Color.RED);

or like this, in Python:

self.pen = self.penerator(Color.RED)

The factory we pass into the Scientist in Java could look like this:

Scientist erwin = new Scientist(color -> new ColoredPen(color, "BiC"));

The one we give in Python could look like this:

def colored_bic_pen(color):
    return ColoredPen(color, "BiC")

erwin = Scientist(colored_bic_pen)

Multimethod Factories

In some examples for the Factory Pattern on the internet, they show factories that have multiple methods to call for generating an object. I haven’t seen this in action in real life, but it might happen. In these instances, it may be better to stick to the OO option, but if you want to change it to a functional pattern, simply provide separate factory callables instead of one object with multiple methods.

Outro

I didn’t expect to write this much, but as I went, there were so many little variances that I wanted to show. I didn’t get around to them all, mostly because I didn’t feel like keeping track of them all, especially in two languages, but I’m sure that I’ve given you a good enough toolbox to figure it out on your own.

I hope you learned something. If you didn’t, I hope you enjoyed the example at least.

Reference: Functional Factory Pattern from our JCG partner Jacob Zimmerman at the Programming Ideas With Jake blog.

Jacob Zimmerman

Jacob is a certified Java programmer (level 1) and Python enthusiast. He loves to solve large problems with programming and considers himself pretty good at design.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button