简体   繁体   中英

Best Practices to avoid Dependencies between Java Classes in a certain case?

I spend too much time on figuring out how to avoid dependencies between classes. Maybe there are some best practices which you guys elaborated?

To explain what I mean let's assume the following:

  1. I have a JPanel "topPanel" containing a JTextField "textField" and a custom Panel JCustomPanel "customPanel"
  2. Let's say, the JCustomPanel simply has two JButtons "button1" and "button2", which can be pressed to change the textField.

And this is where the pain starts. As long as I don't want the button1 and button2 to interact with the textField, I have a nicely independent JCustomPanel Class, which I could use just everywhere. What would be the best way to edit the textField? I would prefer solutions where the JCustomPanel does not need to know anything about it's topPanel.

Update to the question:

My question received very good answers and I feel that the MVC-Pattern might really be a powerful solution to my question. Where I'm still having difficulties is how to realize the MVC-Pattern in my code. The answers seem to suggest different approaches, so I'm going to post some code to get the best implementation of the MVC-Pattern.

public class JTopPanel extends JPanel {

  private JTextField textField;
  private JCustomPanel customPanel;
  private boolean myBool = true;

  public JTopPanel() {

   super();
   this.setLayout(new BorderLayout(5,5));     
   textField = new JTextField("0", 15);
   textField.setEditable(false);
   customPanel = new JCustomPanel();
   this.add(BorderLayout.NORTH, textField);
   this.add(BorderLayout.CENTER, customPanel);

 } // Constructor JTopPanel
} // Class JTopPanel

And now the JCustomPanel Class:

public class JCustomPanel extends JPanel {

private JButton button1, button2;

public JCustomPanel() {
    super();
    this.setLayout(new FlowLayout(FlowLayout.TRAILING, 1, 1));
    button1 = new JButton("1");
    button2 = new JButton("2");
    this.add(button1);
    this.add(button2);
    button1.addActionListener( ... ); // change textField from JTopPanel
    button2.addActionListener( ... ); // change textField from JTopPanel
    } // Constructor JCustomPanel
 } // Class JCustomPanel

Thanks!

Separate the model and view side.

Your textfield would then display a certain value of the model. Pressing button 1 or 2 would update the model instead of directly updating the textfield.

Each of the views is responsible to react on model updates. In the above example, the textfield should get updated when the value is changed in the model. It is important to note here that the view does not care who is updating the model. It has no knowledge of button1/2 . It just detects an update to the model, and reacts accordingly.

This does not remove all dependencies. You end up with a dependency between the view classes (both panels) and the model. However, the ugly dependency between the two view classes has been removed.

More info can be found on eg Wikipedia in the Model-view-controller and Model-view-presenter articles.

In this case ("where the JCustomPanel does not need to know anything about it's topPanel") the "topPanel" should register ActionListener to the buttons of "customPanel" because it is your "textField" that wants to change when the buttons are pressed.

JCustomPanel should have accessor methods like getButton1() and getButton2() which could be used to access them and register action listeners appropriately. JCustomPanel in this case will remain independent of the surrounding world.

General answer: Check out the Model-View-Controller pattern (or similar design patterns) to decouple interface components: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

A more specific answer:

Introduce a "controller" class that implements an interface eg ActionListener.

Register the controller class with your buttons (button1.addActionListener(myController)).

implement the interface in the controller (eg actionPerformed) to handle

see http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html

The code you want to execute when pressing button1 or button2 depends on components outside the responsability of the JCustomPanel. In that case you can define an interface like

public interface OnButtonClickListener {
   public void onClick(int buttonnumber);
}

In your JCustomPanel add a method to pass an implementation of this interface:

  public class JCustomPanel {
    private OnButtonClickListener listener;

    public void setOnButtonClickListener(OnButtonClickListener listener) {
      this.listener=listener;
    }
    // .. the rest of the class
  }

Also in you JCustomPanel create listeners for the 2 buttons and in this call the listener.OnClick() method;

This way the JCustomPanel has no hard dependencies with its outer context.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM