Elegant Factory using Functions as first class citizens

                        The main intent behind a Factory pattern described generically is to  “Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclass.” Factory pattern is one of the commonly applicable pattern in the Object world.

                                We start with complex enough version of Factory pattern example and how it is implemented using Java. Here’s a simple example of Factory implementation in  the classical OOP way.

                            A Commands Interface with listOfCommands() method definition. We have WindowsCommands , LinuxCommands and MACCommands as concrete classes implementing Commands. Commandline class requires the Factory class CommandFactory to get the appropriate list of commands.



public class WindowsCommands extends Commands {

@Override
public String toString()
{
return "This is WindowsCommands Class instantiated";
}
@Override
public List<String> listOfCommands() {
return Arrays.asList("DiskPart","Evntcmd","winnt","w32tm");
}

}

public class LinuxCommands extends Commands {

@Override
public String toString()
{
return "This is LinuxCommand Class instantiated";
}
@Override
public List<String> listOfCommands() {
return Arrays.asList("busybox","usermod","groupadd","python2.7");
}

}

/* A factory class that return the appropriate Commands Object 
based on the OSType paramter */
public class CommandFactory {

private String OSType;

public CommandFactory(String OSType)
{
this.OSType = OSType;
}

public Commands getInstance()
{
if(this.OSType.equalsIgnoreCase("Windows"))
return new WindowsCommands();
else if(this.OSType.equalsIgnoreCase("Linux"))
return new LinuxCommands();
else
return new MACCommands();

}

}

Now we have a CommandLine class that holds a Commands Object. The Appropriate Commands Object is set using the CommandFactory .

package com.functProg.examples.subsumingFactory;

import java.util.function.Function;

public class CommandLine {

private Commands commands;

public CommandLine(String OSType) {
 this.commands = (new CommandFactory(OSType)).getInstance();
 }

public void printAvailableCommands() {
 System.out.println(commands.listOfCommands().toString());
 }

public static void main(String args[]) {
 new CommandLine("Windows").printAvailableCommands();
 new CommandLine("Linux").printAvailableCommands();

}
}

Output
[DiskPart, Evntcmd, winnt, w32tm]
[busybox, usermod, groupadd, python2.7]

The list of commands are returned based on the Type of the OS. Here the crux is that the CommandLine class is least concerned about how the Commands object it contains is initialized. The Factory does this for the CommandLine class.

If we think on functional lines a factory is nothing but a supplier of Objects. If we could have a Supplier which would supply the right Commands Object based on the lambda passed to it the need for a seperate CommandFactory is subsumed. Now if we look at the refactored code below a lamda which directly returns a required object is directly passed to the CommandLine class. Again the main motive of keeping the CommandLine class independent of how Commands object is initialized.


package com.functProg.examples.subsumingFactory;

import java.util.function.Function;
import java.util.function.Supplier;

public class CommandLine<T> {

private Commands commands;

public CommandLine(Supplier<T> commandSupplier) {
this.commands = (Commands) commandSupplier.get();
}

public void printAvailableCommands() {
System.out.println(commands.listOfCommands().toString());
}

public static void main(String args[]) {
new CommandLine<Commands>(() -> new WindowsCommands())
.printAvailableCommands();
new CommandLine<Commands>(() -> new LinuxCommands())
.printAvailableCommands();
}
}

Output
[DiskPart, Evntcmd, winnt, w32tm]
[busybox, usermod, groupadd, python2.7]

We get the same output as the previous one but certainly with lot less ceremony and eliminating the need of CommandsFactory class. The essence here is the way we think of a Factory. Previously we had to have Factory class that needed to be composed into the class where we needed those kinds of objects. Now , with the Functional Style we can pass functions across that solve the same purpose. Passing what to do directly as a function and defining only the definition inside makes this a much elegant approach.

Leave a comment