7

Psuedo-code

The snippets provided are to be taken as psuedo-code. I am open to if there is a different solution that is the standard way to solve this problem.

This is about the expected usage:

Some clarification:

  • One, and only one configuration will be used per application. It will not be changed during runtime.
  • Main.java can not allow @Override.
  • Configuration.java can not be an Interface as default values should be given to fields not overridden.
  • Configuration.java will grow quite substantially from its two current fields. Rendering the builder-pattern very messy to work with.

Configuration.java

public class Configuration
{
    public static int getFoo () { return 1; }
    public static int getBar () { return 2; }
}

UserDefinedConfiguration.java

public class UserDefinedConfiguration extends Configuration
{
    @Override
    public static int getFoo () { return 3; }
}

Main.java

public final class Main {
    private final Configuration config;

    // default configuration
    public Main () {
        this (Configuration.class);
    }

    // user-defined configuration
    public Main (Class<? extends Configuration> config) {
        this.config = config;
    }

    // dummy-test
    public void printFoo () {
        System.out.println(config.getFoo());
    }
}

Now to the main question, how to accomplish this? If no (or Configuration is passed) getFoo() should return 1, if the UserDefinedConfiguration is passed then 3.

One way to accomplish it is to store an instance of Configuration. However, it feels redundant when all the getters are static. It doesn't make much sense to not have them as static either.

Note: This is taken into account.

Community
  • 1
  • 1
Emz
  • 1,280
  • 1
  • 14
  • 29
  • 2
    `It doesn't make much sense to not have them as static either.` - why not? You want to have different configuration sets and I assume that you create each configuration set only once, so the "overhead" of non-static methods (if at all) and the creation of one instance of your configuration should not matter. And you automatically gain the `@Override` with a clean solution. – Andreas Fester Dec 22 '15 at 10:32
  • Because it doesn't make any sense to have multiple `Configuration`s. The methods belong directly to the `Configuration`. I am not really worried about the "overhead". – Emz Dec 22 '15 at 10:34
  • Do the config values need to live in code? An alternative would be to create a hierarchy of property files or hash maps where values which are read later override previous values. You would then not need to model the inheritance as classes/interfaces. Just speculating, probably I misunderstand the question completely ... – Andreas Fester Dec 22 '15 at 10:41
  • I think you are onto something if I understand it correctly. Problem with a `HashMap` doing the storing part is that it can contain Integers, Strings, Doubles and what-not. Also, I want it to be more firm with what exists. The idea is that I provide a `Configuration`, if one or two things doesn't match the user(s) requirements then they can override just those things, while keeping everything else intact. I also need to make sure that the `Configuration` can not be changed during runtime. While still being accessible. – Emz Dec 22 '15 at 10:43

2 Answers2

1

Unless playing with dirty reflection, I'm afraid you'll have to work with instances instead of classes. From @JonSkeet:

A singleton allows access to a single created instance - that instance (or rather, a reference to that instance) can be passed as a parameter to other methods, and treated as a normal object.

A static class allows only static methods.

This is exactly what you're trying to do: passing the configuration as a parameter.


I would create an abstract class defining the default values:

public abstract class Configuration {
  public int getFoo() { return 1; }
  public int getBar() { return 2; }
}

Then, one singleton per concrete configuration:

public final class DefaultConfiguration extends Configuration {
  public static final Configuration INSTANCE = new DefaultConfiguration();
  private DefaultConfiguration() {}
  // nothing to override, use the default values
}

public final class UserDefinedConfiguration extends Configuration {
  public static final Configuration INSTANCE = new UserDefinedConfiguration();
  private UserDefinedConfiguration() {}
  @Override public int getFoo() { return 3; } // specific `foo` value
}

Finally, in your Main:

public class Main {
  private final Configuration config;
  public Main() { this(DefaultConfiguration.INSTANCE); }
  public Main(Configuration config) { this.config = config; }
}

Plus, note that Java 8 allows default methods implementations within interfaces; Configuration could then be an interface:

public interface Configuration {
    default int getFoo() { return 1; }
    default int getBar() { return 2; }
}
Community
  • 1
  • 1
sp00m
  • 47,968
  • 31
  • 142
  • 252
  • Nice remark of the `interface` in Java 8, I did not know about `default`. Not that it helps me in this case, as I can just use an abstract class to produce the same result. – Emz Dec 22 '15 at 13:34
  • I was afraid I had to resort to reflection to solve it "my" way. I prefer not to. – Emz Dec 22 '15 at 13:34
  • Instead of using Singletons I can just invoke a `new Configuration()` and pass it while removing `static` from the getters. Again however, this feel hacky as well as it is not directly what I want to accomplish. It will produce the same result in the end however. I did mention this briefly in my question `One way to accomplish it is to store an instance of Configuration. However, it feels redundant when all the getters are static. It doesn't make much sense to not have them as static either.` Singletons will get me around the problem of instantiating it twice however. – Emz Dec 22 '15 at 13:36
  • I really want to get around having to create an instance of the configuration file. Now this is what I want. What I want is different from what is possible / good praxis. I will think about it, read up some more and get back to you. – Emz Dec 22 '15 at 13:38
0

So essentially, you need polymorphism on a type rather than an instance. In Java this is usually done with generic types:

class GenericMain<T extends Configuration>
{
    private final T config;
}

and because Java doesn't allow default generic arguments, you have to define another class to specify the default:

class DefaultMain extends GenericMain<Configuration>
{
}

These match one-to-one to your Main () and Main (Class<? extends Configuration> config) constructors.


Alternatively, you could store an instance of Configuration and do something like this:

public class Configuration
{
    private final int foo = 1;
    private final int bar = 2;

    public final int getFoo () { return foo; }
    public final int getBar () { return bar; }

    public Configuration () {}

    protected Configuration (int foo) {
        this.foo = foo;
    }
}

public class UserDefinedConfiguration extends Configuration
{
    public UserDefinedConfiguration() {
        super(3);
    }
}
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • I do not want to expose this `Main` in any way. The only way the user(s) should use it is `Main main = new Main();`. Also, the `Configuration` class will have quite a few fields, easily over 100 (yes they are all directly related `Main`. Even using the builder-pattern will make it extremely messy for a user to change fields. – Emz Dec 22 '15 at 11:05