1

Javaでenumを拡張できないことは知っていますが、以下のエレガントなソリューションを見つけようとしています

地域全体のさまざまな Web サービスの http エンドポイントを含む列挙型 (またはクラス) をモデル化しようとしています。たとえば、サービス A と B があり、それぞれが米国、EU、JP、または CN に 4 つの地域固有のエンドポイントを持つとします。(これは基本的に、私が書いているいくつかの個別のデバッグコード用です。本番環境では、エンドポイントは構成から選択されます)

私はこのようなことをしたいと思っていました(Javaコードに準拠していません)。

public enum IEndPoint {
    NA_END_POINT,
    EU_END_POINT,
    JP_END_POINT,
    CN_END_POINT,
}

public enum ServiceAEndPoint extends IEndPoint {
   NA_END_POINT("http://A.com/");
   EU_END_POINT("http://A-eu.com/");
   JP_END_POINT("http://A-jp.com/");
   CN_END_POINT("http://A-cn.com/");
}

各地域のメソッドを持つインターフェイスを使用してこれを行うことができますが、私の意見では、列挙型の方法がより表現力豊かです。これをモデル化できるより良い方法はありますか? 私が探しているのは、継承関係をモデル化し、列挙の表現力を持つより良い方法があるかどうかです。

ServiceAEndPoint.NA_END_POINT

serviceAEndPoint.getNAEndPoint()
4

6 に答える 6

3

ServiceBEndPoint列挙型(および同様のもの)も必要になると思います。その場合、あなたのモデルはあまり意味がないと思います。

IEndPoint実際には、サービスが実行されている可能性のある環境/地域の種類の列挙です。サービス自体の列挙ではありません。個々のサービス (A、B など) は、地域ごとに異なるアドレスを持ちます。

したがって、私はIEndPoint列挙型だけに固執し、サービス固有のコードには、特定のエンドポイントのアドレスを提供するルックアップ マップがあります。このようなもの:

public enum IEndPoint {
    NA_END_POINT,
    EU_END_POINT,
    JP_END_POINT,
    CN_END_POINT,
}

public class ServiceABroker {
   private static final Map<IEndPoint, String> addressesByEndPoint;
   static {
      addressesByEndPoint = new EnumMap<>();
      addressesByEndPoint.put(NA_END_POINT, "http://A.com/");
      addressesByEndPoint.put(EU_END_POINT, "http://A-eu.com/");
      addressesByEndPoint.put(JP_END_POINT, "http://A-jp.com/");
      addressesByEndPoint.put(CN_END_POINT, "http://A-cn.com/");
   }

   public String getAddressForEndPoint(IEndPoint ep) {
       return addressesByEndPoint.get(ep);
   }
}
于 2013-10-30T14:55:43.323 に答える
1

あなたの質問を理解しているかどうかはわかりませんが、たとえば、次のようなことを行うことができる列挙型にメソッドを追加できます。

public enum ServiceAEndPoint{
    NA_END_POINT("http://A.com/");
    EU_END_POINT("http://A-eu.com/");
    JP_END_POINT("http://A-jp.com/");
    CN_END_POINT("http://A-cn.com/");

    private final String url;

    private EndPoint(String url){
        this.url=url;
    }

    public String getURL(){
        return url;
    }
}
于 2013-10-30T14:56:47.983 に答える
1

これらが静的な最終定数である場合は、それらをインターフェイスに入れます。インターフェイスに のような名前を付けますIServiceAEndPointKeys。ここで、キーの部分は規則です。

ここでは、enumがより適切で便利であると考えています。

  • 例 1: ファイルの種類。jpgpdfなどを含む列挙型。
  • 例 2: 列の定義。3 列のテーブルがある場合、 IDNameDescription (たとえば) を宣言する列挙型を記述し、それぞれに列ヘッダー name列幅列 IDなどのパラメーターがあります。
于 2013-10-30T14:54:57.813 に答える
1

次のようなことを検討してください。

public abstract class EndpointFactory {
    public abstract String getNAEndPoint();
    public abstract String getEUEndPoint();
}

