Всегда раньше считал что дублирование кода -- это плохо (без всяких исключений).
Но оказывается есть случаи когда дублирование кода -- наиболее правильно решение.
Случай, благодаря которому я пришел к такому вывод -- маппинг данных.
Мне нужно было данные из базы Amazon SimpleDB проецировать (ну или мапить) на объекты высокоуровневого языка. Т.е. нужно было сохранять объекты в базу и воссоздавать объекты из данных БД.
Первое решение, которое пришло в голову -- использовать рефлексию. Кстати, даже есть готовые библиотеки работающие по этому принципу.
Но при разборе больших массивов данных -- рефлексия работает медленно.
Наиболее подходящим решением оказалась
КОДОГЕНЕРАЦИЯ. Причем это решение оказалось на порядок
проще рефексии.
В итоге получился такой код для авто-генерации:
final String lineSeparator = System.getProperty("line.separator");
Field[] fields = entityClass.getDeclaredFields();
StringBuilder stringBuilder = new StringBuilder();
// object->item
stringBuilder.append("protected RequestAttributeContainer buildRequestAttributeContainer()" + lineSeparator);
stringBuilder.append("{" + lineSeparator);
stringBuilder.append("RequestAttributeContainer requestAttributeContainer = new RequestAttributeContainer();" +
lineSeparator);
{
for (Field field : fields)
{
String fieldName = field.getName();
stringBuilder.append("requestAttributeContainer.addAttribute(\"" + fieldName + "\", " + fieldName +
");" + lineSeparator);
}
}
stringBuilder.append("return requestAttributeContainer;" + lineSeparator);
stringBuilder.append("}" + lineSeparator);
// item->object
stringBuilder.append(lineSeparator);
stringBuilder.append("protected " + entityClass.getSimpleName() +
"(ResponseAttributeContainer responseAttributeContainer)" + lineSeparator);
stringBuilder.append("{" + lineSeparator);
{
for (Field field : fields)
{
String fieldName = field.getName();
Class<?> fieldType = field.getType();
String suffix;
if (fieldType.equals(boolean.class))
{
suffix = "AsBoolean";
}
else if (fieldType.equals(int.class))
{
suffix = "AsInteger";
}
else if (fieldType.equals(long.class))
{
suffix = "AsLong";
}
else if (fieldType.equals(String.class))
{
suffix = "";
}
else
{
suffix = "As" + fieldType.getSimpleName();
}
stringBuilder.append(fieldName + " = responseAttributeContainer.tryGetAttributeValue" + suffix + "(\"" +
fieldName + "\");" + lineSeparator);
}
}
stringBuilder.append("}" + lineSeparator);
System.out.print(stringBuilder.toString());
Он создает 2 метода: buildRequestAttributeContainer и конструктор класса. В этих методах происходит проекция объекта (кое-какая логика вынесена в общие классы).
Как видите -- получилось очень и очень просто, на порядок проще использования рефлексии, а скорость заметно возросла.
Какие недостатки у подобного решения?
Здравствуйте, 0K, Вы писали:
0K>Наиболее подходящим решением оказалась КОДОГЕНЕРАЦИЯ. Причем это решение оказалось на порядок проще рефексии.
Кодогенерация — это не дублирование кода