2016-04-23 68 views
1

我正在嘗試使用MVC編碼實踐來生成桌面RPG的字符。我將有幾個「控制面板」類,每個類都有一組特定的按鈕來處理角色創建過程的不同方面(滾動屬性,購買設備等)。我的控制器類將擁有每個「控制面板」類的實例。我的廣義代碼是在這裏:如果B類的實例是類A的成員,那麼當B類中的按鈕被按下時,B類如何調用類A的方法?

公共類控制器{

private Model m; //class Model not shown 
private Viewer v; //class Viewer not shown 
private JFrame frame; 
private ControlPanelOne cpo; 
private ControlPanelTwo cpt; //class ControlPanelTwo not shown 

public Controller(){ 
    m = new Model(); 
    v = new Viewer(); 
    frame = new JFrame(); 
    frame.setLayout(…); 
    cpo = new ControlPanelOne(); 
    cpt = new ControlPanelTwo(); 
    frame.add(cpo.getPanel()); 
    frame.add(cpt.getPanel());} 

public void update(){ 
    m.update(); 
    v.update();}} 

公共類ControlPanelOne {

private JPanel panel; 
private JButton button; 

public ControlPanelOne(){ 
    panel = new JPanel(); 
    button = new JButton(「press me」); 
    panel.add(button); 
    button.addActionListener(new ActionListener(){ 
     public void actionPerformed(ActionEvent e){ 
      //do some stuff; 
      //call Controller’s update method;}})} //the important bit! 

public JPanel getPanel(){ 
    return panel;}} 

公共類測試儀{

public static void main(String[] args){ 

    Controller c = new Controller();}} 

我怎樣才能得到ControlPanelOne看並在按下ControlPanelOne的按鈕時調用Controller的update()方法?我試着製作ControlPanelOne擴展控制器,這樣我就可以在按下ControlPanelOne的按鈕時調用super.update(),但當Controller實例化時(例如在Tester類中),它的ControlPanelOne成員也會被實例化, Controller和ControlPanelOne的構造函數在構造的無限循環中調用。

試圖欺騙編譯器,使Controller的update()方法靜態不起作用,因爲實例m和v不是靜態的。

我不想讓ControlPanelOne成爲控制器的內部類,如果我可以幫助它的話。還會有其他的「控制面板」類(ControlPanelTwo等),我害怕讓所有的內部類都會讓Controller的代碼變得漫長而混亂。我希望每個「控制面板」作爲一個單獨的類來處理一個特定的功能,以便於維護和模塊化代碼重用。

似乎很清楚,ControlPanelOne不應該有一個控制器作爲成員變量,因爲)它是概念上向後和b)其他的「控制面板」的需要自己一個控制器的情況下,情況......

我曾經有過控制器擴展JFrame和ControlPanelOne擴展JPanel(這樣Controller可以直接添加()一個ContollPanelOne的實例,而不是調用ControlPanelOne的getPanel()方法),但是我讀了讓類擴展這些組件,而不是讓你的組件成員上課形式很差。但是,如果它會以某種方式幫助回去使控制器和擴展ControlPanelOne JFrame的JPanel的和...

也許我的MVC的想法是錯誤的...

請告知

+0

您應該使用接口來定義像'update'這樣的常用方法,並將該接口作爲參數傳遞給控制面板 –

+0

如果您希望特定的A類實例能夠調用B類的特定實例上的實例方法那麼爲什麼不簡單地將對B實例的引用傳遞給A的構造函數呢? – scottb

回答

0

你的近期目標是到一個匿名ControlPanelOne的構造函數中實現ActionListeneractionPerformed方法中對Controller實例調用updateControlPanelOneController的實例的構造函數組成。實際上,您需要從ControllerControlPanelOne的循環參考,反之亦然。

下面是一個簡單的方法。您可以查看最低限度完成的項目here

首先,你的Controller

public class Controller { 

    private Model m; //class Model not shown 
    private Viewer v; //class Viewer not shown 
    private JFrame frame; 
    private ControlPanelOne cpo; 
    private ControlPanelTwo cpt; //class ControlPanelTwo not shown 

    public Controller() { 
     m = new Model(); 
     v = new Viewer(); 
     frame = new JFrame(); 
     frame.setLayeredPane(null); // Do something 

     cpo = new ControlPanelOne(this); // Supply self to the instance of ControlPanelOne 
     cpt = new ControlPanelTwo(); 

     frame.add(cpo.getPanel()); 
     frame.add(cpt.getPanel()); 
    } 

    public void update() { 
     m.update(); 
     v.update(); 
    } 
} 

接下來,ControlPanelOne

public class ControlPanelOne { 

    private JPanel panel; 
    private JButton button; 

    public ControlPanelOne(final Controller controller){ 
     panel = new JPanel(); 
     button = new JButton("press me"); 
     panel.add(button); 
     button.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       //do some stuff; 

       controller.update(); 

      } 
     }); 
    } 


    public Component getPanel() { 
     return null; 
    } 
} 

