2017-03-08 10 views
2

Java 8でコマンドパターンを使用して、さまざまなクラスのオブジェクトにさまざまなコマンドを渡したいとします。キャッチは、オブジェクトにはパブリックセッターを公開したくないメンバーがあることです。私はそれらのメンバーがコマンドを介して操作されることを望みます。私の問題は、これらのメンバ(または、より良いパッケージプライベートセッタ)をコマンドに公開する方法です。私がそれらをインタフェースの一部にすると、それらを公開する。私が複数の継承を必要とするので、それらを継承することは選択肢ではありません。だから、コマンドはクラスの一部として、あるいはインターフェースの一部として公開されていない場合、どのようにsetterが利用可能であるかを知ることができますか?オブジェクトの種類を切り替えるJavaの代替方法

私が考えている最良の解決策は、コマンドのタイプを切り替えてコマンドの実行を実装することです。がクラス内にあります(メンバーはプライベートになることもできます)。必要な情報をコマンドクラスから引き出すだけです。しかし、OO言語でオブジェクトタイプを切り替えるという考えは、私に汚染を感じさせます。より良い方法がありますか?

+6

問題を説明するのではなく、[mcve]を入力すると手助けするのが簡単になります。 –

+0

最小限の、完全で検証可能な例は、設計に取り組むことができない場合は非常に良いものです。デザインをしていなくても実用的ではありません。下のdasblinkenlightのおかげで、私が必要としていたパターンを見つけることができました。 – digitig

答えて

2

使用Visitor Pattern

  • あなたの設定可能なクラスは、あなたのコマンドクラスは、あなたがコマンドのacceptメソッドに設定可能なクラスを渡すと、コマンドはそのメソッドを呼び出しElement
  • ある
  • Visitorですコマンドのタイプに対応します。

    interface CommandVisitor { 
        void visit(SetCommand1 cmd); 
        void visit(SetCommand2 cmd); 
    } 
    interface Command { 
        void accept(CommandVisitor v); 
    } 
    class SetCommand1 : Command { 
        public void accept(CommandVisitor v) {v.visit(this);} 
    } 
    class SetCommand2 : Command { 
        public void accept(CommandVisitor v) {v.visit(this);} 
    } 
    

    今すぐあなたの設定可能なクラスがあなたに渡されたコマンドの種類に基づいて、「コールバック」を受け取ることになりますSetCommand1SetCommand2ためvisitオーバーロードを実装することができます:ここで

は一例です。

+0

このソリューションは、パッケージプライベートAPIへのアクセスを得るために、OPと同じように、同じパッケージ内に存在するように、 'サポートされているさまざまなクラス'を必要とします。しかし、それはあなたが[表現の問題](https://en.wikipedia.org/wiki/Expression_problem)を解決するあなたの方法にあると思います。新しいコマンドへの不変性と新しいデータ型への変形。 – mike

1

された入れ子のクラスは、その外側のクラスのprivateメンバーへのアクセス権を持っているので、あなたは、コマンドにネストされたクラスを作ることができる:

interface Command { 
    void execute(); 
} 

class Model { 
    private int fieldA; 
    private String fieldB; 

    ... 

    public Command getCommand() { 
     return new MyCommand(); 
    } 

    ... 

    private class MyCommand implements Command { 
     @Override 
     public void execute() { 
      fieldA = 10; 
      fieldB = "Foo"; 
      //Or use setter... 
     } 
    } 
} 

その後:

Model model = ...; 
Command command = model.getCommand(); 
//usage... 

この方法でMyCommandModelにアクセスすることができます "他のものはできません。

0

このソリューションでは、オブジェクトに強制的にコマンドを提供します。これにより、オブジェクトの内部を隠すことができます。コマンドはすべてCommandから派生しています。

@FunctionalInterface 
public interface Command { public void execute(); } 

たとえば、CommandAです。

public interface CommandA extends Command { } 

このフレームワークで動作するオブジェクトは、Commandableを実装する必要があります。このインタフェースは、サポートされているすべてのコマンド用のメソッドを持ち、オブジェクトが与えられたコマンドの固有の実装を返すことを可能にします。

public interface Commandable { public CommandA getCommandA(); } 

以下のように使用する。

public class Type implements Commandable { 

    private boolean isRunning = false; 

    public CommandA getCommandA() { 
     return() -> {isRunning = true;}; 
    } 

    public boolean isRunning() { 
     return isRunning; 
    } 

    public static void main(String[] args) { 
     Type type = new Type(); 
     System.out.println(type.isRunning()); 

     Commandable object = type; 
     CommandA command = object.getCommandA(); 
     command.execute(); 

     System.out.println(type.isRunning()); 
    } 

} 

出力を使用すると、オブジェクトがCommandableを実装したくない場合は、コマンドレジストリのいくつかの種類を作成し、実装を登録するすべてのオブジェクトを強制することができ、また

false 
true 

ですそこのコマンド(それをサポートしています)の。

関連する問題