我正在编写一个程序来读取文件中的数据,该文件可能是多种格式之一(实际上是相同格式的不同版本),我正在使用反射为每种格式调用相应的函数。假设文件格式是在文件的第一个字节上指定的数字:
Class DataFile extends Model {
...
Blob file
...
public void parse() throws Exception{
InputStream is = file.get();
Class c = Class.forName("models.DataFile");
Method m = c.getMethod("parse_v"+is.read(), (Class []) null);
m.invoke(this, (Object []) null);
}
public void parse_v0() throws Exception{
...
}
public void parse_v1() throws Exception{
...
}
}
我的问题是,我是在滥用/滥用反思吗?我觉得我应该使用继承并使用自己的“解析”过程为每个文件类型创建一个不同的类,但在开始解析之前我不知道文件类型...然后我不能“低估”并且只使用像((DataFile_v1) this).parse()
这样的东西,所以我有点迷失。
感谢您的时间!
答案 0 :(得分:7)
这没有什么根本性的错误,但是更灵活和可扩展的方法来做同样的事情就是将版本信息用作Map
中的密钥,并且具有{{1}中的值是处理程序对象。然后任何代码都可以注册一个处理程序(处理程序都可以实现一个公共接口),你的读者代码可以只查找Map
中的处理程序并调用它。
请务必处理Map
不包含特定版本处理程序的情况!
答案 1 :(得分:2)
如果您使DataFile
接口定义parse
方法,并实现具有多个类(DataFile_v1
等)的接口,则调用代码不必知道选择了哪种实施方式。
DataFile dataFile = dataFileFactory.getForVersion(is.read());
dataFile.parse(file);
我认为从一般设计的角度来看,这是一种更好的方法。但是,在某些时候,您需要在版本号和DataFile实现之间创建某种映射。 (在这种情况下,我是在假想的dataFileFactory
中进行的。)你必须确定使用反射或其他方法选择实现是否更合适。
答案 2 :(得分:0)
我认为在这里使用反射是可以的。替代方案是使用继承或枚举(即Strategy pattern),以及从版本代码到正确策略的映射。一旦初始化了所有所需的映射,就可以从地图中获取正确的解析器对象并调用它。但是,设置此解决方案仍然需要大量的样板代码,这会降低其可读性。
答案 3 :(得分:0)
你在做什么也不错。如果你想在不同的类中使用不同的解析器,你不能像你说的那样向下转换,但你可以实例化一个新的解析器对象。因此,在您知道要解析的格式之前,您现有的类将是实际解析器前面的一个外观,它们不会被实例化。
答案 4 :(得分:0)
您可以使用集合,但使用反射也可以查找集合。如果您的映射没有改变,我会使用反射。
getClass().getMethod("parse_v"+is.read()).invoke(this);