Intent/Definition
Derived types must be completely substitutable for their base types.
The Liskov Substitution Principle represents the “L” of the five SOLID Principles of object-oriented programming to write well-designed code that is more readable, maintainable, and easier to upgrade and modify.
Rules of Thumb?
- This principle applies to inheritance hierarchies and is just an extension of the Open Close Principle.
- It means that we must make sure that new derived classes are extending the base classes without changing their original behavior. Basically, derived classes should never do less than their base class.
- If a subtype of the supertype does something that the client of the supertype does not expect, then this is in violation of LSP. Imagine a derived class throwing an exception that the superclass does not throw, or if a derived class has some unexpected side effects. One has to consider that how the client programs are using the class hierarchy. Sometimes code refactoring is required to fix identified LSP violations.
Liskov's Substitution Principle Example
First, let's see "bad" design and implementation.
Bad Code Design
LSP is violated here! Why? Logically WinampMediaPlayer only supports playing audio. So what's wrong with the overriding playVideo method of a super class?
MediaPlayer.java
public class MediaPlayer {
// Play audio implementation
public void playAudio() {
System.out.println("Playing audio...");
}
// Play video implementation
public void playVideo() {
System.out.println("Playing video...");
}
}
VlcMediaPlayer.java
public class VlcMediaPlayer extends MediaPlayer {
}
WinampMediaPlayer.java
public class WinampMediaPlayer extends MediaPlayer {
// Play video is not supported in Winamp player
public void playVideo() {
throw new VideoUnsupportedException();
}
}
VideoUnsupportedException.java
public class VideoUnsupportedException extends RuntimeException {
private static final long serialVersionUID = 1 L;
}
ClientTestProgram.java
public class ClientTestProgram {
public static void main(String[] args) {
// Created list of players
List < MediaPlayer > allPlayers = new ArrayList < MediaPlayer > ();
allPlayers.add(new VlcMediaPlayer());
allPlayers.add(new DivMediaPlayer());
// Play video in all players
playVideoInAllMediaPlayers(allPlayers);
// Well - all works as of now...... :-)
System.out.println("---------------------------");
// Now adding new Winamp player
allPlayers.add(new WinampMediaPlayer());
// Again play video in all players & Oops it broke the program... :-(
// Why we got unexpected behavior in client? --- Because LSP is violated in WinampMediaPlayer.java,
// as it changed the original behavior of super class MediaPlayer.java
playVideoInAllMediaPlayers(allPlayers);
}
/**
* This method is playing video in all players
*
* @param allPlayers
*/
public static void playVideoInAllMediaPlayers(List < MediaPlayer > allPlayers) {
for (MediaPlayer player: allPlayers) {
player.playVideo();
}
}
}
- Refer MediaPlayer.java superclass and its subclasses DivMediaPlayer.java, VlcMediaPlayer.java- Refer ClientTestProgram.java code, before adding "WinampMediaPlayer.java"
- Now WinampMediaPlayer.java is added, in which LSP is violated
- Oops, it broken "ClientTestProgram.java"
Good Code Design
Let's refactor the code to make "good" design using LSP?
- Refer "MediaPlayer.java" super class and its sub class "AudioMediaPlayer.java" having play audio ability
- Refer "VideoMediaPlayer.java" extends "MediaPlayer.java" and adds play video ability
- Refer "DivMediaPlayer.java", "VlcMediaPlayer.java". Both extends "VideoMediaPlayer.java" for play audio and video ability.
- Refer "WinampMediaPlayer.java" which extends "AudioMediaPlayer.java" for play audio ability.
- So client program can substitute "VideoMediaPlayer.java" super type with "DivMediaPlayer.java" or "VlcMediaPlayer.java", but not with "WinampMediaPlayer.java"
Class diagram
MediaPlayer.java
public class MediaPlayer {
// Play audio implementation
public void playAudio() {
System.out.println("Playing audio...");
}
}
DivMediaPlayer.java
public class DivMediaPlayer extends VideoMediaPlayer {
// DivMediaPlayer code goes here
}
VlcMediaPlayer.java
public class VlcMediaPlayer extends VideoMediaPlayer {
// VlcMediaPlayer code goes here
}
VideoMediaPlayer.java
public class VideoMediaPlayer extends MediaPlayer {
// Play video implementation
public void playVideo() {
System.out.println("Playing video...");
}
}
WinampMediaPlayer.java
public class WinampMediaPlayer extends AudioMediaPlayer {
// WinampMediaPlayer code goes here
}
VideoUnsupportedException.java
public class VideoUnsupportedException extends RuntimeException {
private static final long serialVersionUID = 1 L;
}
ClientTestProgram.java
public class ClientTestProgram {
public static void main(String[] args) {
// Created list of video players
List < VideoMediaPlayer > allPlayers = new ArrayList < VideoMediaPlayer > ();
allPlayers.add(new VlcMediaPlayer());
allPlayers.add(new DivMediaPlayer());
// Play video in all players
playVideoInAllMediaPlayers(allPlayers);
// Well - all works as of now...... :-)
System.out.println("---------------------------");
// Now adding new Winamp player. If you uncomment below line,
// it would give compile time error as can't add audio player in list of video players.
// allPlayers.add(new WinampMediaPlayer());
}
/**
* This method is playing video in all players
*
* @param allPlayers
*/
public static void playVideoInAllMediaPlayers(List < VideoMediaPlayer > allPlayers) {
for (VideoMediaPlayer player: allPlayers) {
player.playVideo();
}
}
}
Posts Related to SOLID Principles
- Single Responsibility Principle
- Open Closed Principle
- Liskov's Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
Learn complete Oops concepts and SOLID Principles on Object Oriented Design in Java Tutorial
Learn beginners to expert Core Java on Java Tutorial (300 + Articles)
You can find all the top tutorials of this site on Java/J2EE Tutorials on JavaGuides
Free Spring Boot Tutorial | Full In-depth Course | Learn Spring Boot in 10 Hours
Watch this course on YouTube at Spring Boot Tutorial | Fee 10 Hours Full Course
Comments
Post a Comment