Tight Coupling and Loose Coupling In Java
If you are quite familiar with Java and moving towards Spring Framework or you want to get an idea of a loosely-coupled and tightly-coupled system from a programming perspective or you want to add a bit more knowledge to your mental knowledge repository, then we are good to go.
What are tightly and loosely coupled systems?
Briefly, tightly coupled means a system in which the components are dependent on each other. It reduces the flexibility of a system and swapping a component for another is very difficult. Loosely-coupled systems are those where components are not dependent on each other and the components can be swapped with ease. So, how do we achieve loose coupling in Java?
How do we implement loose coupling in Java?
We achieve this in Java by creating a superior interface. All other classes will implement this interface to define the methods. It's like android apps for Android software and iOS apps for iOS. Now finally we need a runner class that will instantiate the games and the object of this runner class will be used to run the games from the main class. This might seem a bit overwhelming but stick till the end and you will get the picture.
Tight-coupling Coding Implementation
In the below example, we consider creating a gaming device that will run 2 games: Super Mario and Super Contra. If we implement this in Java, the code will be:
public class SuperMario {
public void up() { System.out.println("Super Mario: up"); }
public void down() { System.out.println("Super Mario: down"); }
public void left() { System.out.println("Super Mario: left"); }
public void right() { System.out.println("Super Mario: right"); }
}
public class SuperContra {
public void up() { System.out.println("Super Contra: up"); }
public void down() { System.out.println("Super Contra: down"); }
public void left() { System.out.println("Super Contra: left"); }
public void right() { System.out.println("Super Contra: right"); }
}
public class GameRunner {
private SuperMario game;
public GameRunner(SuperMario game) {
this.game = game;
}
public void run() {
game.up();
game.down();
game.left();
game.right();
}
}
public class GamingDevice {
public static void main(String[] args) {
SuperMario game = new SuperMario();
GameRunner runner = new GameRunner(game);
runner.run();
}
}
Now the problem with the above implementation is that in the GameRunner
class, the object is strictly set as a SuperMario
object. So, currently, it seems like our device can only run(tightly coupled) the SuperMario game. What I mean is, if we try to run the below code in my GamingDevice
class, we will get an error.
public class GamingDevice {
public static void main(String[] args) {
SuperContra game = new SuperContra();
GameRunner runner = new GameRunner(game);
runner.run();
}
}
But a device running one game is not ideal, right? Our device is supposed to run many games.
To summarize the scenario, our device can currently run only one game now i.e. Super Mario, but we want it to be able to run both Super Mario and Super Contra. So, how do we fix our device?
We fix it by installing a Gaming Software(interface) in our Gaming Device that can run both games. So, rather than running the game directly on the device, our device will be able to run the gaming software which supports both games.
So, our new implementation goes like this:
Loose-coupling Coding Implementation
public interface GamingSoftware {
public void up();
public void down();
public void left();
public void right();
}
public class SuperMario implements GamingSoftware {
public void up() { System.out.println("Super Mario: up"); }
public void down() { System.out.println("Super Mario: down"); }
public void left() { System.out.println("Super Mario: left"); }
public void right() { System.out.println("Super Mario: right"); }
}
public class SuperContra implements GamingSoftware {
public void up() { System.out.println("Super Contra: up"); }
public void down() { System.out.println("Super Contra: down"); }
public void left() { System.out.println("Super Contra: left"); }
public void right() { System.out.println("Super Contra: right"); }
}
public class GameRunner {
private GamingSoftware game;
public GameRunner(GamingSoftware game) {
this.game = game;
}
public void run() {
game.up();
game.down();
game.left();
game.right();
}
}
public class GamingDevice {
public static void main(String[] args) {
SuperMario superMario = new SuperMario();
SuperContra superContra = new SuperContra();
GameRunner marioRunner = new GameRunner(superMario);
GameRunner contraRunner = new GameRunner(superContra);
marioRunner.run();
contraRunner.run();
}
}
Now, our both games will run perfectly. So, what we achieved here is a loosely-coupled system or gaming device which will be able to run any game that the Gaming Software supports(i.e. the game is implemented using the GamingSoftware interface).
So, this is the difference between tightly-coupled and loosely-coupled systems in Java and the difference between their implementations. If you found this article helpful, a like would be appreciated :)