2

私は抽象クラスを持っています:

public abstract class AbstractCommand {

    private static State state;
}

目的

  • クラスのオブジェクトはState、いくつかの「制御クラス」によって提供され、各AbstractCommandサブクラスが必要とするデータを提供します
  • 各サブクラスには読み取りアクセスが必要です
  • サブクラスはフィールドを変更できません

現在のアプローチ

stateサブクラス (コマンドを定義する) がフィールドを使用できるように (読み取り専用)、プログラムの「制御クラス」によってフィールドを初期化する必要があります。サブクラスは内部で定義されており、ユーザーのインターフェースとして使用する必要があります。このユーザーには、 への書き込みアクセス権はありませんstate

問題

  • publicsetState()メソッドを追加するAbstractCommandと、すべてのサブクラスがアクセスできるようになり、ユーザーもアクセスできるようになります
  • フィールドを final にすると、オブジェクトの作成が抽象クラスで強制的に行われ、「制御クラス」はこのオブジェクトを使用する必要があり、さらに置き換えられません。

このようなものをどのように処理しますか?

別の試み

一部の回答はパッケージの可視性を使用したソリューションを提案しているため、これがうまくいくかどうか疑問に思います:

「制御クラス」(パッケージの外部から) からの呼び出しを抽象クラスに委譲することによって、必要な情報を提供するクラスを同じパッケージ内に配置します。

少しあいまいに聞こえますが、どう思いますか?

4

7 に答える 7

1

protected私があなたを正しく理解しているなら、あなたはキーワードを探しています。

Javaでは、このキーワードはサブクラスとパッケージのフィールドアクセスを許可しますが、フィールドをパブリックにしません。これにより、フィールドのパブリック保護を犠牲にすることなく、探しているパブリック読み取り専用の動作が可能になります。保護されたフィールドに直接アクセスできるクラスは、同じパッケージ内のすべてのもの、または直接サブクラス(別のパッケージ内にある可能性があります)のみです。

出典:http ://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

于 2013-01-17T16:16:50.537 に答える
1

AbstractCommand「制御クラス」と特定の実装を別のパッケージと同じパッケージに入れることができます。次に、package-private セッターと保護されたゲッターを提供できます。これにより、制御クラスが値を設定できるようになり、実装はゲッターにのみアクセスできます。

ただし、これはパッケージ構造を混乱させます。これが発生したくない場合は、Factory を使用してみてください。次のパッケージ構造を構築できます。

 command
     impl
         CommandImpl1 //extends AbstractCommand
         CommandImpl2 //extends AbstractCommand
     AbstractCommand
     CommandFactory

アイデアは、Factory を使用して AbstractCommand のインスタンスを作成するというものです。したがって、他のパッケージの Factory にパラメーターを渡すと、必要な実装が選択され、新しいオブジェクトが返されます。この場合、前のアイデアを使用して、ゲッターとセッターへの適切なアクセスを許可できます。ただし、ここでは、フィールドを一度だけ設定できます。

何度も変更する必要がある場合は、アセッサーを作成できます。これは、AbstractCommand と同じパッケージ内の CommandAccessor クラスであり、次のような静的メソッドを提供する必要があります。

public static void setState(State newState, AbstractCommand command);

実装クラスで使用することを妨げるものは何もありませんが、使用しないという非公式のルールを設定することはできます。

于 2013-01-17T16:22:52.120 に答える
1

あいまいなソリューションしか提供できません。

最初にいくつかの解決策:

どちらか

private static final State state = Controller.initState();

または、制御の反転、依存性注入、を使用し@Injectます。これにより、単体テストも可能になります。確かに、Web にはオープンソースの DI コンテナーが存在します (Spring、または Pico コンテナーはまだ存在しますか?)。または、いくつかの DI コンテナーから Bean を要求します。

両方が早すぎる場合は、遅延評価に進みます (部分的に静的な初期化は既に遅延しています)。内部クラスが表示されることがあります。

