2

First SE stack,

I am working on a large chunk of old Java code and am finding tons of duplication and inconsistently configured/created objects because of different authors, skill levels, etc.

I have implemented a few static factory patterns and am having a debate as how to make the factory configurable.

EDIT: per comment suggestions,

Option A:

public final class TacoFactory {

    private static int defaultCheese = 0;

    private TacoFactory() {}

    public static Taco createTaco(int cheese) {}

    public static Taco createDefaultTaco() { createTaco(defaultCheese); }

    public static synchronized void configure(int cheese) { 
        this.defaultCheese = cheese; 
    }
}

Option B:

public final class TacoFactory {

    public static int defaultCheese = 0;

    private TacoFactory() {}

    public static Taco createTaco(int cheese) {}

    public static Taco createDefaultTaco() { createTaco(defaultCheese); }
}

Option C: Some elite way/pattern that google-fu has yet to give me. If there is some good documentation on this pattern, please share. :)

Option D: Doesn't matter and/or isn't specified.

Option E: Builder Pattern, although I voiced my concerns as to why I don't think this fits my use case on the answer that suggest it below.

class Taco {
    private final int cheese;
    private final int beef;

    Taco(int cheese, int beef) {
        this.cheese = cheese;
        this.beef = beef;
    }
}

class TacoBuilder {
    private int cheese = 0; 

    TacoBuilder setCheese(int cheese) {
        this.cheese = cheese;
        return this;
    }

    TacoBuilder setBeef(int beef) {
        this.beef = beef;
        return this;
    }

    Taco build() {
        return new Taco(a, b);
    }
}

Foo foo = new FooBuilder().setA("a").build();
19
  • 3
    what is your motivation for having "setDefaultCheese" in option A? Aug 30, 2017 at 22:53
  • Underlying reason is that as code is being rewritten, I am trying to be flexible to the current configuration management. Currently, system is pulling configuration from xml file on a per object creation basis (terrible for this system in my opinion). The plan is to move it to one time configuration read to some config object and configuring objects on construction from the configuration that will now be in memory. I have no control over that plan and who knows, it could change again, so my thinking is being able to configure defaultCheese might be redundant but more flexible in the end. Aug 30, 2017 at 23:24
  • tldr; making the default configurable is more flexible in the long run and hopefully makes the code completely reusable. Aug 30, 2017 at 23:30
  • 1
    Which option most effectively satisfies your specific software requirements? Aug 30, 2017 at 23:48
  • 2
    is this java, C#, or some weird language that has no return keyword? Aug 31, 2017 at 3:46

2 Answers 2

3

Option B seems highly preferable for a static factory, as allowing for configuration of a static class is just asking for trouble.

  • In a single threaded environment you will still see issues, where module A configures the factory, but module B was expecting a different configuration. This is especially important when you do not "own" all of the client code (still important if you do though).

  • In a multi-threaded environment (even if you synchronize the methods), you could have one thread change the default while another is trying to get the default, and end up with non-deterministic behavior (due to the race condition).

If you want a configurable factory, make it non-static. This will make the code re-usable. If it is configurable and static, no one can use it, because they can't rely on other programmers in the same code base changing the configuration else-where.

2
  • You very last section has got me thinking. The reality is no one will be calling configure at the time of or after the first object is created. But leaving the possibility is just as much a concern as the flexibility. using option B as a base point, if i create two constructors one with new configured values, and one empty constructor and remove static from the rest of the methods. I will still have default values, but they can only be configured by creating a separate object. Yeah? Aug 31, 2017 at 20:31
  • in the above i did not mean to include removing the static methods as part of the solution. Aug 31, 2017 at 20:40
1

Option A seems the closest to what I would be expecting. It looks like you have tried to implement the Builder pattern for your factory, but it doesn't seem to provide a complete interface.

I recommend reading Vitali Fedorenko's answer to this question and then follow the option 5 from that answer.

3
  • The main problem with using a builder is for me, in this instance, I do not always own the code for "Taco" or this would be a perfect fit. I am trying to enforce a standardized configuration for all of our commonly used objects (whether we own them or not). This pattern will be used across about 20-25 objects. Aug 31, 2017 at 15:44
  • 1
    I think the Builder pattern is the best choice too. If you don't own the code, create a Wrapper class for those third-party classes and implement the Builder pattern in these wrappers (and use the wrapper from now on the entire project). The pattern itself is already the one you should follow for all your classes IMO. Aug 31, 2017 at 16:45
  • The builder pattern is great. For this specific situation tho, if someone wants to change the configuration, it will only pertain to that builder object. This is why I went completely static. I may be missing something so feel free to correct me. For a specific use case of the edited Option A: When our new configuration management is implemented and integrated, I don't want them to have to go and recompile my library. I want the configuration manager to be able to read their configuration, call my configures, and the programs will run without further changes. Aug 31, 2017 at 20:26

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.