8

I have a class, which has an Initialize method, which creates a bunch of tables in a database. This class looks like this:

public class MyClass
{
  private bool initialized = false;

  public void Initialize()
  {
    if(!initialized)
    {
        //Install Database tables
        initialized = true;
    }
  }

  public void DoSomething()
  {
    //Some code which depends on the database tables being created 
  }

  public void DoSomethingElse()
  {
    //Some other code which depends on the database tables being created 
  }
} 

The two methods DoSomething and DoSomethingElse need to make sure that the Initialize method has been called before proceeding because they depend on having the tables in the database. I have two choices:

  1. Call the Initialize method in the constructor of the class - this does not seem like a good idea because constructors should now call methods, which are non-trivial and could cause an exception.

  2. Call the Initialize method in each of the two methods - this does not seem like a great solution either especially if there are more than a handful of methods.

Is there a design pattern which could solve this in a more elegant way?

Milen Kovachev
  • 5,111
  • 6
  • 41
  • 58

5 Answers5

10

I would use a static factory method in which Initialize is invoked, and make the constructor private, to force use of the static factory method:

public class MyClass
{
  private MyClass() { ... }

  public static MyClass createInstance() {
    MyClass instance = new MyClass();
    instance.Initialize();
    return instance;
  }
}

Also, I would remove the initialized variable - in part because you don't need it any more - but also because it requires some means of guaranteeing visibility (e.g. synchronization, volatile or AtomicBoolean) for thread safety.

I think that Miško Hevery's blog post on (not) doing work in constructors is an interesting read.

Community
  • 1
  • 1
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • so if I called MyClass.createInstance() more than once the database would be initialized more than once? – DaveH Apr 25 '16 at 14:35
  • @DaveH that is entirely dependent upon how you implement `Initialize`. – Andy Turner Apr 25 '16 at 14:37
  • @DaveH If you want to prevent your class from being initiliazed more than once you can use Singleton design pattern. – Karolis Kajenas Apr 25 '16 at 15:01
  • @Carl there is no particular requirement to use a singleton. For instance, you could use a proxy; there are then no necessary restrictions on its multiplicity. – Andy Turner Apr 25 '16 at 17:43
  • @AndyTurner Out of curiosity, what would be purpose of using Proxy in this case? – Karolis Kajenas Apr 25 '16 at 17:48
  • I don't agree with this answer. You should do this kind of initialisation work in an object created specifically for this - be it a factory, service locator, dependency injection framework or whatever. The major problem here is how are you going to test MyClass? The answer is it's either impossible of very difficult. What if MyClass is a collaborator in another class? Then this class is also nearly impossible to test as well. – Stuart Mar 01 '18 at 09:53
  • Totally agree with Stuart, singleton are best to avoid if possible. – Nick Turner Aug 13 '19 at 13:16
  • @NickTurner this isn't a singleton. – Andy Turner Aug 13 '19 at 13:19
1

I would separate the installation of the database from the definition of tasks that depends on it:

  • static factory could be used for the database installation as pointed out by @andy-turner

  • and the repository pattern to do work on the database

I suggest this solution because if i understand correctly, you are concerned about the high number of tasks that depends on the database.

Using the dependency injection pattern the repository can get a reference to the database, so in your bootstrapping code you can execute the database installation once and then inject the reference to the database in all the repositories that depends on it.

sc3w
  • 1,154
  • 9
  • 21
0

I would recommend using a collaborator that does the initialisation. That way MyClass can easily be tested by substituting a mock for the initialiser collaborator. For example:

public class MyClass {

public MyClass(MyClassInitialiser initialiser) {
    initialiser.initialize();
}

public void DoSomething() {
    //Some code which depends on the database tables being created
}

public void DoSomethingElse() {
    //Some other code which depends on the database tables being created
}

}

Stuart
  • 3,226
  • 5
  • 24
  • 28
0

Or an alternative solution, the idea here is that you're breaking the single responsibility principle in MyClass. There is non-trivial initialisation behaviour (installing database tables) and behaviour on those tables in the same class. So you should separate those responsibilities into two different classes and pass one in as a collaborator to the other.

public class MyClass {

    DatabaseCollaborator collaborator;

    public MyClass(DatabaseCollaborator collaborator) {
        this.collaborator = collaborator;
    }

    public void DoSomething() {
        //Some code which depends on the database tables being created
        collaborator.someMethod();
    }

    public void DoSomethingElse() {
        //Some other code which depends on the database tables being created
        collaborator.anotherMethod();
    }

}

public class DatabaseCollaborator {

    DatabaseConfig config;

    public DatabaseCollaborator(DatabaseConfig config) {
        this.config = config;
    }

    public void someMethod() {

    }

    public void anotherMethod() {

    }
}

public class DatabaseConfig {

    public DatabaseConfig() {
        // initialize
    }
}
Stuart
  • 3,226
  • 5
  • 24
  • 28
0

When I want a class whose instances must be initialized exactly once but I want to defer initialization until right before it's necessary (at which point the caller may fail to call an Initialize function, find it inconvenient to do so, or etc.), I do it similar to how you've started out with your code, but I make the initialization method private and name it something like "EnsureInitialized". It uses a flag to track and early exit if initialization has already been done, and all functions which depend on initialization already having happened just call that function as their first line (after argument-checking).

If I expect the caller to control when this instance's initialization is done, I make the method public, name it "Init", track whether it has been run with a flag, handle idempotence or max-run-once inside the Init method however is appropriate for that class, and all methods which depend on Init having already been run will call a different, private method named "AssertIsInitialized" which will throw an exception with text like "Must call init on {class name} instance before using this function".

My goal with these different patterns is to be unambiguous about each method's expectations and operation regarding initialization within the class instance lifecycle, and provide discoverability (of the design or code bugs using it) and automatic behavior (in the case of the self-initializing class in my first paragraph) wherever I think each is most appropriate to what the rest of the application is doing.

X Goodrich
  • 101
  • 1
  • 1