-1

I'm looking for a design pattern for a set of methods which will be used in several projects so I'm making a "library" with them.

At first I thought of making all of them static so they could be called by Library.methodName() and that's it. I did and realized I was passing around a couple of constant values for every method which can set once and then used inside the class. (This constant values change between projects)

Now I thought of having a Class which has to be instantiated with this values and access the methods trough the object without passing the values every time, however I want to prevent the creation of objects of the "Library" class every time so I thought of Singleton.

I did make a Singleton with all of this, however I need to make an explicit set for the class variables at first, but this approach requires the programmer to now that the value has to be set before using the methods, which will make it fail for sure eventually, even by myself.

doing Singleton.getInsance(value1, value2).method(...) all the time is out of the question, I'd prefer my initial approach. Also, I can't define a "default" value for this variables, they HAVE to be set.

Is there a design pattern that will help me have a Singleton which can be initialized with given values and not having to pass them around all the time?

or should I just stick with my initial approach and make the programmer pass the values all the time?

or any other option, any design pattern that fits, or anything else may also work.

Thanks

hectorg87
  • 753
  • 1
  • 7
  • 24
  • 2
    Why not use a "normal class" with a 2-args constructor and construct an instance of it when you need it? If you need to set some parameters every time for the object, it does not sound like a good candidate for a singleton... – assylias Aug 29 '12 at 08:35
  • @assylias because: "I want to prevent the creation of objects of the "Library" class every time so I thought of Singleton" – hectorg87 Aug 29 '12 at 08:36
  • Singleton is an overused pattern, especially in Java. Heavy use of static is an anti-pattern as your code will become difficult to unit test since you can't mock your object's collaborators. – SteveD Aug 29 '12 at 08:38
  • You can have overloaded getinstance method one with parameters and another without it. In first call client should call it with parameters however subsequent call may call getinstance without it because value has already been initialized. – Ajay Tiwari Aug 29 '12 at 08:39
  • I suggest reading 'Growing Object-Orientated Software, Guided by Tests' for patterns on OO software construction. – SteveD Aug 29 '12 at 08:40
  • @ajay I also though of this, however this would still require the programmer to be aware of calling the proper getInstance – hectorg87 Aug 29 '12 at 08:41
  • @hectorg87 Why do you *"want to prevent the creation of objects of the "Library" class"*? The calling client can only create one instance if they decide to. – assylias Aug 29 '12 at 08:43
  • @assylias because I want to make it "dumb-proof" and prevent stuff like `new Object(value1,value2).methodX()` , `new Object(value1,value2).methodY()` all the time. With this in mind, I think my only other option is my first approach – hectorg87 Aug 29 '12 at 08:45
  • @hectorg87 Have a look at the libraries you use every day, it is the client's responsibility to use them correctly - you should not use a [flawed design](http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons) just because some clients might be dumb. – assylias Aug 29 '12 at 08:52
  • @assylias you are right, it is usually the client's responsibility, however that doesn't make it good and I guess it is a good practice to **don't allow a client do anything with your library that they are not supposed to do**. Am I wrong thinking like that? – hectorg87 Aug 29 '12 at 09:08

6 Answers6

0

should I just stick with my initial approach and make the programmer pass the values all the time?

The only alternative to this I can see is to have a Constructor for a context which holds and sets all the mandatory values. I would avoid using a stateful singleton if you can.

If the caller wants to avoid creating the object multiple times, they can make it a singleton if they want to, but you shouldn't force them to use a singleton.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I get it, but as I told @assylias on the comments, I want to make it "dumb-proof" and prevent stuff like `new Object(value1,value2).methodX()` , `new Object(value1,value2).methodY()` all the time. With this in mind, I think my only other option is my first approach – hectorg87 Aug 29 '12 at 08:48
0

Or, since these value change between project but not inside a project, your "library" can read a configuration file giving you the values value1, value2 so that the calling code does not need to give them each time.

This would be a lazy reading (made at first call) so you are additionally assured that the library is initialized before being used. You might want then to throw an unchecked exception if the file does not exist of course.

jolivier
  • 7,380
  • 3
  • 29
  • 47
  • I thought of this. All our projects have a "Config" class, which I can expect them to have and have a dummy one in my library for it to compile. The only problem with this is that the Config class is never in the same package between projects :-S – hectorg87 Aug 29 '12 at 08:54
  • I was more thinking of a config **file**, like yourlibrary.ini to be put at the root of the classpath, as log4j and java.util.logging do – jolivier Aug 29 '12 at 09:01
  • You are so close to my problem. This Config class what does is to read a config file, which is different for each project and is on a different path each time, which is not on the classpath. Actually the values I say that have to be passed around all the time are values read from that config file. – hectorg87 Aug 29 '12 at 09:09
  • then in my opinion this config file should be split into multiple parts, the parts relevant for your library that is in a standardized non changing place, and the part that is relevant to your projects which you can place wherever you want. In my opinion your library should not depend on a class from a dependency (you are inserting cyclic dependency), if it has a configuration it should have its own config class and the config class of the project should read from the config class of your library if needed, not the other way around – jolivier Aug 29 '12 at 09:13
