Reputation: 105
I've got two methods with the same list and types of arguments and almost the same body but each of them calls another function to fetch list of elements. To be more precise:
public void method1 (int a, int b) {
//body (the same in both of methods)
List<SomeObject> list = service.getListA(int c, int d);
//rest of the body (the same in both of methods)
}
public void method2 (int a, int b) {
//body (the same in both of methods)
List<SomeObject> list = service.getListB(int c, int d, int e);
//rest of the body (the same in both of methods)
}
What is the best approach to the problem avoiding code duplication in that case? I thought about Strategy pattern, but there is a problem with difference in argument list.
UPDATE:
public void method1 (int a, int b) {
//body (the same in both of methods)
int c = some_value;
List<SomeObject> list = service.getListA(a, b, c);
//rest of the body (the same in both of methods)
}
public void method2 (int a, int b) {
//body (the same in both of methods)
int c = some_value;
int d = another_value;
List<SomeObject> list = service.getListB(a, b, c, d);
//rest of the body (the same in both of methods)
}
So some variables are local and some are passed through arguments.
Upvotes: 5
Views: 241
Reputation: 4891
You could also use an enum:
public void method(int a, int b, Service service) {
// body
List<SomeObject> list = service.getList(myClass);
// rest
}
public enum Service {
METHOD_1 {
@Override
public List<SomeObject> getList(MyClass myClass) {}
},
METHOD_2 {
@Override
public List<SomeObject> getList(MyClass myClass) {}
};
public abstract List<SomeObject> getList(MyClass myClass);
}
public MyClass {
private final int c;
private final int d;
private final int e;
...
}
Essentially the same as @proskor except in a different form.
Upvotes: 0
Reputation: 147124
If the body parts depend upon one another so you can't do as @dicarlo2's answer:
private interface GetObjects {
List<SomeObject> get();
}
public void method1(int a, int b) {
impl(a, b, new GetObjects() { public List<SomeObject> get() {
return service.getListA(c, d);
}});
}
public void method2(int a, int b) {
impl(a, b, new GetObjects() { public List<SomeObject> get() {
return service.getListB(c, d, e);
}});
}
private void impl(int a, int b, GetObjects getObjects) {
//body (the same in both of methods)
List<SomeObject> list = getObjects.get();
//rest of the body (the same in both of methods)
}
You can use an enum in place of GetObjects
if you are concerned about the new
, but don't mind getting the order mixed up, missing out on outer this
and don't want to open this up (although it could implement an public interface).
Better syntax coming in Java SE 8, possibly. IIRC, along the lines of:
public void method1(int a, int b) {
impl(a, b, { -> service.getListA(c, d) });
}
Upvotes: -1
Reputation: 2875
public void method (int a, int b, List<SomeObject> theList) {
//body (the same in both of methods)
List<SomeObject> list = theList;
//rest of the body (the same in both of methods)
}
This to me removes ALL the code duplication, means the method NEVER has to be modified each time we want to operate on a list derived using a different method signature.
I believe you could further this if the type SomeObject is not known using generics i.e. (and I am not a java programmer so you will have to read the docs)
public void method (int a, int b, List<T> theList) {
//body (the same in both of methods)
List<T> list = theList;
//rest of the body (the same in both of methods)
}
Upvotes: 0
Reputation: 1412
Encapsulate the invocation of service.getListA or service.getListB in an ListSource class/interface, implement each version in concrete classes and pass a concrete instance as a third argument. This is basically the object-oriented version of the answer proposed by jlordo.
interface ListSource {
List<SomeObject> getList(int c, int d, int e);
}
class ListSourceA implements ListSource {
// constructor etc.
@Override
public getList(int c, int d, int e) {
return service.getListB(c, d);
}
}
class ListSourceB implements ListSource {
// constructor etc.
@Override
public getList(int c, int d, int e) {
return service.getListA(c, d, e);
}
}
public void method (int a, int b, ListSource source) {
//body (the same in both of methods)
List<SomeObject> list = source.getList(int c, int d, int e);
//rest of the body (the same in both of methods)
}
Upvotes: 3
Reputation: 37813
One way of avoiding code duplication in your case could be to introduce an extra parameter that is used to decide which method to retrieve the list is going to be used:
public void method (int a, int b, int method) {
//body (the same in both of methods)
List<SomeObject> list = null;
switch (method) {
case 1:
list = service.getListA(int c, int d);
break;
case 2:
list = service.getListB(int c, int d, int e);
break;
}
//rest of the body (the same in both of methods)
}
instead of using int method
as the additional parameter I would use an new enum
type and define a default
case in the switch
statement.
Upvotes: 4
Reputation: 4891
Factor them out into additional methods.
public void method1 (int a, int b) {
MyClass myClass = method3(a, b);
List<SomeObject> list = service.getListA(myClass.getC(), myClass.getD());
method4(list);
}
public void method2 (int a, int b) {
MyClass myClass = method3(a, b);
List<SomeObject> list = service.getListB(myClass.getC(), myClass.getD(), myClass.getE());
method4(list);
}
public MyClass {
private final int c;
private final int d;
private final int e;
...
}
public MyClass method3(int a, int b) {
// body
return new MyClass(c, d, e)
}
public void method4(List<SomeObject> list) {
// rest of body
}
Upvotes: 6