返回并使用java

时间:2016-08-16 17:24:49

标签: java

不确定标题是否正确。我是Java的新手,试图弄清楚如何让一个班级使用不同的服务"。假设我有一个APIRequest类,这个类需要能够根据需要使用不同的API。例。我需要运送一个包,如果包低于32OZ我需要使用Endicia,否则我需要使用FedEx。我有2"服务"类FedexRequest和EndiciaRequest。我试图允许APIRequest类使用任何一个,具体取决于包的重量。我创建了一个名为APIService的类,它有一个名为getService的静态方法。它只是创建一个字符串名称的地图 - >请求类如此...

public class APIService {

private static Map<String, Object> services = new HashMap<>();

private static final Map<String, String> availableServices = new HashMap() {{
    put("fedex", "FedexRequest");
    put("endicia", "EndiciaRequest");
}};

public static Object getService(String type) {
    if(services.containsKey(type)) {
        return services.get(type);
    }
    return null;
}

static {
    for(Map.Entry<String, String> serv : availableServices.entrySet()) {
        try {
            Class<?> cls = Class.forName(serv.getValue());
            services.put(serv.getKey(), cls.newInstance());
        } catch(Exception e) {
            services.put(serv.getKey(), new Class[1]);
        }
    }
}

}

所以现在我可以调用APIService.getService(&#34; fedex&#34;);但是我很难在APIRequest课程中弄清楚如何使用它,因为我需要做类似......

this.service = (FedexRequest) APIService.getService("fedex");
//or
this.service = (EndiciaRequest) APIService.getService("endicia);

但这打破了等式的整个动态部分,如果我以后需要添加其他服务怎么办? 我尝试让FedexRequest和EndiciaRequest实现Request接口,然后使用

this.service = (Request) APIService.getService("fedex");

但是这给了我一个Java.lang.Class错误,说它无法转换为Request。我假设它是因为Request是一个接口,所以你不能在实现类上使用cls.newInstance()然后转换为接口。

我真的迷失了如何允许我的APIRequest类使用FedexRequest或EndiciaRequest,而没有专门使用类型转换,因此它可以是动态的,我们可以在以后添加服务而无需重新编码整个事情。我来自PHP,这将非常简单,因为您不必明确定义类型。任何帮助将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:3)

如果我是你,我会做以下事情:

这是Service接口的实现:

public interface Service {
    public void performAction();
    //other common functions...
}

对APIService类的一个小修改:

public class APIService {

private static Map<String, Service> services = new HashMap<>();

private static final Map<String, String> availableServices = new HashMap() {{
    put("fedex", "com.finity.shipping.api.fedexapi.FedexRequest");
    put("endicia", "com.finity.shipping.api.endiciaapi.EndiciaRequest");
}};

public static Service getService(String type) {
      return services.get(type);
}

static {
    for(Map.Entry<String, String> serv : availableServices.entrySet()) {
        try {
            Class<?> cls = Class.forName(serv.getValue());
            services.put(serv.getKey(), cls.newInstance());
        } catch(Exception e) {
            services.put(serv.getKey(), new Class[1]);
        }
    }
}

}

每当您需要将服务添加到您的应用程序时,只需实现服务界面:

public class FedexRequest implements Service {
    public void performAction() {
        //do something
    }
}

最后在您的班级中使用this.service

Service service;
...
this.service = APIService.getService("fedex");
this.service.performAction();

答案 1 :(得分:0)

Pooya解决方案很好。

我会添加一些东西。您使用一些字符串来表示可打字的内容:常量和类。使用反射来初始化一个工厂,你只处理一些字符串中的类(例如com.finity.shipping.api.fedexapi.FedexRequest)并且属于你自己的项目的类似乎是一个开销。
如果您的工厂不知道它将实例化哪些类,使用反射是有意义的。但似乎并非如此。

此外,使用枚举可以使FEDEX和ENDICIA保持不变。它允许输入它们并避免不良的suprpises。

我们希望您的工厂更简单。这是一个例子:

public class APIService {

public static enum TypeRequest{
  FEDEX, ENDICIA;
}

private static Map<String, Service> services = new HashMap<>();

  static {
      services.put(FEDEX, new FedexRequest());
      services.put(ENDICIA, new EndiciaRequest());       
  }

  public static Service getService(TypeRequest typeRequest) {
        return services.get(typeRequest);
  }

}