Шаблон метода шаблона для статических классов

У меня есть служебный класс, который выполняет некоторую работу. Очевидно, он закрыт для расширения и все методы статичны. Для простоты класс выглядит так:

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
    }
}

В классе есть метод doWork, который выполняет множество вычислений. Кстати, метод вызывает вспомогательный метод help для получения некоторого результата, а остальная часть кода использует результат, возвращенный методом help.

Теперь в клиентском коде я хочу повторно использовать функциональность метода doWork, но вместо вызова help я хочу вызвать метод help2. Самое простое решение - просто создать метод doWork2 с заменой help на help2.

Это очень плохой подход, потому что каждое изменение в doWork должно быть реплицировано и в doWork2. Это очень похоже на шаблон Template Method, но из-за того, что у нас здесь нет расширения, мы не можем его применить.

Лучшее решение, которое я придумал, - добавить параметр к этому методу, но сохранить всех существующих пользователей doWork:

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

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

Какие лучшие дизайнерские решения можно применить для решения этой проблемы? Есть ли способ добиться такой гибкости, как у Template Pattern, но в применении к классам.

Заранее спасибо.


person mishadoff    schedule 26.04.2013    source источник
comment
Есть ли причина, по которой вы не используете перегрузку метода в своем решении? public static void doWork() {...} public static void doWork(boolean param) {...}   -  person Crazenezz    schedule 26.04.2013
comment
Или еще лучше public static void doWork(int variable). Хотя я подозреваю, что реальный ответ заключается в том, что путаница вызвана статикой и что объекты дадут более четкий ответ - хотя трудно сказать с абстрактными примерами.   -  person Nick Holt    schedule 26.04.2013
comment
То, что вы ищете, - это шаблон стратегии. Проверьте ответ Арнальдо.   -  person Mehmet Ataş    schedule 26.04.2013


Ответы (3)


Мое предложение основано на шаблоне команд, где класс Util является Invoker, а каждая пара doWork-help инкапсулируются с использованием интерфейса Worker.

Рабочий интерфейс может быть чем-то вроде

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

Класс Util

public final class Util {
    private Util() { }

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

}

Конкретный рабочий (реализации help и 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;
    }

}

Другой рабочий

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;
    }

}

И казнь

Util.toWork(new ConcreteWorker());
Util.toWork(new ConcreteWorker2());
person Arnaldo Ignacio Gaspar Véjar    schedule 26.04.2013
comment
Вместо интерфейса Worker лучше сделать его абстрактным классом с методом doWork (). На самом деле это то же самое, что я предлагаю, но только с большим количеством кода. У вас четыре класса вместо одного. Я полагаю, что перечисления - лучшая замена статическим методам. - person Mikhail; 26.04.2013
comment
Большой! Похоже на шаблон стратегии Collections.sort(lst, Comparator). Как я мог это пропустить? - person mishadoff; 26.04.2013

Вы можете создать 2 статических объекта Help1 & Help2, реализующих Help интерфейс, у которых есть метод help (), и изменить свой метод doWorkWithParameter следующим образом:

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

Это тесно связано с вашим текущим решением. Но я думаю, что это немного больше «объектно-ориентировано».

person DeadlyJesus    schedule 26.04.2013

Не так давно я сделал вот что:

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;

тогда мы можем позвонить:

Constants.HELPER.doWork()

Переключая постоянные значения HELPER, я могу изменить поведение. или вы можете сделать:

Helper.OLD.doWork();
Helper.NEW.doWork();
person Mikhail    schedule 26.04.2013
comment
Это из книги «Эффективная Java» - Правило 34: Эмуляция расширяемых перечислений с интерфейсами. - person Mikhail; 27.04.2013