要記住的重要一點是要申報的最後Controller在構造函數中提供的實例(你可以找出原因here)。在Java 8中這不是必需的,但它仍然是一個很好的習慣。

0

如果我的理解以及B類是A類的一個組件
B類不知道關於類A的,即使它是該類的成員,它也不會引用它。 這叫做組成「has-a」的關係。如果你想知道這個類,你應該在類B中擁有一個類A的實例,或者使得類A的方法是靜態的。

class B { 
    btnPressed() { 
     /*To call this method you need or an object of class A, or static method in class A*/ 
     methodA(); //Method form class A 

     op1: 
     a = new A(); 
     a.methodA(); 

     op2: 
     //make methodA static in class A 
     A.methodA(); 
    } 
} 

class A { 
    b = new B(); 

    methodA(); 
} 

希望這會有所幫助。

1

確實,你不遵守MVC模式。該模式的要點是爲您的模型,視圖和控制器提供清晰的分離。所以,任何企圖互相繼承或合作的企圖都會損害這種利益。

我會做的是使一個AbstractAction像:

public class UpdateAction extends AbstractAction { 

    private Controller controller; 

    ... 
    @Override 
    public void actionPerformed(ActionEvent ae) { 
     controller.update(); 
    } 
} 

然後,初始化和設置按鈕彈起視圖外,視圖不需要知道它的顯示;它只需要知道它的工作就是展示事物。你可以讓控制器extend JFrame並添加JPanel到它。

JButton button = new JButton("Button"); 
button.setAction(new UpdateAction(this)); 
... more button set up 
... add button to views 
... add views to frame 

現在,無論何時點擊按鈕,它都會調用控制器的update()方法。

1

當ControlPanelOne的按鈕被按下時,如何讓ControlPanelOne查看並調用Controller的update()方法?

這通常是通過使用Observer Pattern,其中控制器將寄存器與視圖興趣的實現特定事件發生時被通知,顯示將在適當的時候,呼叫每個註冊方在事件發生時。這樣,視圖不關心控制器,只是它需要生成適當的事件。

+0

你在這裏對觀察者的描述是真實的,但是它不是把過多的代碼放在視圖中,因爲它現在關心的是特定的事件嗎?如果您有各種鍵綁定,按鈕和鼠標事件等,將其放入視圖中以便通知控制器的靈活性較低。我寫這些觀點時,只是畫出它負責的對象(簡單地去吧。繪製(克))。它會監聽控制器的變化(例如玩家移動)和重繪()。您的好處是您可以根據遊戲狀態來改變行爲,視圖也不應該知道。 – ChiefTwoPencils

+0

我見過人們試圖強制Swing進入純粹的MVC,但Swing已經是MVC的一種形式。相反,我允許視圖是「所需要的」,並且在視圖和控制器之間定義一個關於它們預期提供的預期功能的契約,這樣,我可以以任何我想要的方式更改視圖只要它確認了該觀點的預期合同。爲什麼視圖需要了解控制器?實際上,我在Swing中編寫MVC的方式中,視圖和模型完全不瞭解控制器,它們只是生成控制器響應的事件 – MadProgrammer

+0

視圖的責任是表示模型的狀態(通過提供給它通過控制器),所以視圖現在可以自由地以任何方式執行它,而控制器不關心,所以如果由於某種原因必須改變視圖,我不需要寫一個全新的控制器來支持它。通過這種方法,我完全分離了每一層,因爲它只受到他們定義的合同的約束,我可以單獨替換模型和/或控制器和/或視圖,整個事情繼續工作 – MadProgrammer

相關問題