Template Method pattern for static classes
Asked Answered
M

3

6

I have a util class that perform some work. Obviously, it is closed for extension and all methods are static. For the sake of simplicity, the class looks like this:

public final class Util {
    private Util() { }

    public static void doWork() {
        // some work
        int variable = help();
        // some work uses variable
    }

    private static int help() {
        // some helper functionality
    }
}

The class has method doWork that performs a lot of calculations. By the way, method calls helper method help to obtain some result and rest of the code use the result returned by help method.

Now, in client code I want to reuse functionality of method doWork, but instead of calling help I want to call help2 method. The simplest solution just create method doWork2 with replacing help to help2.

It is very bad approach, because every change in doWork must be replicated in doWork2 either. This very similar to Template Method pattern, but due to fact that we don't have extension here, we can't apply it.

Best solution I came up with to add parameter to this method, but preserve all existing users of doWork:

public static void doWork() {
    doWorkWithParameter(true);
}

public static void doWorkWithParameter(boolean helpOrHelp2) {
    // some work
    int variable = helpOrHelp2 ? help() : help2();
    // some work uses variable
}

What are better design solutions can be applied to solve this problem? Is there a way to achieve flexibility like Template Pattern has, but in application to util classes.

Thanks in advance.

Mudstone answered 26/4, 2013 at 12:47 Comment(3)
Is there any reason you don't use method overload in your solution? public static void doWork() {...} public static void doWork(boolean param) {...}Twocycle
Or better still public static void doWork(int variable). Though I suspect the actual answer is that the confusion is due to the statics and that objects would provide a cleaner answer - difficult to tell with the abstract examples though.Names
What you are looking for is Strategy Pattern. Check Arnaldo's answer.Gush
S
5

My suggestion is inspired in the Command Pattern, where Util class is a Invoker and each doWork-help pairs are encapsulated using the Worker interface.

The Worker Inteface could be some like

public interface Worker {
    public void doWork();
    public int help();
}

The Util Class

public final class Util {
    private Util() { }

    public static void toWork(Worker worker){
        worker.doWork();
    }

}

The Concrete Worker (implementations of help and doWork)

public class ConcreteWorker implements Worker{

    @Override
    public void doWork() {
        // TODO Auto-generated method stub
            int variable = help();

    }

    @Override
    public int help() {
        // TODO Auto-generated method stub
        return 0;
    }

}

Another Worker

public class ConcreteWorker2 implements Worker{

    @Override
    public void doWork() {
        // TODO Auto-generated method stub
            int variable = help();

    }

    @Override
    public int help() {
        // TODO Auto-generated method stub
        return 1;
    }

}

And the Execution

Util.toWork(new ConcreteWorker());
Util.toWork(new ConcreteWorker2());
Scarletscarlett answered 26/4, 2013 at 12:59 Comment(2)
Instead of Worker interface you'd better make it as an abstract class with doWork() method. This is actually the same as what I suggest, but just with more code. You have four classes instead of one. I suppose enums are better replacement of static methods.Pontiff
Great! It looks like strategy pattern Collections.sort(lst, Comparator). How could I miss that?Mudstone
D
1

You could create 2 static object Help1 & Help2 implementing Help interface wich have a help() method and change your doWorkWithParameter method like this:

public static void doWorkWithParameter(Help h) {
    int variable = h.help();
}

It's closely related to your current solution. But I think it's a little more "Object Oriented".

Disconnect answered 26/4, 2013 at 12:56 Comment(0)
P
1

Not so long time ago I have made this:

public static enum Helper{
    OLD(){
        public int help(){
            return 0;
        }
    },

    NEW(){
        public int help(){
            return 1;
        }
    };

    public abstract int help();

    public void doWork() {
        int variable = help();
    }
}

public static Helper HELPER = Helper.NEW;

then we can call:

Constants.HELPER.doWork()

By switching HELPER constant values I can change behavior. or you can do:

Helper.OLD.doWork();
Helper.NEW.doWork();
Pontiff answered 26/4, 2013 at 12:56 Comment(1)
This is from Effective Java book - "Item 34: Emulate extensible enums with interfaces"Pontiff

© 2022 - 2024 — McMap. All rights reserved.