我正在实施日志管理系统,并希望日志类型可扩展。我们得到一个从JSON(来自Filebeat)解析的基础对象,例如:
class LogLine {
String message
Date timestamp
String type
String source
}
鉴于此LogLine对象,我希望能够创建不同的对象,这也将扩展此LogLine。
class SomeLog extends LogLine {
int myfield
String username
}
class SomeOtherLog extends LogLine {
Date startTime
Date endTime
String username
String transactionID
}
所以,在我目前的非理想实施中:
void parse(String s){
LogLine logLine = .....parseFromString(s)
if ( logline.type.equals('def') ){
SomeLog someLog = new SomeLog.Builder.build(logLine)
} else if ( logline.message.containts('abc') ){
SomeOtherLog someotherLog = new SomeOtherLog.Builder.build(logline)
}
}
但是,正如您可以想象的那样,子类中的构建器会复制超类LogLine对象,无论如何我可以在不复制值的情况下执行此操作,因为它们已经是子类了吗?是否有设计模式来实现这一目标?我不想依赖像BeanUtils.copyProperperties
答案 0 :(得分:1)
当您基于另一个创建新对象时,最好制作一个所有字段的副本。这是一种名为defensive copying的最佳做法。
由于您解析了一个字符串,因此不需要防御性副本。此外,我想您要解析输入字符串中的某些特定字段,例如myfield
的{{1}}和SomeLog
的{{1}}。您可以重新设置对象创建,如
startDate
如果您有许多LogLine的子类,那么您可能希望将创建逻辑移动到SomeOtherLog
,它管理有关将字符串解析为特定对象的所有内容。
答案 1 :(得分:1)
介绍用于创建LogLine
个对象的工厂界面。
public interface LogLineFactory {
public LogLine createLog(LogLine logLine);
}
并使用Map
进行查找。
private Map<String, LogLineFactory > logLineFactories = new HashMap<>();
{
logLineFactories .put("def", new SomeLogFactory());
logLineFactories .put("abc", new SomeOtherLogFactory());
}
然后,您可以使用map looup忽略if else分支。
LogLine logLine = parseFromString(s);
LogFactory logFactory = logLineFactories.get(logLine.type);
if(logFactory != null) {
LogLine wrappedLogLine = logFactory.createLog(logLine);
}
也许您需要更多信息来创建LogLine
,并且您必须更改界面。
public interface LogLineFactory {
public LogLine createLog(LogLine logLine, String s);
}
PS:使用Java 8,您可能希望使用方法引用。
logLineFactories.put("def", SomeLog::new);
logLineFactories.put("abc", SomeOtherLog::new);