private static class Singleton {
    private static final State state = Controller.initState();
}

おそらくgetInstanceを使用します。

私の選択:

どういうわけか静的ではありませんが、シングルトンへのゲッターです。コントローラーで動作する Bean フレーム。


静的ではなくシングルトン。

以前の Eclipse 3 リッチ クライアントで豊富に使用されていた静的 (静的関数) など

IPreferenceStore store = IDEWorkbenchPlugin.getDefault().getPreferenceStore();
boolean autoPrint = store.getBoolean(AUTO_PRINT);

代わりに、OSGi コンテナーとアノテーションによる依存性注入を使用します。

@Inject @Preference(AUTO_PRINT)
boolean autoPrint;

出典: Eclipse 4、M. Teufel および J. Helming によるリッチ クライアント

短くなるだけでなく、クラス間の結合が少なくなり、autoPrint を好きなように入力でき、充填クラスに干渉する必要がないため、単体テストをより簡単に記述できます。

このようなコンテナのオーバーヘッドを追加することをためらう場合、最も簡単な方法は、Java オブジェクト、POJO Bean をルックアップできる1 つのグローバル アプリケーション コンテキストを用意することです。おそらくXMLファイルに裏打ちされています:

State state = ApplicationContext.lookup(State.class, "state");

<bean name="state" class="org.anic.State" value="sleepy" depends="firstThis"/>
<bean name="firstThis .../>

気をつけてください、静的な状態を持つ必要はもうありません。

Spring フレームワークには、そのような XML アプローチがあります。

利点は、シーケンスとさまざまなファクトリ/作成方法が考えられる集中型の初期化です。

(的外れな回答ですみません。)

于 2013-01-17T16:45:12.383 に答える
0

したがって、Magus が「AbstractCommand のサブクラスは状態値を設定できないが、他のクラスはそれを実行できるようにしたいですか?」と述べたような動作が必要であることがわかります。

これが私の提案です:

  1. いくつかのルールでインターフェイスを作成します。すべてのサブクラスに適用したいこと

  2. AbstractCommand次に、そのインターフェイスを実装しましょう。これにはstate変数も含まれている必要があります。これにより、一連のルールを下位レベルで維持できます。

  3. AbstractCommand手順 1 で定義したインターフェイスの 2 番目のレグでは、クラス変数にアクセスしたくない他のクラスを用意します。

これにより、パッケージ構造を維持できます。お役に立てれば。

于 2013-01-17T16:31:32.963 に答える
0

抽象クラスのコンストラクターとして渡します

public abstract class AbstractCommand {
    private static State state;
    protected AbstractCommand(State state){
        this.state = state;
    }        

    public State getState(){
        return state;
    }
}

あなたの拡張クラスでは...

 public class Command1 extends AbstractCommand{
       public Command1(){
             super([some state]);
       }
 }

拡張クラスは、state初期化中に 1 回設定できますが、その後は読み取り専用アクセスになります。

于 2013-01-17T16:26:34.423 に答える
0

これが私が試していたものです:

インターフェイスを次のように作成します。

public interface RuleInterface { //Define rules here void method1(); }

これを AbstractCommand クラスに実装します

public abstract class AbstractCommand implements RuleInterface{ private static String state; }

他のクラスがあり、このクラスは変数を変更できstateます

public class SubClassAbstractCommand extends AbstractCommand{ @Override public void method1() {
} }

インターフェイス用にもう 1 つのレッグを次のように作成します。

public class AnotherLeg implements RuleInterface{ @Override public void method1() { } }

AnotherLeg クラスはstate変数にアクセスできなくなりましたが、インターフェイスを介してルールを適用できますRuleInterface

于 2013-01-17T17:07:54.207 に答える
0
public abstract class AbstractCommand {
    private static State state;
    static {
        state = Controller.getState();
    }
    protected AbstractCommand(){
    }        
    public State getState(){
        return state;
    }
}
于 2014-07-19T14:12:03.780 に答える