Reputation: 32757
I have a class that looks like this:
class A {
public void method1(){
iniCall();
// Do something
finalCall();
}
public void method2(){
iniCall();
// Do something different
finalCall();
} // ... more methods like this
}
How can I simplify this iniCall
and finalCall
so not to write them in every function (or several functions)?
Is it possible to do something like call(method1)
, being call something like this:
public void call(method){
iniCall();
method();
finalCall();
}
Otherwise, what is a good alternative?
Upvotes: 15
Views: 1474
Reputation: 1396
I'm not sure I like the use of Runnable
in the context others have used. Typically, I think of Runnable
as something that will run in a thread, executor service, etc. And to back that up is the documentation:
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.
But making something that does the same thing from scratch is really simple and quick. We can make an abstract class that will hold the structure you need:
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();
}
Of course you need to come up with better names, but that's the starting point. Then we have two options: instantiate an anonymous class built by extending this class, or creating a new concrete class. Here's the example of using an anonymous class:
AbstractClass a = new AbstractClass()
{
@Override
public void foo()
{
// Place an implementation here.
method(); // one example, based on the OP.
}
};
a.doTheThing();
And here's how you would do an actual class:
public class ConcreteClass extends AbstractClass
{
@Override
public void foo()
{
// Place an implementation here.
}
}
ConcreteClass c = new ConcreteClass();
c.doTheThing();
I mainly wanted to bring this up so that you could have a look at the 'anonymous class' paradigm, which is analogous to being able to pass functions as parameters. Other languages have pointers to functions, delegates, etc - well this is what Java has. The compiler will ensure that your anonymous class and concrete classes will have an implementation of foo
, or it won't compile, so it's not something you can just go 'oops' and forget to implement.
Upvotes: 0
Reputation: 14928
EDIT I see that my answer raises some questions.
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.
So creation of an instance of this interface may lead to uncertainty and questions. As suggested in comments, you may want to write your own interface and use it instead. It may be something like this:
public interface Method {
public void run();
}
Your call
method will change to something like this:
public void call(Method method) {
iniCall();
method.run();
finalCall();
}
And your call to this method will be something like this:
call(new Method() {
public void run() {
// do your stuff here
}
});
I suggest that you use similar design or consider using of a Template pattern which will probably require some refactoring.
Upvotes: 12
Reputation: 54611
Similar to the other suggestions (who are much quicker than me - but I always want to provide a running example...), I'd suggest passing a Runnable
instance to a method that generically calls iniCall()
, executes the Runnable
and then calls finalCall()
.
The actual work may be passed in as dedicated Runnable
instances, lambdas or method references - the latter is shown here:
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");
}
}
The output is, as desired:
ini
doSomething
final
ini
doSomethingDifferent
final
BTW: I'd be hesitant to use reflection in general for things like this. Most often, there is an easier, more straightforward and less error-prone way.
Upvotes: 5
Reputation: 26034
In Java you can't pass methods as argument. You could pass a Runnable
though:
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();
}
However, I really don't like this approach. I think you could apply template design patter.
Upvotes: 0
Reputation: 393771
You can use a lambda expression (or anonymous class instance that implements Runnable
if you don't use Java 8) :
public void call(Runnable method){
iniCall();
method.run();
finalCall();
}
...
public void someMethod () {
call (() -> {
// do something
});
...
call (() -> {
// do something different
});
}
Upvotes: 12