考虑以下示例,其中类TextFile
,XmlFile
,HtmlFile
,ShellScriptFile
等等都是类SimpleFile
的子类。我正在编写一个类FileOperations
,它有一个方法可以根据类型搜索泛型文件的内容。
以下是代码示例:
public searchFile(SimpleFile targetFile, String searchStr) {
if (targetPage instanceof HtmlFile) {
// search html file
}
else if (targetPage instanceof TextFile) {
// search text file
}
else if (targetPage instanceof XmlFile) {
// search xml file
}
else if (targetPage instanceof ShellScriptFile) {
// search shell file
}
...
}
这种结构对我来说很难闻。我知道这是多态性的最佳案例。但我无法控制File
类或其子类。我无法写入它们。
还有另一种方法可以清理这个烂摊子吗?因为if-else结构会随着我添加对不同文件类型的支持而不断增加。
否则,如果我坚持使用这种结构,那么instanceof
是Java中最快的运算符吗?它对绩效有何影响?
对于上述情况,使用getClass()
或isAssignableFrom()
会更好吗?
感谢您的意见或建议!
答案 0 :(得分:3)
首先我要说你的例子似乎并不坏。它有点冗长,并且可以说不像将它们分成不同的方法那样具有凝聚力,但它对我来说看起来很正常。我认为更简洁的方法可能是使用重载。我不能说速度上的差异,但从维护和可扩展性的立场来看,它将来会更容易处理。
public void searchFile(SimpleFile targetFile , String searchStr) {
// SimpleFile generalized behavior.
if (targetPage instanceof HtmlFile) searchFile((HtmlFile)targetFile, searchStr);
else if (targetPage instanceof TextFile) searchFile((TextFile)targetFile, searchStr);
else if (targetPage instanceof XmlFile) searchFile((XmlFile)targetFile, searchStr);
else if (targetPage instanceof ShellScriptFile) searchFile((ShellScriptFile)targetFile, searchStr);
else System.out.println("Subtype not recognised");
}
public void searchFile(HtmlFile targetFile , String searchStr) {
// HtmlFile specific behavior
}
public void searchFile(TextFile targetFile , String searchStr) {
// TextFile specific behavior
}
public void searchFile(XmlFile targetFile , String searchStr) {
// XmlFile specific behavior
}
public void searchFile(ShellScriptFile targetFile , String searchStr) {
// ShellScript specific behavior
}
如果是SimpleFile
的新子类,它将默认为该方法的SimpleFile
版本。如果在编译时未知类型(如注释中所示),则可以使用最通用的searchFile()
方法来相应地检查和重新分发对象。
修改:关于多次使用instanceof
,consensus appears to be that it's irrelevant, and that the use of modern instanceof is pretty fast anyway的性能影响的说明。
答案 1 :(得分:1)
如果您可以修改File
及其子类,则可以尝试使用访问者模式。由于您不能,我建议您将类型测试开关语句合并到一个方法中,这样您只需要修改一个开关。
public Enum FileHandler {
HTML(){
public search(File file, String searchstr){ /* ... */}
public prettyPrint(File file){ /* ... */}
},
XML(){ /* ... */};
// ... end list of enum implementations
public static FileHander get(File file){
// Put your master switch statement here
if (targetPage instanceof HtmlFile) {
return HTML;
}
else if (targetPage instanceof XmlFile) {
return XML;
}
// ...
}
}
使用enum类的代码看起来像这样,避免了可怕的switch语句:
public searchFile(SimpleFile targetFile, String searchStr) {
FileHandler.get(targetFile).search(targetFile, searchStr);
}
答案 2 :(得分:0)
您可以使用interpreter-design-pattern或责任链设计模式来解决此问题。这些模式似乎只是解决这个问题的完美方法。
解释器设计模式的示例,如果需要责任链设计模式的示例,请发表评论
客户端:
public Integer wordCountOnPage (Page samplePage)
{
ArrayList list = new ArrayList<Page>();
list.add(new XmlPage());
list.add(new HtmlPage());
list.add(new JsonPage());
for (int index = 0 ; index < list.size(); index ++)
{
Page eachPage = (Page) list.get(index);
if (eachPage.intercept(samplePage)){
Integer i = eachPage.wordCountOnPage(samplePage);
}
}
return 1;
}
public class XmlPage implements Page {
@Override
public Boolean intercept(Page page) {
// TODO Auto-generated method stub
return page instanceof XmlPage;
}
@Override
public Integer wordCountOnPage(Page page) {
// TODO Auto-generated method stub
return null;
}
}
public interface Page {
Boolean intercept(Page page);
Integer wordCountOnPage(Page page);
}
答案 3 :(得分:0)
我的方法是使用一个执行业务逻辑的方法创建一个接口FileSearcher
。为每种文件类型创建此接口的一个实现。然后,创建一个注册表,将SimpleFile
的子类映射到它们对应的FileSearcher
实现。在您的搜索文件方法中,不是进行instanceof
检查,而是在运行时查找匹配的FileSeacher
实现并委托给它。
使用此实现时,如果存在HtmlFile
等子类,则可能会遇到麻烦,因为您必须将HtmlFileSearcher
映射到HtmlFile
的所有子类。在这种情况下,将另一个方法添加到FileSearcher
,名为canHandle(Class<SimpleFile> runtimeClass)
,允许FileSearcher
实现发出他们理解的文件类的信号。在注册表中,不是在地图中查找,而是遍历所有已注册的FileSearchers
。