2016-08-16 3 views
1

タイトルがこの正義を行うかどうかわからない。私はJavaにはまったく新しく、単一のクラスに異なる "サービス"を使用させる方法を理解しようとしています。私がAPIRequestクラスを持っているとしましょう。このクラスは、必要なものに応じて異なるAPIを使用できる必要があります。例。パッケージを発送する必要があります。パッケージが32OZ未満の場合はEndiciaを使用する必要があります。そうでなければFedExを使用する必要があります。私は2つの "サービス"クラスFedexRequestとEndiciaRequestを持っています。私は、APIRequestクラスがパッケージの重量に応じてどちらかを使用できるようにしようとしています。 getServiceという静的メソッドを持つAPIServiceというクラスを作成しました。それは単なる文字列名のマップを作成します。 - >要求クラスのようなので...返され、javaで別のクラスを使用する

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(「フェデックス」)を呼び出すことができます。しかし、私は...私のような何かをする必要がありますので、私のAPIRequestクラスでそれを使用する方法を把握しようとしている

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

を本当に苦労していますが、それは式の全体の動的な部分を壊し、後で別のサービスを追加する必要がある場合はどうすればよいですか? 私は

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

を使用し、その後、FedexRequestとEndiciaRequest両方がリクエストインターフェイスを実装した試みたが、それが要求にキャストすることはできないと言ってくれのjava.lang.Classエラーが発生します。これは、Requestがインタフェースであるため、実装クラスでcls.newInstance()を使用してインタフェースにキャストできないためです。

私は実際にAPEXequestクラスがFedexRequestまたはEndiciaRequestを使用できるようにする方法を失っています。これは型キャストを特に使用することなく、動的になり、後でサービス全体を記録せずにサービスを追加することができます。私はPHPから来ていますが、明示的に型を定​​義する必要がないので、これは非常に簡単です。どんな助けでも大歓迎です。ありがとうございました。

+0

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

+1

あり、あなたのアプローチにはいくつかの問題がありますが、最も直接的なあなたはスーパータイプを定義する必要があることであると思われる(例えば、 '全てのあなたの実装タイプ( 'class FedexService implement ApiService')のためのインタフェースApiService')を提供します。 – chrylis

+0

クラスをキーとして使用し、getServiceでいくつかのジェネリックを使用する必要があります。 'public static T getService(クラスタイプ){'またはそのようなもの –

答えて

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

パーフェクトを編集しました。私は2つのfedexクラスとendiciaクラスに "Request"インターフェイスを実装していましたが、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); 
    } 

} 
関連する問題