21

私はしばしば次のようなことをしたいと思っています:

class Foo{
public static abstract String getParam();
}

Foo のサブクラスにパラメーターを返すように強制します。

私はあなたがそれをすることができないことを知っています、そして私はあなたがそれをすることができない理由を知っていますが、一般的な代替手段は次のとおりです。

class Foo{
public abstract String getParam();
}

パラメーターの値を知りたいだけで、クラスのインスタンス化に費用がかかる場合は役に立たないインスタンスが必要になるため、満足できません。

「定数インターフェイス」アンチパターンを使用せずに、人々がこれをどのように回避するかを知りたいと思います。

編集:私は特定の問題についてさらに詳細を追加しますが、これは私がこのようなことをしたいと思ったときのことです。過去には他にもいくつかありました。

私のサブクラスはすべてデータ プロセッサであり、スーパークラスはそれらの間の共通コードを定義します。これにより、データを取得して解析し、必要な場所に配置できます。各プロセッサは、SQL データベースに保持されている特定のパラメータを必要とします。各プロセッサーは、必要なパラメーターのリストとデフォルト値を提供できる必要があります。これにより、各プロセッサーのタイプに必要なパラメーターを確認することで、構成データベースを検証またはデフォルト値に初期化できます。プロセッサのコンストラクターで実行することは受け入れられません。これは、オブジェクト インスタンスごとに 1 回ではなく、クラスごとに 1 回だけ実行する必要があり、各タイプのクラスのインスタンスがまだ必要でない場合にシステムの起動時に実行する必要があるためです。

4

5 に答える 5

11

ここで静的なコンテキストでできる最善のことは、次のいずれかのようなものです。

a. 具体的に探しているが、コントラクトの一部ではないメソッドを用意し (したがって、だれにも実装を強制することはできません)、実行時にそれを探します。

 public static String getParam() { ... };
 try {
     Method m = clazz.getDeclaredMethod("getParam");
     String param = (String) m.invoke(null);
 }
 catch (NoSuchMethodException e) {
   // handle this error
 }

b. 注釈を使用します。注釈を使用すると、クラスに強制的に配置することができないという同じ問題が発生します。

@Target({TYPE})
@Retention(RUNTIME)
public @interface Param {
   String value() default "";
}

@Param("foo")
public class MyClass { ... }


public static String getParam(Class<?> clazz) {
   if (clazz.isAnnotationPresent(Param.class)) {
      return clazz.getAnnotation(Param.class).value();
   }
   else {
      // what to do if there is no annotation
   }
}
于 2012-08-13T17:42:38.490 に答える
3

間違ったツールで間違った問題を解決したいようです。すべてのサブクラスが静的メソッドを定義する(実際には継承とは言えません)場合でも、それを問題なく呼び出すことはできません (コンパイル時に不明なクラスで静的メソッドを呼び出すには、リフレクションまたはバイト コード操作を使用します)。

アイデアが一連の動作を持つことである場合、すべてが同じインターフェイスを実装するインスタンスを使用しないのはなぜですか? 特定の状態のないインスタンスは、メモリと構築時間の点で安価であり、状態がない場合は、すべての呼び出し元に対して常に 1 つのインスタンス (flyweight パターン) を共有できます。

メタデータをクラスと結合するだけでよい場合は、好きなメタデータ機能を構築/使用できます。最も基本的な (手作業での) 実装は、クラス オブジェクトがキーである Map を使用することです。それがあなたの問題に合っているかどうかは、実際には詳細に説明していない問題によって異なります。

EDIT:(構造)メタデータはデータをクラスに関連付けます(これは1つのフレーバーにすぎませんが、おそらくより一般的なものです)。注釈は、非常に単純なメタデータ機能として使用できます (クラスにパラメーターで注釈を付けます)。他にも無数の方法 (および達成すべき目標) があります。複雑な側面としては、実行時にアクセスするために UML モデルに設計された基本的にすべての情報を提供するフレームワークがあります。

しかし、あなたが説明するもの (データベース内のプロセッサとパラメーター) は、私が「一連の動作」と名付けたものです。そして、「パラメーターはクラスごとに1回ロードする必要がある」という議論は議論の余地があり、「静的」なものを必要とせずにこれを解決するために使用できるイディオムを完全に無視しています。つまり、flyweight パターン (インスタンスを 1 回だけ持つため) と遅延初期化 (作業を 1 回だけ行うため) です。必要に応じてファクトリーと組み合わせる。

于 2012-08-13T17:13:10.887 に答える