2016-08-16 3 views
1

제목이이 정의를 수행하는지 확실하지 않습니다. 저는 Java에 익숙하지 않고 한 클래스에서 다른 "서비스"를 사용하는 방법을 알아 내려고 노력하고 있습니다. 내가 APIRequest 클래스를 가지고 있다고 가정하면,이 클래스는 필요한 것에 따라 다른 API를 사용할 수 있어야합니다. 예. 패키지를 발송해야합니다. 패키지가 32OZ 이하인 경우 Endicia를 사용해야하고, 그렇지 않으면 FedEx를 사용해야합니다. FedexRequest와 EndiciaRequest라는 2 가지 "서비스"클래스가 있습니다. APIRequest 클래스가 패키지의 가중치에 따라 둘 중 하나를 사용하도록 허용하려고합니다. getService라는 정적 메서드가있는 APIService라는 클래스를 만들었습니다. ; 그래서 지금은 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]); 
     } 
    } 
} 

}

- 그냥 문자열 이름의 맵을 작성 그러나 내가 ... 내가 좋아하는 뭔가를 할 필요가 있기 때문에, 내 APIRequest 클래스에서 그것을 사용하는 방법을 알아 내려고

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

을 정말 힘든 시간을 보내고 있어요하지만 그 방정식의 전체 동적 부분을 나누기, 나중에 다른 서비스를 추가해야하는 경우 어떻게해야합니까? 나는 FedexRequest과 EndiciaRequest 모두 다음, 요청 인터페이스를 구현

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

를 사용 가진 시도했지만 그게 요청에 캐스트 할 수없는 말을 나에게 java.lang.Class의 오류를 제공합니다. 요청은 인터페이스이므로 구현 클래스에서 cls.newInstance()를 사용할 수 없으므로 인터페이스로 캐스팅됩니다.

필자는 APIRequest 클래스가 특별히 유형 캐스팅을 사용하지 않고 FedexRequest 또는 EndiciaRequest를 사용하여 동적 일 수 있고 모든 것을 다시 코딩하지 않고 나중에 서비스를 추가 할 수 있도록하는 방법에 대해 정말로 분실했습니다. 필자는 명시 적으로 타입을 정의 할 필요가 없기 때문에 PHP에서이 것이 매우 간단합니다. 어떤 도움이라도 대단히 감사하겠습니다. 고맙습니다.

+0

https://en.wikipedia.org/wiki/Strategy_pattern – Nahum

+1

이 당신의 접근 방식에 여러 가지 문제가 있지만 가장 즉각적인 당신이 상위 유형을 정의해야한다는 것 같습니다 (예를 들어,' interface ApiService')를 구현 유형 (class FedexService는 ApiService를 구현합니다. – chrylis

+0

클래스를 키로 사용하고 getService에서 일부 generic을 사용해야합니다. public static T getService (클래스 type) {'또는 이와 비슷한 것 –

답변

3

내가 당신이라면 나는 할 것이다 다음

이 서비스 인터페이스의 구현입니다 :

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]); 
     } 
    } 
} 

} 

때마다 애플리케이션에 추가 할 서비스가 필요합니다. 서비스 인터페이스를 구현하기 만하면됩니다.

012 당신이 this.service를 사용하는 클래스의

그리고 마지막으로는 :

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

@ChiefTwoPencils는 메모에 감사드립니다. 나는 – Pooya

+0

Perfect를 편집했습니다. 나는 "요청"인터페이스를 구현하는 2 개의 페더럴과 endicia 클래스를 가졌지 만, APIService에 올바른 타입 선언이 없기 때문에 Request 대신 Object를 사용했습니다. 이것은 나를 위해 완벽하게 일했습니다. 정말 고맙습니다. –

+0

Google Guice와 MapBinder/MultiBinding 같은 DI 프레임 워크가 여기에 적합할까요? https://github.com/google/guice/wiki/Multibindings – faizan

0

Pooya 솔루션은 좋다.

내가 추가하겠습니다. 일부 문자열을 사용하여 상수 및 클래스와 같이 입력 가능한 항목을 나타냅니다. 리플렉션을 사용하여 일부 문자열 (예 : com.finity.shipping.api.fedexapi.FedexRequest)에서 하드로 작성된 클래스 만 처리하고 사용자 자신의 프로젝트에 속하는 팩토리를 초기화하는 작업은 오버 헤드로 보입니다.
팩토리가 인스턴스화 할 클래스를 모르는 경우 리플렉션을 사용하면 의미가 있습니다. 그러나 그것은 사실이 아닌 것 같습니다.

게다가 FEDEX와 ENDICIA는 enum을 사용하여 상수 일 수 있습니다.그것을 입력하고 나쁜 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); 
    } 

} 
관련 문제