You can use at least these two design patterns to solve your problem:
Depending on your use case of your application one can be better than other, but both solve the issue of high coupling between objects. The difference between them is that the Observer pattern will introduce "Observer" and "Subject" objects whereas a Mediator will encapsulate the communication between objects. You could combine both patterns for your solution using two interfaces as the following example:
import java.util.*;
public class TestAB {
public static void main(String args[]) {
Mediator messageBus = new Mediator();
ClassA objA = new ClassA();
ClassB objB = new ClassB();
messageBus.register("ClassB", objB);
objA.sendMessage(messageBus, "ClassB", "Hello class B!");
}
}
class ClassA {
public void sendMessage(Mediator bus, String dest, String text) {
// send message to the sendMessage() in class B.
bus.sendMessage(new Message() {
public String getDestination() { return dest; }
public String getText() { return text; }
});
}
}
class ClassB implements Observer {
public void sendMessage(Message msg){
System.out.println("sendMessage from ClassB received: "+ msg.getText());
}
public String getId(){
return "B";
}
public void onMessage(Message msg) {
// listen to message calls from the message bus (Mediator)
sendMessage(msg);
}
}
interface Message {
public String getDestination();
public String getText();
}
interface Observer {
public String getId();
public void onMessage(Message msg);
}
class Mediator {
Map<String, Observer> observerList = new HashMap<String, Observer>();
protected void register(String id, Observer obj) {
observerList.put(id, obj);
}
protected void sendMessage(Message msg) {
Observer obj = observerList.get(msg.getDestination());
obj.onMessage(msg);
}
}
All classes that want to receive messages need to implement the interface Observer, in this case B implements the Observer interface and calls its own "sendMessage" method when some message arrives. Finally we created a TestAB class with the mediator object (message bus) responsible to deliver the messages from A to B objects.
For the sake of simplicity I tried to avoid some refinements on the implementation, if you want to know more about these patterns you can get more information in the following link
https://sourcemaking.com/design_patterns/mediator