Abstract Factory Design Java

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite
1












I am new to Design Pattern implementation and would like to strongly solidify my knowledge to become as good of a programmer as I can. Is this a proper implementation of the Abstract Factory design? The idea here is that I can interchangeably utilize either a ConsoleLogger or a FileLogger for three different "levels" of logging (Execution, Output, and Error). I want the client to be able to log Execution and Output to console, but Error logs to a file if necessary.



Logger Interface:



public interface ILogger 
public void log(String content);



Base Logging Factory:



import java.util.HashMap;

public abstract class LoggingFactory
static
factoryMap = new HashMap<String, LoggingFactory>();


private static HashMap<String, LoggingFactory> factoryMap;

public abstract ILogger getLogger();

public static void register(String type, LoggingFactory factory)
factoryMap.put(type, factory);


public static LoggingFactory getFactory(String type)
return factoryMap.get(type);




ConsoleOutputLoggingFactory:



public class ConsoleOutputLoggingFactory extends LoggingFactory 
static
LoggingFactory.register("ConsoleOutputLoggingFactory", new ConsoleOutputLoggingFactory());


@Override
public ILogger getLogger()
return new ConsoleOutputLogger();




ConsoleOutputLogger:



public class ConsoleOutputLoggerimplements ILogger 
@Override
public void log(String content)
System.out.println("ConsoleOutputLogger " + content);




FileOutputLoggingFactory:



public class FileOutputLoggingFactory extends LoggingFactory 
static
LoggingFactory.register("FileOutputLoggingFactory", new FileOutputLoggingFactory());


@Override
public ILogger getLogger()
return new FileOutputLogger();




FileOutputLogger:



public class FileOutputLogger implements ILogger 
@Override
public void log(String content)
//write output to file




ConsoleErrorLoggingFactory:



public class ConsoleErrorLoggingFactory extends LoggingFactory 
static
LoggingFactory.register("ConsoleErrorLoggingFactory", new ConsoleErrorLoggingFactory());


@Override
public ILogger getLogger()
return new ConsoleErrorLogger();




ConsoleErrorLogger:



public class ConsoleErrorLogger implements ILogger 
@Override
public void log(String content)
System.out.println("ConsoleErrorLogger" + content);




FileErrorLoggingFactory:



public class FileErrorLoggingFactory extends LoggingFactory 
static
LoggingFactory.register("FileErrorLoggingFactory", new FileErrorLoggingFactory());


@Override
public ILogger getLogger()
return new FileErrorLogger();




FileErrorLogger:



public class FileErrorLogger implements ILogger 
@Override
public void log(String content)
//write error to file




Factory Initializer:



public class LoggingInitializer 
public LoggingInitializer()
LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());




Main:



public class AbstractFactoryExample 
public static void main(String args)
new LoggingInitializer();

ILogger outputLogger = LoggingFactory.getFactory("OutputLogger").getLogger();
if (outputLogger != null)
outputLogger.log("Hello World");








