Один метод, называемый несколькими методами
У меня есть класс, который выглядит так:
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
, или он не будет компилироваться, поэтому вы не можете просто "упс" и забыть реализовать.