2017-03-08 63 views
2

我想在Java 8中使用命令模式將各種命令傳遞給各種類的對象。問題在於這些對象有我不想向公衆公開的設置者的成員;我希望通過命令操縱只有。我的問題是如何將這些成員(或者更好的包私人設置者)公開給命令。如果我將它們作爲界面的一部分,那麼我會將它們公開。繼承它們不是一種選擇,因爲我需要多重繼承。那麼如果這些指令既不是類的一部分,也不是作爲接口的一部分公開的,那麼該命令如何知道setter是可用的?Java替代開啓對象類型

我認爲最好的解決辦法是讓相關的類來打開命令的類型和執行命令的執行類中完全(使成員可以是私有的 - 甚至更好),只是從命令類中提取必要的信息。但是以OO語言切換對象類型的想法讓我感覺受到了污染。有沒有更好的辦法?

+6

如果你提供一個[mcve]而不是僅僅描述問題,那麼它會更容易幫助你。 –

+0

當一個設計人員無法工作時,一個最小的,完整的和可驗證的例子都很好。甚至連一個設計都沒有的時候,它是不太實際的!所以感謝下面的dasblinkenlight,以便發現我需要的模式。 – digitig

回答

2

使用Visitor Pattern

  • 你的配置類是Visitor
  • 你的命令類是Element
  • 你通過配置類命令的accept方法,並且命令調用一個方法對應於命令的類型。

下面是一個例子:

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);} 
} 

現在您的配置類可以實現visit重載SetCommand1SetCommand2,將接收基於傳遞給你的命令的類型的「回調」。

+0

該解決方案需要「OP支持的各種類」,才能訪問包私有API,因爲OP稱它爲駐留在同一個包中。但我想,這與你解決[表達問題]的方式有關(https://en.wikipedia.org/wiki/Expression_problem)。不變新的命令和變種新的數據類型。 – mike

1

嵌套類訪問其封裝類的私有成員,所以你可以做的命令嵌套類:

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... 

這樣MyCommand可以訪問Model「但沒有其他的東西可以。

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()); 
    } 

} 

輸出是

false 
true 

另外,如果你不希望對象來實現Commandable,您可以創建某種命令的註冊表,並迫使每一個對象註冊該實施(它支持)的命令。