share|improve this question

























    up vote
    0
    down vote

    favorite
    1












    I am new to Design Pattern implementation and would like to strongly solidify my knowledge to become as good of a programmer as I can. Is this a proper implementation of the Abstract Factory design? The idea here is that I can interchangeably utilize either a ConsoleLogger or a FileLogger for three different "levels" of logging (Execution, Output, and Error). I want the client to be able to log Execution and Output to console, but Error logs to a file if necessary.



    Logger Interface:



    public interface ILogger 
    public void log(String content);



    Base Logging Factory:



    import java.util.HashMap;

    public abstract class LoggingFactory
    static
    factoryMap = new HashMap<String, LoggingFactory>();


    private static HashMap<String, LoggingFactory> factoryMap;

    public abstract ILogger getLogger();

    public static void register(String type, LoggingFactory factory)
    factoryMap.put(type, factory);


    public static LoggingFactory getFactory(String type)
    return factoryMap.get(type);




    ConsoleOutputLoggingFactory:



    public class ConsoleOutputLoggingFactory extends LoggingFactory 
    static
    LoggingFactory.register("ConsoleOutputLoggingFactory", new ConsoleOutputLoggingFactory());


    @Override
    public ILogger getLogger()
    return new ConsoleOutputLogger();




    ConsoleOutputLogger:



    public class ConsoleOutputLoggerimplements ILogger 
    @Override
    public void log(String content)
    System.out.println("ConsoleOutputLogger " + content);




    FileOutputLoggingFactory:



    public class FileOutputLoggingFactory extends LoggingFactory 
    static
    LoggingFactory.register("FileOutputLoggingFactory", new FileOutputLoggingFactory());


    @Override
    public ILogger getLogger()
    return new FileOutputLogger();




    FileOutputLogger:



    public class FileOutputLogger implements ILogger 
    @Override
    public void log(String content)
    //write output to file




    ConsoleErrorLoggingFactory:



    public class ConsoleErrorLoggingFactory extends LoggingFactory 
    static
    LoggingFactory.register("ConsoleErrorLoggingFactory", new ConsoleErrorLoggingFactory());


    @Override
    public ILogger getLogger()
    return new ConsoleErrorLogger();




    ConsoleErrorLogger:



    public class ConsoleErrorLogger implements ILogger 
    @Override
    public void log(String content)
    System.out.println("ConsoleErrorLogger" + content);




    FileErrorLoggingFactory:



    public class FileErrorLoggingFactory extends LoggingFactory 
    static
    LoggingFactory.register("FileErrorLoggingFactory", new FileErrorLoggingFactory());


    @Override
    public ILogger getLogger()
    return new FileErrorLogger();




    FileErrorLogger:



    public class FileErrorLogger implements ILogger 
    @Override
    public void log(String content)
    //write error to file




    Factory Initializer:



    public class LoggingInitializer 
    public LoggingInitializer()
    LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
    LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
    LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
    LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());




    Main:



    public class AbstractFactoryExample 
    public static void main(String args)
    new LoggingInitializer();

    ILogger outputLogger = LoggingFactory.getFactory("OutputLogger").getLogger();
    if (outputLogger != null)
    outputLogger.log("Hello World");








    share|improve this question





















      up vote
      0
      down vote

      favorite
      1









      up vote
      0
      down vote

      favorite
      1






      1





      I am new to Design Pattern implementation and would like to strongly solidify my knowledge to become as good of a programmer as I can. Is this a proper implementation of the Abstract Factory design? The idea here is that I can interchangeably utilize either a ConsoleLogger or a FileLogger for three different "levels" of logging (Execution, Output, and Error). I want the client to be able to log Execution and Output to console, but Error logs to a file if necessary.



      Logger Interface:



      public interface ILogger 
      public void log(String content);



      Base Logging Factory:



      import java.util.HashMap;

      public abstract class LoggingFactory
      static
      factoryMap = new HashMap<String, LoggingFactory>();


      private static HashMap<String, LoggingFactory> factoryMap;

      public abstract ILogger getLogger();

      public static void register(String type, LoggingFactory factory)
      factoryMap.put(type, factory);


      public static LoggingFactory getFactory(String type)
      return factoryMap.get(type);




      ConsoleOutputLoggingFactory:



      public class ConsoleOutputLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("ConsoleOutputLoggingFactory", new ConsoleOutputLoggingFactory());


      @Override
      public ILogger getLogger()
      return new ConsoleOutputLogger();




      ConsoleOutputLogger:



      public class ConsoleOutputLoggerimplements ILogger 
      @Override
      public void log(String content)
      System.out.println("ConsoleOutputLogger " + content);




      FileOutputLoggingFactory:



      public class FileOutputLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("FileOutputLoggingFactory", new FileOutputLoggingFactory());


      @Override
      public ILogger getLogger()
      return new FileOutputLogger();




      FileOutputLogger:



      public class FileOutputLogger implements ILogger 
      @Override
      public void log(String content)
      //write output to file




      ConsoleErrorLoggingFactory:



      public class ConsoleErrorLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("ConsoleErrorLoggingFactory", new ConsoleErrorLoggingFactory());


      @Override
      public ILogger getLogger()
      return new ConsoleErrorLogger();




      ConsoleErrorLogger:



      public class ConsoleErrorLogger implements ILogger 
      @Override
      public void log(String content)
      System.out.println("ConsoleErrorLogger" + content);




      FileErrorLoggingFactory:



      public class FileErrorLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("FileErrorLoggingFactory", new FileErrorLoggingFactory());


      @Override
      public ILogger getLogger()
      return new FileErrorLogger();




      FileErrorLogger:



      public class FileErrorLogger implements ILogger 
      @Override
      public void log(String content)
      //write error to file




      Factory Initializer:



      public class LoggingInitializer 
      public LoggingInitializer()
      LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
      LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
      LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
      LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());




      Main:



      public class AbstractFactoryExample 
      public static void main(String args)
      new LoggingInitializer();

      ILogger outputLogger = LoggingFactory.getFactory("OutputLogger").getLogger();
      if (outputLogger != null)
      outputLogger.log("Hello World");








      share|improve this question











      I am new to Design Pattern implementation and would like to strongly solidify my knowledge to become as good of a programmer as I can. Is this a proper implementation of the Abstract Factory design? The idea here is that I can interchangeably utilize either a ConsoleLogger or a FileLogger for three different "levels" of logging (Execution, Output, and Error). I want the client to be able to log Execution and Output to console, but Error logs to a file if necessary.



      Logger Interface:



      public interface ILogger 
      public void log(String content);



      Base Logging Factory:



      import java.util.HashMap;

      public abstract class LoggingFactory
      static
      factoryMap = new HashMap<String, LoggingFactory>();


      private static HashMap<String, LoggingFactory> factoryMap;

      public abstract ILogger getLogger();

      public static void register(String type, LoggingFactory factory)
      factoryMap.put(type, factory);


      public static LoggingFactory getFactory(String type)
      return factoryMap.get(type);




      ConsoleOutputLoggingFactory:



      public class ConsoleOutputLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("ConsoleOutputLoggingFactory", new ConsoleOutputLoggingFactory());


      @Override
      public ILogger getLogger()
      return new ConsoleOutputLogger();




      ConsoleOutputLogger:



      public class ConsoleOutputLoggerimplements ILogger 
      @Override
      public void log(String content)
      System.out.println("ConsoleOutputLogger " + content);




      FileOutputLoggingFactory:



      public class FileOutputLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("FileOutputLoggingFactory", new FileOutputLoggingFactory());


      @Override
      public ILogger getLogger()
      return new FileOutputLogger();




      FileOutputLogger:



      public class FileOutputLogger implements ILogger 
      @Override
      public void log(String content)
      //write output to file




      ConsoleErrorLoggingFactory:



      public class ConsoleErrorLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("ConsoleErrorLoggingFactory", new ConsoleErrorLoggingFactory());


      @Override
      public ILogger getLogger()
      return new ConsoleErrorLogger();




      ConsoleErrorLogger:



      public class ConsoleErrorLogger implements ILogger 
      @Override
      public void log(String content)
      System.out.println("ConsoleErrorLogger" + content);




      FileErrorLoggingFactory:



      public class FileErrorLoggingFactory extends LoggingFactory 
      static
      LoggingFactory.register("FileErrorLoggingFactory", new FileErrorLoggingFactory());


      @Override
      public ILogger getLogger()
      return new FileErrorLogger();




      FileErrorLogger:



      public class FileErrorLogger implements ILogger 
      @Override
      public void log(String content)
      //write error to file




      Factory Initializer:



      public class LoggingInitializer 
      public LoggingInitializer()
      LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
      LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
      LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
      LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());




      Main:



      public class AbstractFactoryExample 
      public static void main(String args)
      new LoggingInitializer();

      ILogger outputLogger = LoggingFactory.getFactory("OutputLogger").getLogger();
      if (outputLogger != null)
      outputLogger.log("Hello World");










      share|improve this question










      share|improve this question




      share|improve this question









      asked Feb 8 at 18:19









      Hans Landa

      1




      1




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote














          static 
          factoryMap = new HashMap<String, LoggingFactory>();


          private static HashMap<String, LoggingFactory> factoryMap;



          can be simplified to the following without any changes in functionality:



          private static final Map<String, LoggingFactory> factoryMap = new HashMap<>();




          public class LoggingInitializer 
          public LoggingInitializer()
          LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
          LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
          LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
          LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());





          The initialization of a class only happens in it's initializer blocks. Nowhere else.

          What you're doing here is wiring up dependencies. Use a DI framework for that ...



          If you were going to set up the factories this way in the first place, you could've just not have them register themselves. It's weird that they register themselves anyways. That results in the following changes:



          1. LoggerFactory implementations don't need to be derived from LoggingFactory to have access to the factoryMap, only to conform to the getLogger interface.

          2. Actually the getLogger interface is what you'd have in a functional interface in modern Java.

          This results in simplifications to your API. Instead of explicitly constructing factories and using getFactory, you're off much better hiding the implementation detail of Factories and instead using a Facade, like so:



          public static final class LoggingFactory 
          private static final Map<String, Supplier<ILogger>> factoryMap = new HashMap<>();
          static
          ILogger consoleOutLoggerSingleton = new ConsoleOutputLogger();
          factoryMap.put("ConsoleOutputLogger", () -> consoleOutputLoggerSingleton);

          ILogger fileOutputLoggerSingleton = new FileOutputLogger();
          factoryMap.put("FileOutputLogger", () -> fileOutputLoggerSingleton);

          ILogger consoleErrorLoggerSingleton = new ConsoleErrorLogger();
          factoryMap.put("ConsoleErrorLogger", () -> consoleErrorLoggerSingleton);

          ILogger fileErrorLoggerSingleton = new FileErrorLogger();
          factoryMap.put("FileErrorLogger", () -> fileErrorLoggerSingleton);


          public static ILogger getLoggerFor(String name)
          return factoryMap.getOrDefault(name, () -> new NoOpLogger()).get();




          This cuts away the "man in the middle" of your factory, not to mention the initialization outside the class. It also is more in line with usual Java logging APIs, where you directly obtain the logger.



          In closing you should be aware that reinventing logging is usually a "Bad Idea™". If this hadn't been prefixed, I'd have washed your head for it :)



          Finally: Just because there is a factory, the client of you API doesn't need to know- Generally the less indirection your API has, the easier it will be to use. Strive to minimize ways through your API.






          share|improve this answer





















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187109%2fabstract-factory-design-java%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote














            static 
            factoryMap = new HashMap<String, LoggingFactory>();


            private static HashMap<String, LoggingFactory> factoryMap;



            can be simplified to the following without any changes in functionality:



            private static final Map<String, LoggingFactory> factoryMap = new HashMap<>();




            public class LoggingInitializer 
            public LoggingInitializer()
            LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
            LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
            LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
            LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());





            The initialization of a class only happens in it's initializer blocks. Nowhere else.

            What you're doing here is wiring up dependencies. Use a DI framework for that ...



            If you were going to set up the factories this way in the first place, you could've just not have them register themselves. It's weird that they register themselves anyways. That results in the following changes:



            1. LoggerFactory implementations don't need to be derived from LoggingFactory to have access to the factoryMap, only to conform to the getLogger interface.

            2. Actually the getLogger interface is what you'd have in a functional interface in modern Java.

            This results in simplifications to your API. Instead of explicitly constructing factories and using getFactory, you're off much better hiding the implementation detail of Factories and instead using a Facade, like so:



            public static final class LoggingFactory 
            private static final Map<String, Supplier<ILogger>> factoryMap = new HashMap<>();
            static
            ILogger consoleOutLoggerSingleton = new ConsoleOutputLogger();
            factoryMap.put("ConsoleOutputLogger", () -> consoleOutputLoggerSingleton);

            ILogger fileOutputLoggerSingleton = new FileOutputLogger();
            factoryMap.put("FileOutputLogger", () -> fileOutputLoggerSingleton);

            ILogger consoleErrorLoggerSingleton = new ConsoleErrorLogger();
            factoryMap.put("ConsoleErrorLogger", () -> consoleErrorLoggerSingleton);

            ILogger fileErrorLoggerSingleton = new FileErrorLogger();
            factoryMap.put("FileErrorLogger", () -> fileErrorLoggerSingleton);


            public static ILogger getLoggerFor(String name)
            return factoryMap.getOrDefault(name, () -> new NoOpLogger()).get();




            This cuts away the "man in the middle" of your factory, not to mention the initialization outside the class. It also is more in line with usual Java logging APIs, where you directly obtain the logger.



            In closing you should be aware that reinventing logging is usually a "Bad Idea™". If this hadn't been prefixed, I'd have washed your head for it :)



            Finally: Just because there is a factory, the client of you API doesn't need to know- Generally the less indirection your API has, the easier it will be to use. Strive to minimize ways through your API.






            share|improve this answer

























              up vote
              1
              down vote














              static 
              factoryMap = new HashMap<String, LoggingFactory>();


              private static HashMap<String, LoggingFactory> factoryMap;



              can be simplified to the following without any changes in functionality:



              private static final Map<String, LoggingFactory> factoryMap = new HashMap<>();




              public class LoggingInitializer 
              public LoggingInitializer()
              LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
              LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
              LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
              LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());





              The initialization of a class only happens in it's initializer blocks. Nowhere else.

              What you're doing here is wiring up dependencies. Use a DI framework for that ...



              If you were going to set up the factories this way in the first place, you could've just not have them register themselves. It's weird that they register themselves anyways. That results in the following changes:



              1. LoggerFactory implementations don't need to be derived from LoggingFactory to have access to the factoryMap, only to conform to the getLogger interface.

              2. Actually the getLogger interface is what you'd have in a functional interface in modern Java.

              This results in simplifications to your API. Instead of explicitly constructing factories and using getFactory, you're off much better hiding the implementation detail of Factories and instead using a Facade, like so:



              public static final class LoggingFactory 
              private static final Map<String, Supplier<ILogger>> factoryMap = new HashMap<>();
              static
              ILogger consoleOutLoggerSingleton = new ConsoleOutputLogger();
              factoryMap.put("ConsoleOutputLogger", () -> consoleOutputLoggerSingleton);

              ILogger fileOutputLoggerSingleton = new FileOutputLogger();
              factoryMap.put("FileOutputLogger", () -> fileOutputLoggerSingleton);

              ILogger consoleErrorLoggerSingleton = new ConsoleErrorLogger();
              factoryMap.put("ConsoleErrorLogger", () -> consoleErrorLoggerSingleton);

              ILogger fileErrorLoggerSingleton = new FileErrorLogger();
              factoryMap.put("FileErrorLogger", () -> fileErrorLoggerSingleton);


              public static ILogger getLoggerFor(String name)
              return factoryMap.getOrDefault(name, () -> new NoOpLogger()).get();




              This cuts away the "man in the middle" of your factory, not to mention the initialization outside the class. It also is more in line with usual Java logging APIs, where you directly obtain the logger.



              In closing you should be aware that reinventing logging is usually a "Bad Idea™". If this hadn't been prefixed, I'd have washed your head for it :)



              Finally: Just because there is a factory, the client of you API doesn't need to know- Generally the less indirection your API has, the easier it will be to use. Strive to minimize ways through your API.






              share|improve this answer























                up vote
                1
                down vote










                up vote
                1
                down vote










                static 
                factoryMap = new HashMap<String, LoggingFactory>();


                private static HashMap<String, LoggingFactory> factoryMap;



                can be simplified to the following without any changes in functionality:



                private static final Map<String, LoggingFactory> factoryMap = new HashMap<>();




                public class LoggingInitializer 
                public LoggingInitializer()
                LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
                LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
                LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
                LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());





                The initialization of a class only happens in it's initializer blocks. Nowhere else.

                What you're doing here is wiring up dependencies. Use a DI framework for that ...



                If you were going to set up the factories this way in the first place, you could've just not have them register themselves. It's weird that they register themselves anyways. That results in the following changes:



                1. LoggerFactory implementations don't need to be derived from LoggingFactory to have access to the factoryMap, only to conform to the getLogger interface.

                2. Actually the getLogger interface is what you'd have in a functional interface in modern Java.

                This results in simplifications to your API. Instead of explicitly constructing factories and using getFactory, you're off much better hiding the implementation detail of Factories and instead using a Facade, like so:



                public static final class LoggingFactory 
                private static final Map<String, Supplier<ILogger>> factoryMap = new HashMap<>();
                static
                ILogger consoleOutLoggerSingleton = new ConsoleOutputLogger();
                factoryMap.put("ConsoleOutputLogger", () -> consoleOutputLoggerSingleton);

                ILogger fileOutputLoggerSingleton = new FileOutputLogger();
                factoryMap.put("FileOutputLogger", () -> fileOutputLoggerSingleton);

                ILogger consoleErrorLoggerSingleton = new ConsoleErrorLogger();
                factoryMap.put("ConsoleErrorLogger", () -> consoleErrorLoggerSingleton);

                ILogger fileErrorLoggerSingleton = new FileErrorLogger();
                factoryMap.put("FileErrorLogger", () -> fileErrorLoggerSingleton);


                public static ILogger getLoggerFor(String name)
                return factoryMap.getOrDefault(name, () -> new NoOpLogger()).get();




                This cuts away the "man in the middle" of your factory, not to mention the initialization outside the class. It also is more in line with usual Java logging APIs, where you directly obtain the logger.



                In closing you should be aware that reinventing logging is usually a "Bad Idea™". If this hadn't been prefixed, I'd have washed your head for it :)



                Finally: Just because there is a factory, the client of you API doesn't need to know- Generally the less indirection your API has, the easier it will be to use. Strive to minimize ways through your API.






                share|improve this answer














                static 
                factoryMap = new HashMap<String, LoggingFactory>();


                private static HashMap<String, LoggingFactory> factoryMap;



                can be simplified to the following without any changes in functionality:



                private static final Map<String, LoggingFactory> factoryMap = new HashMap<>();




                public class LoggingInitializer 
                public LoggingInitializer()
                LoggingFactory.register("ConsoleOutputLogger", new ConsoleOutputLoggingFactory());
                LoggingFactory.register("FileOutputLogger", new FileOutputLoggingFactory());
                LoggingFactory.register("ConsoleErrorLogger", new ConsoleErrorLoggingFactory());
                LoggingFactory.register("FileErrorLogger", new FileErrorLoggingFactory());





                The initialization of a class only happens in it's initializer blocks. Nowhere else.

                What you're doing here is wiring up dependencies. Use a DI framework for that ...



                If you were going to set up the factories this way in the first place, you could've just not have them register themselves. It's weird that they register themselves anyways. That results in the following changes:



                1. LoggerFactory implementations don't need to be derived from LoggingFactory to have access to the factoryMap, only to conform to the getLogger interface.

                2. Actually the getLogger interface is what you'd have in a functional interface in modern Java.

                This results in simplifications to your API. Instead of explicitly constructing factories and using getFactory, you're off much better hiding the implementation detail of Factories and instead using a Facade, like so:



                public static final class LoggingFactory 
                private static final Map<String, Supplier<ILogger>> factoryMap = new HashMap<>();
                static
                ILogger consoleOutLoggerSingleton = new ConsoleOutputLogger();
                factoryMap.put("ConsoleOutputLogger", () -> consoleOutputLoggerSingleton);

                ILogger fileOutputLoggerSingleton = new FileOutputLogger();
                factoryMap.put("FileOutputLogger", () -> fileOutputLoggerSingleton);

                ILogger consoleErrorLoggerSingleton = new ConsoleErrorLogger();
                factoryMap.put("ConsoleErrorLogger", () -> consoleErrorLoggerSingleton);

                ILogger fileErrorLoggerSingleton = new FileErrorLogger();
                factoryMap.put("FileErrorLogger", () -> fileErrorLoggerSingleton);


                public static ILogger getLoggerFor(String name)
                return factoryMap.getOrDefault(name, () -> new NoOpLogger()).get();




                This cuts away the "man in the middle" of your factory, not to mention the initialization outside the class. It also is more in line with usual Java logging APIs, where you directly obtain the logger.



                In closing you should be aware that reinventing logging is usually a "Bad Idea™". If this hadn't been prefixed, I'd have washed your head for it :)



                Finally: Just because there is a factory, the client of you API doesn't need to know- Generally the less indirection your API has, the easier it will be to use. Strive to minimize ways through your API.







                share|improve this answer













                share|improve this answer



                share|improve this answer











                answered Feb 9 at 1:56









                Vogel612♦

                20.9k345124




                20.9k345124






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187109%2fabstract-factory-design-java%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Greedy Best First Search implementation in Rust

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    C++11 CLH Lock Implementation