Facade design pattern: Facade design pattern provides structured way of designing a system by encapsulating sequence of operations required for business operation into a single interface.
In a complex system, performing a business operation would require interacting with different modules of the system, by calling method on each of the different module in a particular sequence. The facade design patterns abstracts all the interaction with different modules into a single simplified method.In simple words a single interface to perform multi-step process. So the client or the user has to only use this simplified method or interface to perform the business operation and the method/interface will internally take care of calling methods / steps on different modules.
This way Facade Pattern defines a higher-level interface that makes the subsystem or sub modules easier to use.
How to use: Lets take an example of music player.
In a typical mp3 music player system, to play mp3 music, the system has to interact with different modules like
- File loader module to load the file from the source
- The decoder module to decode the music file
- Sound module to output the sound
- player module to stream the decoded music file and to update the gui with the title and duration of the music..
Player.java
public class Player {
private SoundSystem sound;
public void init() {
sound = new SoundSystem();
}
public void startStreaming(byte[] stream) {
// Start streaming
}
public void showTitle(String title) {
// Update gui with the title of the song
}
public void showDuration(int duration) {
// update gui with the duration of the song
}
}
private SoundSystem sound;
public void init() {
sound = new SoundSystem();
}
public void startStreaming(byte[] stream) {
// Start streaming
}
public void showTitle(String title) {
// Update gui with the title of the song
}
public void showDuration(int duration) {
// update gui with the duration of the song
}
}
The Player class depends on the following modules to play a music mp3 file.
public class FileLoader {
public File loadFile(String fileName) {
return new File(fileName);
}
}
public class Decoder {
public byte[] decode(File musicFile) {
// decode the file and return byte array
return null;//return decoded bytes here
}
}
public class SoundSystem {
public void setVolume(int level) {
//set the volume level
}
}
Problem: Without facade pattern, to play mp3 music file, the client has to understand the interfaces of all modules and understand the sequence in which it has to use the module before playing the music file.
A tipical MusicClient class implementation may look like as shown here.
MusicClient.java
public class MusicClient{
public static void main(String args[]) {
FileLoader loader = new FileLoader();
File musicFile = loader.loadFile("test.mp3");
Decoder decoder = new Decoder();
byte[] stream = decoder.decode(musicFile);
Player player = new Player();
player.init();
player.startStreaming(stream);
player.showTitle("New Song");
player.showDuration(15);
}
}
public static void main(String args[]) {
FileLoader loader = new FileLoader();
File musicFile = loader.loadFile("test.mp3");
Decoder decoder = new Decoder();
byte[] stream = decoder.decode(musicFile);
Player player = new Player();
player.init();
player.startStreaming(stream);
player.showTitle("New Song");
player.showDuration(15);
}
}
The class diagram relation ship can be shown as below
Here you can see player client is calling methods on multiple modules one by one. So each time we need to play a song we need to repeat all these steps as shown in main method of PlayerClient. Think of playing multiple songs, then see how the above code will grow in main method.
Solution:All these operations can be abstracted out by providing a Music Player facade with a simple play method. The client has to only use a single simplified interface to play a music file. After applying facede pattern, the new class diagram may look like as shown below
Applying facade:To apply facade pattern, create a MusicPlayerFacade class and give all responsibility to it.
MusicPlayerFacade.java
public class MusicPlayerFacade {
private Player player = new Player();
private FileLoader loader = new FileLoader();
//giving all responsibility to this single method
public void play(String fileName) {
File musicFile = loader.loadFile(fileName);
Decoder decoder = new Decoder();
byte[] stream = decoder.decode(musicFile);
player.init();
player.startStreaming(stream);
player.showTitle(fileName);
player.showDuration(15);
}
}
private Player player = new Player();
private FileLoader loader = new FileLoader();
//giving all responsibility to this single method
public void play(String fileName) {
File musicFile = loader.loadFile(fileName);
Decoder decoder = new Decoder();
byte[] stream = decoder.decode(musicFile);
player.init();
player.startStreaming(stream);
player.showTitle(fileName);
player.showDuration(15);
}
}
Now changing the MusicClient class to make use of MusicPlayerFacade class.
MusicClient.java
public class MusicClient{
public static void main(String args[]) {
MusicPlayerFacade player = new MusicPlayerFacade ();
player.play("test.mp3");
}
}
public static void main(String args[]) {
MusicPlayerFacade player = new MusicPlayerFacade ();
player.play("test.mp3");
}
}
If you use facade you can easily play multiple songs just calling
player.play("test2.mp3");
player.play("abcd.mp3");
player.play("abcd.mp3");
nice post!
ReplyDelete