What is a good way to refactor Java methods with common code and a method call in the middle?
-
Given a method like this: private void longMethod() { // Long series of code anotherMethod(); // Long series of code } What is a good way to support a need to make the anotherMethod() call replaceable? Hypothetically, if Java supports functions as objects, it would be like: private void longMethod(Function function) { // Long series of code function(); // Long series of code } What is a good alternative? The specific reason is to avoid copy-pasting long unit test code where only the call to anotherMethod changes between tests.
-
Answer:
This is a very common idiom in Java. You can't call function(), but you can call a method on it: interface Function { void call(); } Then longMethod calls function.call(); Note that call can't modify the variables in longMethod. This is actually a very good thing about Java; it makes all of the references local, making things easier to debug. If it's necessary to pass parameters to call(), you can do it as: interface Function { void call(Parameter param); } private void longMethod(Function function) { Parameter param; // Long series of code that creates param function(param); // Long series of code } I gather from your description that you were hoping to avoid having to parameterize Function, so that you could write your class like: class MyClass(){ static void foo(); static void bar(); static void baz(); } and call it like: test(MyClass.foo); test(MyClass.bar); test(MyClass.baz); without having to write the kind of interfaces like: class FooFunction implements Function() { void call() { MyClass.foo(); } } ... test(new FooFunction()); test(new BarFunction()); test(new BazFunction()); which is repetitive and boring. Actually, this is possible, with the Java reflection API: import java.lang.reflect.*; void test(String className, String methodName) throws Exception { // setup Class cls = Class.forName(className); Method method = cls.getDeclaredMethod(name); Method.invoke(null); // teardown } which is tested with test("MyClass", "foo"); I've left out a lot of ugly error handling, and if there are parameters you need to deal with that as well. There's even more to do with class loading, if you want to be very clear about where your class file comes from. The Java reflection API is documented at: http://download.oracle.com/javase/6/docs/api/java/lang/reflect/package-summary.html
Joshua Engel at Quora Visit the source
Other answers
Maybe what you're looking for is as simple as the pattern called Template Method? Wikipedia has it, but don't stare at this mess for too long: http://en.wikipedia.org/wiki/Template_method_pattern This might not suit your needs because it tends to involve subclassing (used for good: as an implementation technique), but in your case it could be something like this: abstract class AbstractFoo { private void longMethod() { // Long series of code, creates bar anotherMethod(bar); // Long series of code } protected void anotherMethod(Bar bar); } and: class DefaultFoo { protected void anotherMethod(Bar bar) { ... } }
Kjetil Valstadsve
The common practice is to use a functional interface as Joshua said: interface Function { void apply(); } void longMethod(Function f) { // Long series of code f.apply(); // Long series of code } The problem is there is too much boilerplate to use the interface: longMethod(new Function() { public void apply() { // Your code here. } }); This problem is addressed in the Lambda project that is finally going to be shipped with Java 8. You can simply pass lambdas as an instance of any functional interface: longMethod(() -> { // Your code here. }); For instance: longMethod(() -> System.out.println("Hello Lambda!"));
Soheil Hassas Yeganeh
I am not sure exactly what you want to do, but you could just create new class with the proper function method and then have private void longMethod(class functionObject) { // Long series of code functionObject.function(); // Long series of code } I should say, that I do not use java (I am a scala fan), so I am not sure this is correct syntax. (And as a scala plug, in scala functions are first-class objects, so you can do exactly what you want to do).
Marc Millstone
Your Function is a "longMethoud" closure. Joshua Engel gave you implementation tips. But the issues are: what is a basic functionality you closes by the closure? Try to name it specifically to its business responsibility. Besides all it depends how long the "longMethod" is. If it is a 11kLOC monster, consider Replace Method with Method Object Refactoring first. And then step by step divide it into smaller pieces.
MichaÅ Bartyzel
Related Q & A:
- What is a good way to structure mark-up generating code and avoid the example mess?Best solution by Code Review
- What is a good way to find business partners?Best solution by Quora
- What is a good way to advertise enexpensively for a small business? It is handyman work?Best solution by Yahoo! Answers
- What's a good way to let a girl know you are interested in her?Best solution by Yahoo! Answers
- What is a good way to break in a snowboard?Best solution by answers.yahoo.com
Just Added Q & A:
- How many active mobile subscribers are there in China?Best solution by Quora
- How to find the right vacation?Best solution by bookit.com
- How To Make Your Own Primer?Best solution by thekrazycouponlady.com
- How do you get the domain & range?Best solution by ChaCha
- How do you open pop up blockers?Best solution by Yahoo! Answers
For every problem there is a solution! Proved by Solucija.
-
Got an issue and looking for advice?
-
Ask Solucija to search every corner of the Web for help.
-
Get workable solutions and helpful tips in a moment.
Just ask Solucija about an issue you face and immediately get a list of ready solutions, answers and tips from other Internet users. We always provide the most suitable and complete answer to your question at the top, along with a few good alternatives below.