2012-04-12 116 views
0

我有一個使用command design pattern的對象集合,即它們實現了一個抽象Command類,並且有一個​​方法。使用命令設計模式將命令行參數轉換爲對象

調用時(例如)在命令行中,你可以做這樣的事情,但其嚴重笨重,你將如何實現這一點:

public void main(String[] arg) { 
    Command c = null; 

    if(arg[0].equals("FirstCommand") { 
     c = new FirstCommand(arg[1]); 
    } 
    if(arg[0].equals("SecondCommand") { 
     c = new SecondCommand(arg[1], arg[2]); 
    } 
    if(arg[0].equals("ThirdCommand") { 
     c = new ThirdCommand(arg[1], Long.parseLong(arg[2])); 
    } 
    //.....etc.... 
    c.execute(); 
} 

顯然可用命令的列表的增長,這變得相當繁瑣的代碼

回答

1

反射很容易。開始與這個:

final Class[] argTypes = new Class[args.length - 1]; 
final String[] cmdArgs = new String[args.length - 1]; 
for (int i = 0; i < argTypes.length; i++) { 
    argTypes[i] = String.class; 
    cmdArgs[i] = args[i+1]; 
} 
final Command c = (Command) Class.forName(MY_PACKAGE + args[0]).getConstructor(argTypes) 
    .newInstance(cmdArgs); 

現在,解決的唯一的事情是,你將不得不推解析和驗證到您的Command構造。或者,如果你想變得很花哨,你可以找到一個基於arg count的構造函數,查看它接受的arg類型,並適當地解析cmdline args。

0

不需要你跟蹤可用命令的通用解決方案就是使用反射來實例化命令。你要麼有一個構造函數獲取參數列表,要麼定義像McDowell建議的那樣的execute方法。這取決於你是否想用相同的參數多次重新執行相同的命令,以及命令是否可以從緩存的結果中受益(無狀態與有狀態)。

命令名稱將是類的簡單名稱。你只能添加包來創建一個完全限定的名字,然後添加class.getConstructor(Class [] params)並調用該構造函數(或者如果選擇將參數傳遞給execute方法,則使用默認構造函數)。

+0

這是我的理解,它不可能做到這一點沒有一些複雜的類路徑加載hackery? – Jacob 2012-04-12 12:30:04

+0

你認爲classpath hackery是什麼意思?我的答案假定指定爲參數的類可用於正在運行的類的類加載器。 Marko TopoInik發佈了我懶得寫出答案的代碼 – bennidi 2012-04-27 20:42:28