2016-01-15 65 views
0

注:我瞭解清潔守則設計模式面向對象編程所以請回答時記住這一點。如何在Java中設計ActionListener類?

我有一堆窗口,上面有一堆JButtons和一個TextField。下面是其單獨的文件窗口類:

// Window.java 
public class Window { 
    JTextField textField; 
    JButton button1; 
    JButton button2; 
    ... 
} 

這是我想什麼:

當我按下button1我想textField顯示「1」,當我按下button2顯示「 2" 等,因此,這裏是在一個單獨的文件中的ActionListener類,這是那種我想要它做的事:

//TextInputActionListener.java 
public class TextInputActionListener implements ActionListener{ 
    public void actionPerformed(ActionEvent e) { 
     if(e.getSource() == button1) { 
      textField.setText("1"); 
     } 
     else if (e.getSource() == button 2) { 
      textField.setText("2"); 
     } 
    } 
} 

現在很明顯這不會工作,所以我的問題是我應該如何定義這個類?

  • 我被宣佈作爲一個內部類的Window
  • 難道我不打算爲它創建一個單獨的類嗎?(我可以只作Window類實現ActionListener這將解決這個問題)

注:正如你所看到的問題不是如何去做,而是,如何做到這一點的方式支持面向對象的設計。

+0

#1)擴展Action而不是實現ActionListener。 #2)你可以在Window類中定義動作,或者傳入將要操作的參數。這兩種方法都很好。 –

回答

0

首先我要感謝大家誰回答的問題。沒有你我就不知道了。你們每個人都給了我一個難題。

我最初的問題是:

  1. TextInputListener類需要訪問buttonX
  2. TextInputListener類需要訪問textField

在TextInputListener類我計算過,它並不真正需要訪問的按鈕,它只有知道如果e.getSource()等於button。因此,我在Window類中創建了一個方法,其中ActionEvent作爲參數(如e),將其與buttonX進行比較,然後返回答案。

//Window.java 
... 
boolean isButton0(ActionEvent e) { 
    return e.getSource() == buttons[0]; 
} 
boolean isButton1(ActionEvent e) { 
    return e.getSource() == buttons[1]; 
} 
... 

問題1解決:

所以我現在更近了一步。我可以確定是否按下了button1,button2 ..,但沒有聲明按鈕是公開的,也沒有通過像getButton1()這樣的「getter」方法返回它。

// TextInputListener.java 
public class TextInputListener implements ActionListener { 
    Window window; 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (window.isButton0(e)) { 
      //textField.setText("0") 
     } else if (window.isButton1(e)) { 
      //textField.setText("1") 
     } 
     ... 
    } 
} 

TextInputListener.java和Window.java是在相同的封裝所以我能夠申報方法包私人。)

問題2解決:

一旦再次TextInputListener並不真的需要textField(作爲一個變量)它只需要設置其文本。所以我創建了另一個包私鑰方法setOutputText(String text)來設置文本。下面的代碼:

// Window.java 
public class Window { 
    TextField textField; 
    JButton button1; 
    JButton button2; 
    ... 
    void setText(String text) { 
     textField.setText(text); 
    } 
} 

// TextInputListener.java 
public class TextInputListener implements ActionListener { 
    Window window; 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (window.isButton0(e)) { 
      window.setText("0"); 
     } else if (window.isButton1(e)) { 
      window.setText("1"); 
     } 
     ... 
    } 
} 

把一切TOGETHER:

現在剩下的工作就是讓類的每個實例來了解彼此的唯一的事情。在TextInputListener類添加以下代碼:

public void listenTo(Window window) { 
     this.window = window; 
    } 

在Window類我不得不把ActionListener添加到每個按鈕,所以我加了如下代碼:

public void setActionListener(ActionListener l) { 
     for (int i = 0; i < buttons.length; i++) { 
      buttons[i].addActionListener(l); 
     } 
    } 

這基本上!主要設置一切,它的工作。下面是(幾乎)完整的最終代碼:

// MyApp.java 
public class MyApp { 
    public static void main(String[] args) { 
     Window myWindow = new Window(); 
     TextInputListener myTextInputListener = new TextInputListener(); 

     myWindow.setActionListener(myTextInputListener); 
     myTextInputListener.listenTo(myWindow); 
    } 
} 

// Window.java 
public class Window { 
    TextField textField; 
    JButton button1; 
    JButton button2; 
    ... 
    void setText(String text) { 
     textField.setText(text); 
    } 
    public void setActionListener(ActionListener l) { 
     for (int i = 0; i < buttons.length; i++) { 
      buttons[i].addActionListener(l); 
     } 
    } 
} 

// TextInputListener.java 
public class TextInputListener implements ActionListener { 
    Window window; 

    public void listenTo(Window window) { 
     this.window = window; 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (window.isButton0(e)) { 
      window.setText("0"); 
     } else if (window.isButton1(e)) { 
      window.setText("1"); 
     } 
     ... 
    } 
} 
1

利用您當前的結構,Window類可以實現ActionListener,因爲它負責監聽其視圖上的事件。內部類也是可以接受的,但可能會導致更多混亂的代碼。你應該注意過度分離的擔憂。您應該只根據模型,視圖和控制器真正分離您的代碼。

絕對檢查出MVC設計模式。

+0

尚未研究過MVC模式,但它非常有用。感謝您爲我指出:) –

1

由於偵聽器類經常需要訪問GUI類的字段(比如你的Window),所以對於偵聽器使用內部類是個好主意。

當然,不禁止Window實現ActionListener,但是您在公開API中公開了實現細節,並且您應該考慮是否需要這樣做。

注意的Java 8的Lambda表達式和方法把手讓您有更多的可能性寫監聽器代碼:

class Window { 
    JTextField textField; 
    JButton button1; 
    JButton button2; 


    Window() 
    { 
     button1.addActionListener(event -> textField.setText("1")); 
     ... 
    } 
} 
1

這是我對這個問題:

  • 應該ActionListener執行被聲明爲一個Window的內部類? - 我不會。這是因爲當有一個與包含類的狀態緊密相關的功能塊時使用內部類。對於例如一個Iterator<E>實現可以被編寫爲Collection<E>實現的內部類。在這種情況下,Iterator實現可以訪問Collection實現的私有數據成員。另一個例子是Builder pattern。內部類可以訪問父類的私有成員,因此應謹慎使用。
  • 是否應該爲它創建一個單獨的類 - 是的,並且您應該以最低要求的訪問級別將其聲明在單獨的文件中。你不會想讓Window類實現ActionListener - 只是因爲這會使Window類負責處理所有的事件它包含控件 - 違反關注點分離(單一責任原則)。所以想象一下你將要寫的代碼 - 它將充滿一長串的if條件或一個開關情況來識別事件的來源。這顯然意味着如果將新控件添加到窗口類中,則會增加ifswitch塊的長度。在單獨的類中聲明動作偵聽器允許分離關注點,並且還有助於可測試性。

希望這有助於

+0

謝謝你的有用答案,但如果我應該在一個單獨的文件中聲明actionlistener類,如何訪問按鈕並修改文本字段?如果你可以編輯你的答案並給我提供一些很棒的例子代碼! :) –

+0

爲您的TextInputActionListener)類創建一個構造函數,並將所需的參數傳遞給它:'button.addActionListener(new TextInputActionListener(textField));' – FredK