Один метод, называемый несколькими методами

У меня есть класс, который выглядит так:

class A {
    public void method1(){
        iniCall();

        // Do something
        finalCall();
    }

    public void method2(){
        iniCall();

        // Do something different
        finalCall();
    } // ... more methods like this
}

Как я могу упростить эти iniCall и finalCall, чтобы не записывать их в каждую функцию (или несколько функций)?

Можно ли сделать что-то вроде call(method1), вызывая что-то вроде этого:

public void call(method){
    iniCall();
    method();
    finalCall();
}

В противном случае, что является хорошей альтернативой?

Ответы

Ответ 1

ИЗМЕНИТЬ Я вижу, что мой ответ поднимает некоторые вопросы.

Интерфейс Runnable должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком.

Таким образом, создание экземпляра этого интерфейса может привести к неопределенности и вопросам. Как было предложено в комментариях, вы можете написать свой собственный интерфейс и использовать его вместо этого. Это может быть примерно так:

public interface Method {
    public void run();
}

Ваш метод call изменится на примерно так:

public void call(Method method) {
    iniCall();
    method.run();
    finalCall();
}

И ваш вызов этого метода будет примерно таким:

call(new Method() {
    public void run() {
        // do your stuff here
    }
});

Я предлагаю вам использовать аналогичный дизайн или использовать шаблон шаблона, который, вероятно, потребует некоторого рефакторинга.

Ответ 2

Вы можете использовать выражение лямбда (или экземпляр анонимного класса, который реализует Runnable, если вы не используете Java 8):

public void call(Runnable method){
    iniCall();
    method.run();
    finalCall();
}

...

public void someMethod () {

    call (() -> {
                   // do something
                });
    ...
    call (() -> {
                   // do something different
                });

}

Ответ 3

Как и другие предложения (которые намного быстрее меня, но я всегда хочу предоставить пример...), я бы предложил передать экземпляр Runnable методу, который в общем случае вызывает iniCall(), выполняет Runnable, а затем вызывает finalCall().

Фактическая работа может быть передана в виде выделенных экземпляров Runnable, lambdas или ссылок на методы - последняя показана здесь:

public class RepeatedMethodContents
{
    public static void main(String[] args)
    {
        RepeatedMethodContents r = new RepeatedMethodContents();
        r.callWrapped(r::doSomething);
        r.callWrapped(r::doSomethingDifferent);
    }

    private void callWrapped(Runnable runnable)
    {
        iniCall();
        runnable.run();
        finalCall();
    }

    private void doSomething()
    {
        System.out.println("doSomething");
    }

    private void doSomethingDifferent()
    {
        System.out.println("doSomethingDifferent");
    }

    private void iniCall()
    {
        System.out.println("ini");
    }

    private void finalCall()
    {
        System.out.println("final");
    }

}

Выход по желанию:

ini
doSomething
final
ini
doSomethingDifferent
final

Кстати: я бы не решался использовать размышления вообще для таких вещей. Чаще всего есть более простой, более простой и менее подверженный ошибкам способ.

Ответ 4

В Java вы не можете передавать методы в качестве аргумента. Вы могли бы передать Runnable, хотя:

public void method1() {
    call(new Runnable() {
        @Override
        public void run() {
            //do something
        }
    });
}

public void method2() {
    call(new Runnable() {
        @Override
        public void run() {
            //do something different
        }
    });
}

public void call(Runnable runnable){
    iniCall();
    runnable.run();
    finalCall();
}

Однако мне действительно не нравится этот подход. Я думаю, вы можете применить шаблон дизайна шаблона.

Ответ 5

Я не уверен, что мне нравится использование Runnable в контексте, который другие использовали. Как правило, я думаю о Runnable как о чем-то, что будет выполняться в потоке, службе-исполнителе и т.д. И чтобы поддержать это, документация:

Интерфейс Runnable должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком.

Но сделать то, что делает то же самое с нуля, действительно просто и быстро. Мы можем создать абстрактный класс, который будет содержать необходимую структуру:

public abstract class AbstractClass
{
    private void iniCall() { ... } // Could also be abstract

    private void finalCall() { ... } // Could also be abstract

    public void doTheThing()
    {
        iniCall();
        foo();
        finalCall();
    }

    public abstract void foo();
}

Конечно, вам нужно придумать лучшие имена, но это отправная точка. Тогда у нас есть два варианта: создать анонимный класс, созданный путем расширения этого класса или создания нового конкретного класса. Вот пример использования анонимного класса:

AbstractClass a = new AbstractClass()
    {
        @Override
        public void foo()
        {
            // Place an implementation here.
            method(); // one example, based on the OP.
        }
    };
a.doTheThing();

И вот как бы вы сделали фактический класс:

public class ConcreteClass extends AbstractClass
{
    @Override
    public void foo()
    {
        // Place an implementation here.
    }
}
ConcreteClass c = new ConcreteClass();
c.doTheThing();

В основном я хотел подвести это, чтобы вы могли взглянуть на парадигму "анонимного класса", которая аналогична возможности передавать функции в качестве параметров. Другие языки имеют указатели на функции, делегаты и т.д. - вот что такое Java. Компилятор будет гарантировать, что ваш анонимный класс и конкретные классы будут иметь реализацию foo, или он не будет компилироваться, поэтому вы не можете просто "упс" и забыть реализовать.