Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Communication between several classes

Whenever I make a program I tend to divide different sections in different files, I think it looks more neat that way. To make the problem more concrete say I have this dummy code consisting of four classes,

public class dummy {
    public static void main(String[] args){
        Alpha a = new Alpha();
        Beta b = new Beta();
        Gamma g = new Gamma();

        int x,y,z,j,k,l,o,p,q;

        x = a.getGammaX();
        y = b.getGammaX();
        z = g.getX();

        a.setGammaX(1);

        j = a.getGammaX();
        k = b.getGammaX();
        l = g.getX();

        b.setGammaX(2);

        o = a.getGammaX();
        p = b.getGammaX();
        q = g.getX();
        }
    }

class Alpha{
    Gamma g = new Gamma();
    public int getGammaX(){
        return g.getX();
    }

    public void setGammaX(int x){
         g.setX(x);
    }
}

class Beta{
    Gamma g = new Gamma();
    public int getGammaX(){
        return g.getX();
    }

    public void setGammaX(int x){
        g.setX(x);
    }
}

class Gamma{
    int x = 10;

    public int getX(){
        return x;
    }
    public void setX(int y){
        x = y;
    }
}

The Alpha and Beta classes communicate with the Gamma. The purpose of the integers is to print out their values and compare them with each other after the setters have been called from the different classes. A general problem I have when I split the sections is that when one class change the values in Gamma, the other classes have obsolete values, the x,y,z variables will still have the old values of x in Gamma when a setter method has been called, unless I discover this before spending quite some time finding it.

I tend to circumvent this by passing around one reference of the Gamma class,

Gamma g = new Gamma();
Alpha a = new Alpha(g);
Beta b = new Beta(g);

like so, and spend several lines of code to update everything. Where the reference is being created from the "main" class, where "main" is not necessarily the class with the main method, but the class where the most action is.

The question I have is, is there a standard way of dealing with this kind of problem, where multiple classes communicate with one other class, changing values etc. and ending up with obsolete values?

My problems tend to be more subtle than what is shown but essentially this is what I tend to spend some time on trying to fix. I am sorry if the explanation is muddy, I had a hard time to make the problem this clear, if it is too incomprehensible, write in the comments where and I will try to clear it a bit more clearer.

like image 963
Fox Mulder Avatar asked Jul 04 '14 18:07

Fox Mulder


2 Answers

Use the MVC (model-view-control) pattern or one of its variants, and have classes that need to hold the same data share a model. For instance perhaps Gamma is your model, then have the other classes share the same Gamma instance.

e.g.,

public class Dummy {
   public static void main(String[] args) {
      Gamma g = new Gamma();

      Alpha a = new Alpha(g);
      Beta b = new Beta(g);

      // .........


   }
}

class Alpha {
   private Gamma g;

   public Alpha(Gamma g) {
      this.g = g;
   }

   public int getGammaX() {
      return g.getX();
   }

   public void setGammaX(int x) {
      g.setX(x);
   }
}

class Beta {
   // Gamma g = new Gamma();
   private Gamma g;

   public Beta(Gamma g) {
      this.g = g;
   }

   public int getGammaX() {
      return g.getX();
   }

   public void setGammaX(int x) {
      g.setX(x);
   }
}

class Gamma {
   int x = 10;

   public int getX() {
      return x;
   }

   public void setX(int y) {
      x = y;
   }
}

To have have classes notified of state changes on another class, then use, use an observer pattern as recommended by JohnB.


Note that one way to gain observer support is to use JavaBean's PropertyChangeSupport. For example:

class Gamma {
   public static final String X = "x";
   private PropertyChangeSupport support = new PropertyChangeSupport(this);

   private int x = 10;

   public int getX() {
      return x;
   }

   public void setX(int x) {
      int oldValue = x;
      int newValue = this.x;
      this.x = x;
      support.firePropertyChange(X, oldValue, newValue);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      support.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      support.removePropertyChangeListener(listener);
   }
}

Note: probably the nicest and cleanest way to inject the A and B classes with a shared Gamma class is via dependency injection such as available from one of Spring's modules or from the Guice framework.

like image 70
Hovercraft Full Of Eels Avatar answered Nov 11 '22 21:11

Hovercraft Full Of Eels


The standard way of dealing with this is the so-called observer pattern.

You should make sure that there is only one instance of Gamma, as otherwise you have to make sure all instances are synchonized.

a and b ask g to be registered as observers. g notifies all its observers of a change of its state.

class Gamma extends Observable {
    int x = 10;

    public int getX(){
        return x;
    }
    public void setX(int y){
        x = y;
        notifyObservers (null);
    }
}

class Alpha implements Observer {
    // ...

    public Alpha (Gamma g) {
       g.addObserver (this);
    }

    public void update(Observable o, Object arg) {
       // this method gets called by g whenever g's state changes
       // do necessary updates here
       // ...
    }
 }
like image 44
JohnB Avatar answered Nov 11 '22 22:11

JohnB