0

Is this way comfortable for you ?

public class AreaCalculator {
  private int length = 10;
  private int width = 10;
  private static final AreaCalculator areaCalculator = new AreaCalculator();

  private AreaCalculator() {
    // TODO Auto-generated constructor stub
  }

  public static AreaCalculator getInstance() {
    return areaCalculator;
  }

  public AreaCalculator fillLength(int length) {
    this.length = length;
    return getInstance();
  }

  public AreaCalculator fillWidth(int width) {
    this.width = width;
    return getInstance();
  }

  public AreaCalculator fillAll(int length, int width) {
    this.length = length;
    this.width = width;
    return getInstance();
  }

public int calculateArea() {
    if (!isInit()) {
        throw new RuntimeException("Should Init first!");
    }
    return length * width;
}

public boolean isInit() {
    // add something
    return true;
}

Test Code

public class TestMain {

  public static void main(String[] args) {
    int result = AreaCalculator.getInstance().fillWidth(20).calculateArea();
    System.out.println("10*20=" + result);
    result = AreaCalculator.getInstance().fillWidth(10).fillLength(10).calculateArea();
    System.out.println("10*10=" + result);
    result = AreaCalculator.getInstance().fillAll(10, 30).calculateArea();
    System.out.println("10*30=" + result);
  }

**

Using Config interface.

**

ConfigInf(lib side)

public interface ConfigInf {

    public static String F_LENGTH = "length";
    public static String F_WIDTH = "width";

    public String getProperty(String key);

}

ConfigFactory(lib side)

public class ConfigFactory {

    private static ConfigInf config = null;

    public static void init(ConfigInf config) {
        ConfigFactory.config = config;
    }

    public static ConfigInf getConfig() {
        if (config == null) {
            throw new NullPointerException("Config should be init first");
        }
        return config;
    }
}

ClientConfig (client side)

public class ClientConfig implements ConfigInf {

    String value = "10";

    @Override
    public String getProperty(String key) {
        // read configFile
        if (ConfigInf.F_LENGTH == key) {
            return value;
        } else {
            return "100";
        }

    }

    public void update() {
        value = "100";
    }

}

AreaCalculatorWithConfig(lib side)

public class AreaCalculatorWithConfig {
    private int length = 10;
    private int width = 10;
    //
    private static final AreaCalculatorWithConfig areaCalculator = new AreaCalculatorWithConfig();

    private AreaCalculatorWithConfig() {
        // TODO Auto-generated constructor stub
    }

    public static AreaCalculatorWithConfig getInstance() {
        return areaCalculator;
    }

    public int calculateArea() {
        ConfigInf config = ConfigFactory.getConfig();
        length = getInt(config.getProperty(ConfigInf.F_LENGTH));
        width = getInt(config.getProperty(ConfigInf.F_WIDTH));
        return length * width;
    }

    public static int getInt(String value) {
        return Integer.parseInt(value);
    }
}

TestMainWithConfig (client side)

public class TestMainWithConfig {
    public static void main(String[] args) {
        // init;
        ClientConfig config = new ClientConfig();
        ConfigFactory.init(config);
        //
        System.out.println("Before update:"
                + AreaCalculatorWithConfig.getInstance().calculateArea());
        config.update();
        System.out.println("After update:"
                + AreaCalculatorWithConfig.getInstance().calculateArea());
    }
}
wodong
  • 297
  • 2
  • 10
  • No, because If somebody calls `AreaCalculator.getInstance().calculateArea();` before anything else, on my case it would fail, because I can't define default values for the class variables. – hectorg87 Aug 29 '12 at 09:16
  • If you use static variable(in your first way), you will also get error when you run method without initialize. You can throw an exception if the data are not prepared. I updated my code with exception managed. I also file a demo for config file which mentioned between you and @jolivier. Hope that helps... – wodong Aug 29 '12 at 10:32
0

For your requirement you can use Factory pattern Create Library instance based on the constant passed then Singleton to create instances.

Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
0

I'd simply add the initialisation to the Config classes, where it can be relyably initialized exactly once. The rest of the application then relies on the initialization to be done correctly. Maybe you might want to avoid duplicate initialization by an exception. The trick is to ensure there only one point responible for filling the singleton, either by design or with the brute force of an exception. Configuration of logging works very similar. Though, it's not too strange.

Bernd Ebertz
  • 1,317
  • 8
  • 10
0

The library you're trying to create is totally against principles of object oriented design. You should not create a library of functions/methods. Instead, you should make a library of classes, with states and behavior.

yegor256
  • 102,010
  • 123
  • 446
  • 597