Static factory method is a static method that returns an instance of a class.

The key idea of static factory method is to gain control over object creation and delegate it from constructor to static method. The decision of object to be created is like in Factory made outside the method (in common case, but not always). While the key (!) idea of Factory Method is to delegate decision of what instance of class to create inside Factory Method. E.g. classic Singleton implementation is a special case of static factory method. Example of commonly used static factory methods:

  • valueOf
  • getInstance(used in singleton)
  • newInstance

When to use?

  1. Static factory methods can have meaningful names, hence explicitly conveying what they do
  2. Static factory methods can return the same type that implements the method(s), a subtype, and also primitives, so they offer a more flexible range of returning types
  3. Static factory methods can encapsulate all the logic required for pre-constructing fully initialized instances, so they can be used for moving this additional logic out of constructors. This prevents constructors from performing further tasks, others than just initializing fields

Another example of static factory is as follow

Optional<String> value1 = Optional.empty();
Optional<String> value2 = Optional.of("Baeldung");
Optional<String> value3 = Optional.ofNullable(null);

Logger.java

public class Logger {
    public String logType;
    public String fileLocation;

    public Logger(String logType) {
        this.logType = logType;
    }

    public Logger() {
    }

    public static Logger getDefaultLogger(){
        return new Logger("Console");
    }

    public static Logger getFileLogger(String fileLocation){
        Logger logger =  new Logger("File");
        logger.fileLocation = fileLocation;
        return logger;
    }

    @Override
    public String toString() {
        return "Logger{" +
                "logType=" + logType +
                ", fileLocation='" + fileLocation + '\'' +
                '}';
    }
}

ClientApp.java

public class ClientApp {
    public static void main(String[] args) {
        Logger objLogger = Logger.getDefaultLogger();
        System.out.println(objLogger);
    }
}

Output

Logger{logType=Console, fileLocation='null'}

Logger.java

public class Logger {
    public String logType;
    public String fileLocation;

    public Logger(String logType) {
        this.logType = logType;
    }

    public Logger() {
    }

    public static Logger getLoggerInstance(LoggerType loggerType){
        Logger logger;
        switch(loggerType) {
            case CONSOLE:
                logger = new Logger("Console Logger");
                logger.fileLocation = "JVM Memory";
                break;
            case DATABASE:
                logger = new Logger("Database Logger");
                logger.fileLocation = "DB Connection";
                break;
            case FILE:
                logger = new Logger("File Logger");
                logger.fileLocation = "C:/logs";
                break;
            case SPLUNK:
                logger = new Logger("Splunk Logger");
                logger.fileLocation = "Splunk URL";
                break;
            default:
                logger = new Logger();

        }

        return logger;
    }

    @Override
    public String toString() {
        return "Logger{" +
                "logType=" + logType +
                ", fileLocation='" + fileLocation + '\'' +
                '}';
    }
}

ClientApp.java

public static void main(String[] args) {
        Logger objLogger = Logger.getLoggerInstance(LoggerType.CONSOLE);
        System.out.println(objLogger);
    }

LoggerType.java

public enum LoggerType {
    CONSOLE, FILE, DATABASE, SPLUNK
}

Output

Logger{logType=Console Logger, fileLocation='JVM Memory'}

Comments are closed.