Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 根据对象类型调用方法_Java_Generics_Design Patterns - Fatal编程技术网

Java 根据对象类型调用方法

Java 根据对象类型调用方法,java,generics,design-patterns,Java,Generics,Design Patterns,我有两种助手方法: 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.getClas

我有两种助手方法:

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....
}

但是,这看起来并不优雅,并且很好奇是否有更好的方法。

您可以使用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设计模式,另一种方法是访问者模式,也称为双重分派


第三种方法是使用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....
}

重载操作方法。使用接收到的数据调用接受字符串的方法

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
}
然而,这似乎并不优雅,并且很好奇是否有更好的方法

对。这违反了开闭原则。类必须对扩展开放,但对修改关闭。当你说你需要一个泛型对象时,你也是正确的。以下是您可以做的:

创建加载程序界面

public interface Loader<T> {
   public String load(T t);
}
public class FileLoader implements Loader<File> {
     public String load(File f) { 
            //load from file 
     }    
}
公共接口加载程序{
公共字符串负载(T);
}
创建用于从文件加载的加载程序

public interface Loader<T> {
   public String load(T t);
}
public class FileLoader implements Loader<File> {
     public String load(File f) { 
            //load from file 
     }    
}
公共类文件加载器实现加载器{
公共字符串加载(文件f){
//从文件加载
}    
}
创建用于从Url加载的加载程序

public class UrlLoader implements Loader<Url> {
     public String load(URL r) { 
            //load from url 
     }    
}
公共类UrlLoader实现加载程序{
公共字符串加载(URL r){
//从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
    }

 }
类数据运算符{
装载机;
公共SomeClient(加载程序){
this.loader=loader;
}
公共无效操作(T输入源){
字符串数据=loader.load(inputSource);
//对数据进行操作
}
}
然后,客户端代码可以使用上述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")); 
DataOperator fileDataOperator=newdataoperator(newfileloader());
operate(新文件(“somefile.txt”);
DataOperator urlDataOperator=新的DataOperator(新的UrlLoader());
urlDataOperator.operate(新URL(“http://somesite.com")); 
您可能会认为这是一个解决简单问题的很多类。然而,这实际上符合众所周知的开闭式设计原则。请注意,您如何通过创建适当类的实例来控制用于加载数据的技术。另一个优势是,您可以通过创建一个接受用户输入并创建适当的具体子类的
工厂来决定在
运行时使用哪种技术。这是的简化版本


免责声明:上述代码示例没有经过编译错误测试,因为我在这台机器上没有
Java

我只是偶然发现了同样的问题,并找到了使用反射的不同方法:

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

当然,它带来了处理大量异常的负担。

您还可以解释一下如何在
operate()
方法中使用它吗?@CupawnTae我已经详细阐述了我在早期版本的回答中所说的“在现实世界中,客户端代码将取决于
加载程序
接口”的意思。我希望我的阐述澄清了我所提出的观点,这与OP提出的问题是一致的。@Codebender我已经阐述了我的回答,以扩展我之前所说的“在现实世界中,客户端代码将取决于加载程序接口”@CKing奇怪,我从未看到过这样的评论,在编辑历史记录中看不到它-它是否在后续编辑中汇总?不管怎样,我认为你的编辑成功了clearer@CupawnTae我只是查看了一下编辑历史记录,发现我之前的声明不见了。这很奇怪,因为我把这句话复制到了我的评论中。这违反了一个非常坚实(双关语)的设计原则,即开放-封闭原则。无论您使用的是
equals
还是
instanceof
,每次添加新的数据加载技术时都必须修改类。这违反了开闭原则。您的类必须针对每个新的输入源进行修改。不,您可以使用新的
操作(NewInputSourceType)
重载来扩展该类,但您无法在运行时决定使用这种方法从哪个源加载数据。重载方法在编译时解析。正确,此解决方案仅在编译时已知类型时有效是。OCP需要多态性替换。扩展类并添加新的
operate(NewInputSourceType)
重载不会让您以多态方式替换实现。如果从
文件
加载数据的客户端代码必须从
NewInputSourceType
开始加载数据,则必须将其更改为使用具有此方法的类的引用。如果一个类需要为每种新技术更改客户端代码,那么它遵守OCP有什么好处?OCP也应该扩展到客户端代码。请参阅我的答案中的
DataOperator
,对于任何输入都不会改变。我喜欢这样。它并没有真正减少coce的行数,但至少它限制了可以传递给Operation()的对象类型。如果您能修改您的答案,以显示一个带有反射的示例,我会很高兴的。对不起,没时间了。你为什么不把它计算出来并展示出来呢?