我有一些数据对象,例如Task
、Resource
等。
这些对象保存域数据,例如
public class Task{
private int Id;
private String taskName;
.......
//getters and setters here
//in addition they have a special method dynamically to get values i.e. There is a reason for this
public static String runGetter(Task task, String getter) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (Method method : task.getClass().getMethods()) {
if (method.getName().toLowerCase().equalsIgnoreCase(getter.toLowerCase())) {
if (method.getReturnType().isPrimitive()) {
StringBuilder sb = new StringBuilder();
sb.append(method.invoke(task));
return sb.toString();
}
if (method.invoke(task) != null) {
return method.invoke(task).toString();
}
}
}
return null;
}
}
}
现在我有一些方法可以获取这些对象并将它们写入流
例如
public class WriterUtil{
public void write(Task task, File outputFile){
//write the task object out.
}
public void write(资源资源,文件outputFile){//写出资源对象}
....
}
write方法调用另一个方法从对象中获取数据,如下所示。(是的,它可以提高效率,但这不是我问题的核心)
public class WriterUtil {
.....
public static String extractLine(Task task, LinkedHashMap<String, String> columns, String delimiter) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
StringBuilder sb = new StringBuilder();
Iterator<String> itr = columns.keySet().iterator();
while (itr.hasNext()) {
String getter = "get" + itr.next();
String value = Task.runGetter(task, getter);
if (value == null)
value = "";
sb.append(value + delimiter + " ");
}
return sb.toString().substring(0, sb.lastIndexOf(delimiter)).trim();
}
......
}
我的主要问题是,在上面描述的场景中,我发现自己为每个域对象编写了相同的代码,例如
public void write(任务任务,文件outputFile)public void write(资源资源,文件outputFile)//等等。。。。
我对extractLine重复同样的操作。正如你所看到的,我正在为每个域对象复制相同的代码。其中唯一变化的是实际的域对象。这些方法对每个域对象执行完全相同的操作。
我的问题是;如果我要重构这些方法,并分别编写一个方法应用于每个域对象,那么我的最佳选择是什么。
- 我应该让域对象实现一个接口吗?这似乎相当麻烦,我不确定这是正确的做法
- 我可以使用仿制药吗?我认为这可能是最好的做法,但我对如何生成(这是一个词吗?)我的域对象和这些常见方法的经验非常有限。有人能对我的上述代码进行重写吗?他们将如何将其修改为通用代码
- 我还有第三种选择吗
将反射代码移动到实用程序类型中,并将签名更改为:
public static String runGetter(Object bean, String getter)
方法内部根本没有使用Task
类型。
同样,这里需要Task
类型的唯一原因是其他调用需要它:
public static String extractLine(Object bean, Map<String, String> columns,
String delimiter)
您需要使用一个接口;泛型不能在这里使用(您可以在C++中使用模板,但不能在Java中使用)。
如果不希望对象实现接口,可以为每个域类创建辅助对象;那些助手对象将实现一个具有extractLine()
函数的接口:
class TaskExtractLine implements IExtractLine
{
public TaskExtractLine(Task task)
{
this.task = task;
}
public String extractLine(LinkedHashMap<String, String> columns, String delimiter)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
return WriterUtil.extractLine(task, columns, delimiter);
}
private Task task;
}
然后,您将得到这样的写函数:public void write(IExtractLine extractLineHelper, File outputFile)
,并将其调用为:write(new TaskExtractLine(task), outputFile)
。