2013-09-30 37 views
4

我有一個特殊的問題,我有一個通用的class Command我用來順序地在緩衝區中表示命令。我也有它的幾個子類,如ComputeCommand,DefineCommand,DisplayCommand等。 每個子類的構造函數都採用String參數,命令根據命令語法解析該參數,該命令語法因命令類型而異。獲得專門的兒童班的正確方法是什麼?

我希望能夠做一些事情,如:

String [] lines = { ... }; 
ArrayList<Command> commands = new ArrayList<Command>(); 
for(String line: lines){ 
    commands.add(new Command(line)) 
} 

不過,我需要更多的專業類能夠處理每個命令。

如果我可以定義構造是這樣的:

Command(String line){ 
    if(ComputeCommand.isValidComputeCommand(line)) 
     return new ComputeCommand(line); 
    else if(DisplayCommand.isValidDisplayCommand(line)) 
     return new DisplayCommand(line); 
    [ ... ] 
} 

這將完成我所需要的,但是構造不工作的方式,因爲我們都知道。我想到的

的方法之一是包括像

static Command getInstance(String line){ [...] } 

的方法來實現該功能,但是我不知道,這是在這種情況下,正確的做法。

另一種可能的方法是爲每一個創建工廠類:

class CommandFactory(){ 
    CommandFactory [] subFactories = {new ComputeCommandFactory(), [...]}; 
    Command makeCommand(String line){ 
     for(CommandFactory subFactory: subFactories) 
      if(subFactory.canMake(String line)) 
       return subFactory.makeCommand(line); 
    } 
    boolean canMake(String line){ 
     for(CommandFactory subFactory: subFactories) 
      if(subFactory.canMake(String line)) 
       return true; 
    } 
} 

我想,這可能是最接力,正確的方式來做到這一點,但我不想,如果添加額外的複雜性有一個更好的辦法。

這種情況下使用的正確設計模式是什麼?

編輯: 我也打算繼承一些命令進一步的,比如ComputeCommand可以有一個AddCommandMultiplyCommand子類。

+2

只需要注意一點:'static命令getInstance(String line){[...]}'_already_是工廠方法。您不必爲了擁有工廠方法而引入新類。 –

回答

2

如您所想,您的CommandFactory方法是最接近正確的。工廠/工廠方法通常用於這類問題。

你明顯看到的唯一問題是,這個CommandFactory必須知道所有的子因素,必須知道所有的類型。這意味着如果你添加一個新類型,你也必須將它添加到CommandFactory

但是!您可以使用例如org.clapper.util庫中的ClassFinder以查找在類路徑中實現Command或將CommandFactory擴展的所有類。這樣,您可以在將來添加任何新的Commands,並且CommandFactory仍然可以找到它們並將它們添加到subFactories

您也可以解決問題 - 讓子工廠(或個人Commands自己)瞭解工廠!首先用ClassFinder找到它們,然後調用它們的方法,將它們添加到工廠列表中。這與聽衆的工作方式類似。

1

我正在閱讀的是,你想基於上下文建立正確的對象嗎?你有一些字符串,你想從該字符串的內容構建正確的對象?

你可以有一個CommandBuilder /工廠,這就是你可以放置你的if-else邏輯返回正確的命令。

public Command buildCommand(String line){ 
    if(ComputeCommand.isValidComputeCommand(line)) 
     return computeCommandFactory.buildCommand(line); 
    else if(DisplayCommand.isValidDisplayCommand(line)) 
     return displayCommandFactory.buildCommand(line); 
    [ ... ] 

} 

這聽起來像你想用建設者或abstract factory來構建你需要的Command對象。當你有一個大的if-else if鏈時,你通常要使用一個策略模式。

+1

海報還應該考慮使用諸如ANTLR或JavaCC的詞法分析器,而不是試圖處理每個命令類中的所有決策。我從來沒有用過,但是當我使用C,C++和Obj-C編程時,我已經使用過lex/yacc。 –

1

我認爲你需要組合FactoryChain of Responsibility模式來做你想做的事情。

interface CommandFactory{ 
    Command create(String line); 

    void addToChain(CommandFactory next); 
} 

如果你的工廠無法處理給定的線,然後將其傳遞鏈中的線下一個工廠:

class ComputeCommandFactory{ 


    CommandFactory next; 

    Command create(String line){ 
     if(<can process>){ 
      return new ComputeCommand(line); 
     } 
     if(next ==null){ 
      throw Exception("can't process"); 
     } 
     return next.create(line); 
    } 

} 

這樣你就可以在以後添加新的工廠(即使在運行時)。這與添加類加載器和數據庫驅動程序在Java中的工作方式類似。

1

您正處在正確的軌道上。您正在使用的模式是工廠模式。 你的想法是對的,模式只不過是「寫在紙上」的這種想法:)。

所以,你的情況,你可以做這樣的事情:

public class CommandFactory 
{ 
    public static Command getCommand (String line) 
    { 
     Command command = null; 
     if (ComputeCommand.isValidComputeCommand (line)) 
     { 
     command = new ComputeCommand (line); 
     } 
     else if (DisplayCommand.isValidDisplayCommand (line)) 
     { 
     command = new DisplayCommand (line); 
     } 

    return command; 
    } 
} 

,並使用它像這樣:

Command command = CommandFactory.getCommand (line); 

希望有所幫助。