Interface Segregation Principle
- Clients should not be forced to depend on interface/methods they do not use.
- The main idea behind ISP is to prevent the creation of "fat" or "bloated" interfaces that include methods that are not required by all clients.
- Encourages creation of smaller, focused interfaces
Example 1
Problem
internal interface IMediaPlayer
{
void PlayAudio();
void StopAudio();
void AdjustAudioVolume();
void PlayVideo();
void StopVideo();
void AdjustVideoBrightness();
}
internal class MP3Player : IMediaPlayer
{
public void PlayAudio()
{
Console.WriteLine("play audio");
}
public void StopAudio()
{
Console.WriteLine("Stop audio");
}
public void AdjustAudioVolume()
{
Console.WriteLine("Adjust audio volume");
}
public void PlayVideo()
{
throw new NotImplementedException();
}
public void StopVideo()
{
throw new NotImplementedException();
}
public void AdjustVideoBrightness()
{
throw new NotImplementedException();
}
}
internal class AviVideoPlayer : IMediaPlayer
{
public void PlayAudio()
{
throw new NotImplementedException();
}
public void StopAudio()
{
throw new NotImplementedException();
}
public void AdjustAudioVolume()
{
throw new NotImplementedException();
}
public void PlayVideo()
{
Console.WriteLine("Play video");
}
public void StopVideo()
{
Console.WriteLine("Stop video");
}
public void AdjustVideoBrightness()
{
Console.WriteLine("Adjust video brightness");
}
}
Solution
internal interface IAudioPlayer
{
void PlayAudio();
void StopAudio();
void AdjustAudioVolume();
}
internal interface IVideoPlayer
{
void PlayVideo();
void StopVideo();
void AdjustVideoBrightness();
}
internal class MP3Player : IAudioPlayer
{
public void PlayAudio()
{
Console.WriteLine("play audio");
}
public void StopAudio()
{
Console.WriteLine("Stop audio");
}
public void AdjustAudioVolume()
{
Console.WriteLine("Adjust audio volume");
}
}
internal class AviVideoPlayer: IVideoPlayer
{
public void PlayVideo()
{
Console.WriteLine("Play video");
}
public void StopVideo()
{
Console.WriteLine("Stop video");
}
public void AdjustVideoBrightness()
{
Console.WriteLine("Adjust video brightness");
}
}
Example 2
Problem
- Initially you think that the application will accept only online payments through credit cards.
IOrderProcessor {
ValidateCardInfo()
ValidateShippingAddress()
ProcessOrder()
}
public class OnlineOrderProcessor: IOrderProcessor {}
- The company decides to accept cash-on-delivery payments in select locations.
public class CashOnDeliveryOrderProcessor: IOrderProcessor
{
ValidateCardInfo() {
throw new NotImplementedException();
}
}
- The cash-on-delivery mode of purchase won’t involve any credit, card at all, so the ValidateCardInfo() method inside the CashOnDeliveryOrderProcessor class throws a NotImplementedException.
- Online credit card–based payment needs extra validation steps. IOrderProcessor will be modified to include those extra methods, and OnlineOrderProcessor will implement those additional methods. However, even though CashOnDeliveryOrderProcessor doesn’t need any of the additional functionality, you must implement these newly added methods in it (and throw NotImplementedException ).
- In other words, CashOnDeliveryOrderProcessor is forced to change because of the methods it doesn’t need. This is in violation of ISP. Also notice that after throwing the NotImplementedException from these methods, the CashOnDeliveryOrderProcessor violates LSP.
Solution
- Split the required operations into two interfaces— IOrderProcessor and IOnlineOrderProcessor .
IOrderProcessor {
ValidateShippingAddress()
ProcessOrder()
}
IOnlineOrderProcessor {
ValidateCardInfo()
}
public class OnlineOrderProcessor: IOrderProcessor,IOnlineOrderProcessor {}
public class CashOnDeliveryOrderProcessor: IOrderProcessor {}