public class ServiceAEndpointFactory extends EndpointFactory {
    public static final String NA_END_POINT = "http://A.com/";
    public static final String EU_END_POINT = "http://A-eu.com/";

    public String getNAEndPoint() {
       return ServiceAEndpointFactory.NA_END_POINT;
    }

    public String getEUEndPoint() {
       return ServiceAEndpointFactory.EU_END_POINT;
    }
}

public class ServiceBEndpointFactory extends EndpointFactory {
    public static final String NA_END_POINT = "http://B.com/";
    public static final String EU_END_POINT = "http://B-eu.com/";

    public String getNAEndPoint() {
       return ServiceAEndpointFactory.NA_END_POINT;
    }

    public String getEUEndPoint() {
       return ServiceAEndpointFactory.EU_END_POINT;
    }
}

次に、次のように文字列を直接参照できます。

ServiceAEndpointFactory.NA_END_POINT;

または、実行するまでサービスのタイプがわからない場合は、ベース オブジェクトを使用できます。

EndpointFactory ef1 = new ServiceAEndpointFactory();
String ep = ef1.getNAEndPoint();

これの欠点は、各サブクラスで get*Endpoint() 関数を再定義することです。静的な最終変数を基本クラスで静的にならないように移動し、ゲッター/セッターを基本クラスに1回だけ配置することで、これを排除できます。ただし、その欠点は、オブジェクトをインスタンス化せずに値を参照できないことです (これは、本質的に ENUM で価値があると思われるものをエミュレートします)。

于 2013-10-30T14:55:57.080 に答える
1

列挙型をそのような方法で拡張することはできません。これは主に、列挙型をサブクラス化できないか、従わなければならない制約を課すことができないためです。

代わりに、次のようにインターフェイスを活用します

public interface IEndPoint;

public enum DefaultEndPoints implements IEndPoint {
    NA_END_POINT,
    EU_END_POINT,
    JP_END_POINT,
    CN_END_POINT,
}

public enum DefaultServiceEndPoints implements IEndPoint {
   NA_END_POINT("http://A.com/");
   EU_END_POINT("http://A-eu.com/");
   JP_END_POINT("http://A-jp.com/");
   CN_END_POINT("http://A-cn.com/");
}

public void doSomething(IEndPoint endpoint) {
  ...
}

希望する方法でサブクラス化できない理由は、enum が via.equals(object)と viaの両方で等しいという契約に関連してい==ます。サブクラス化できるとしたら、これは理にかなっていますか?

if ( (DefaultEndPoints)JP_END_POINT == (DefaultServiceEndPoints)JP_END_POINT) {

}

あなたが「はい」と言うなら、私はこれができると期待しています

DefaultEndPoint someEndpoint = DefaultServiceEndPoints.JP_END_POINT;

一方の列挙型宣言の列挙型エントリがもう一方の列挙型宣言にあるという保証はないため、エラーの可能性があります。

それは違うのでしょうか?おそらくそうではありませんが、それを変更すると、徹底的に検討する必要がある多くの複雑さが確実に導入されます (または、Java の強力な静的型チェックを回避する道が開かれます)。

于 2013-10-30T15:05:09.830 に答える
0

このようなパターンはどのようにあなたにアピールしますか? デバッグ セットとリリース セットにインターフェイスを実装し、インターフェイスを実装しenumます。interfaceリリース セットは、名前からプロパティ名を派生させることができますenum。これはすばらしいことです。

public interface HasURL {
  public String getURL();
}

public enum DebugEndPoints implements HasURL {
  NA,
  EU,
  JP,
  CN;

  @Override
  public String getURL() {
    // Force debug to go to the same one always.
    return "http://Debug.com/";
  }
}

public enum NormalEndPoints implements HasURL {
  NA,
  EU,
  JP,
  CN;
  final String url;

  NormalEndPoints () {
    // Grab the configured property connected to my name.
    this.url = getProperty(this.name());
  }
  @Override
  public String getURL() {
    return url;
  }
}
于 2013-10-30T15:06:44.677 に答える