繁体   English   中英

根据对象类型调用方法

[英]Call a method based on the object type

我有两个辅助方法:

public String load(URL url) {...}
public String load(File file) {...}

我想有一个方法,根据它接收的对象类型调用适当的帮助器方法:

public void operate(Object object) {...}

我知道有一种令人费解的方式,它是:

public void operate(Object object) {
    String data = null;
    if (object.getClass().equals(File.class)) {
        data = load((File) object);
    }
    if (object.getClass().equals(URL.class)) {
        data = load((URL) object);
    }
    // operate on the data....
}

然而,这似乎并不优雅,如果有更好的方式,我很好奇。

然而,这似乎并不优雅,如果有更好的方法,那就很好奇。

那就对了。 这违反了开放原则。 类必须对扩展开放,但不能修改。 当你说你需要一个通用的对象时,你也是对的。 这是你可以做的:

创建Loader接口

public interface Loader<T> {
   public String load(T t);
}

创建一个从File加载的加载器

public class FileLoader implements Loader<File> {
     public String load(File f) { 
            //load from file 
     }    
}

创建一个从Url加载的加载器

public class UrlLoader implements Loader<Url> {
     public String load(URL r) { 
            //load from url 
     }    
}

创建一个对数据进行操作的类

 class DataOperator<T> {
    Loader<T> loader;
    public SomeClient(Loader<T> loader) {
       this.loader = loader;
    }

    public void operate(T inputSource) {
       String data = loader.load(inputSource);
       //operate on the data
    }

 }

然后客户端代码可以使用上面的API,如下所示:

DataOperator<File> fileDataOperator = new DataOperator<>(new FileLoader());
fileDataOperator.operate(new File("somefile.txt"));

DataOperator<URL> urlDataOperator = new DataOperator<>(new UrlLoader());
urlDataOperator.operate(new URL("http://somesite.com")); 

你可能会认为这是解决一个简单问题的很多类。 然而,这实际上与众所周知的开放式封闭设计原则相符。 请注意如何通过创建适当类的实例来控制用于加载数据的技术。 您获得的另一个优点是,您可以通过创建一个获取用户输入并创建适当的具体子类的Factory来决定在runtime使用哪种技术。 这是策略模式的简化版本。

免责声明:上面提供的代码示例尚未针对编译错误进行测试,因为我在此计算机上没有Java

您可以使用instanceof并检查它,然后转换对象并调用方法:

if (obj instanceof File) {
   ((File) obj).method();
}
else if (obj instanceof URL) {
   ((URL) obj).method();
}

或反之如下:

if (obj instanceof File) {
 load((File) obj)
}
else if (obj instanceof URL) {
   load((URL) obj)
}

你是对的:铸造是必要的但不优雅。

如果您喜欢GoF Design Patterns,另一种方法是访问者模式又称双重调度。

第三种方法是使用Java反射。

一个稍微不那么令人费解的方式是instanceof ,如

if (object instanceof File)) {
    data = load((File) object);
}

但是,大多数情况下,使用instanceof表示您正在尝试实现的目标有更好的结构,例如

public void operate(File file) {
    operate(load(file));
}

public void operate(URL url) {
    operate(load(url));
}

public void operate(String data) {
    // operate on the data....
}

也过载了操作方法。 使用您收到的数据来调用接受String的方法。

public static void operate(URL url) {
    String data = load(url);
    doOperations(data);
}

public static void operate(File file) {
    String data = load(file);
    doOperations(data);
}

private static void doOperations(String data) {
    //TODO Do something with data
}

我偶然发现了同样的问题,并发现了一种使用Reflection的不同方法:

public void operate(Object object) {
    Method method = this.getClass().getDeclaredMethod("load", object.getClass());
    String data = (String) method.invoke(this, object);
    // [...]
}

当然,它带来了处理相当多的例外的负担。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM