Özetle ISP, sorumlulukları bir arada toplanmış ve gereksiz kodlara neden olacak interface’ler oluşturmak yerine özelleştirilmiş ve gereksiz kod’a neden olmayacak interface’ler tanımlamamız gerektiğini söyleyen prensiptir.
Genel maksatlı interfaceleri parçalayarak daha özel boyuta indirmemiz gerekmektedir. Bu şekilde nesnelere ihtiyacı olmayan property veya metot içeren interface’i implemente etmemeiş olacağız.
Single Responsibility Principle ile oldukça benzer olan Interface Segration Principle aralarında bir bulunuyor. SRP sınıflar ile ilgilenirken ISP ise interface’ler ile ilgilenir.
Örnek:
Futbol oyununda hem kaleci(goalkeeper) hem de forvet (striker) birer oyuncudurlar. Bu gerçeğin oop’de class’lara dökülmesi ise şu şekilde olurdu:
Ortak özellikleri barındıracak ve ata klasımız olan Player sınıfımızı oluşturduk.
public interface IPlayer
{
void KickBall();
void KeepBall();
}
Mevki klaslarımızı oluşturduk ve ata sınıfımızdan miras aldık.
public class Goalkeeper : IPlayer
{
public void KeepBall()
{
//Operations
}
public void KickBall()
{
//Operations
}
}
public class Striker : IPlayer
{
public void KeepBall()
{
throw new System.NotImplementedException();
}
public void KickBall()
{
//Operations
}
}
Günün sonunda istediğimizi yapdık ve çalışmaya devam edebiliriz ancak burada prensiplere uymayan bir sorunumuz var. ‘Player’ içerisinde ‘Striker’ sınıfının kullanamayacağı bir ortak özellik bulunuyor. Kalece şut çekebilir veya top tutabilir ancak forvet şut çekebilir olsada top tutamaz. Bundan dolayı buradaki ortak özellik diğer mevkilerle uyumlu olsa dahi ‘Striker’ sınıfı için gereksiz kod barındırmaktadır. Buda ISP prensibine aykırıdır. Bu problemden kurtulmak için daha fazla özelleştirme yapacağız. Ortak özellikleri büyük çatılar altına almaktansa çatıyı dar tutup class sayısını arttırmak daha iyidir.
ISP ile çözersek:
‘IPlayer’ sınıfımızda yalnızca tüm mevkilerin birden kullandığı özellikleri tuttuk. Diğer mevkilerin ortak özellikleri için ‘IGoalkeeper’ isimli class’a gerekli özellikleri tanımlayıp özelliği kullanmasını istediğimiz class’a ata class olarak verdik. Böylelikle ‘Striker’ sınıfı sadece ‘IPlayer’ sınıfından ‘Goolkeeper’ sınıfı ise ‘IPlayer’ ve ‘IGoolkeeper’ sınıfından miras alarak gereksiz kod yükünden kurtulup ortak özellikleri bu şekilde ISP’ye uyarak kullandık.
public interface IPlayer
{
void KickBall();
}
public interface IGoalkeeper
{
void KeepBall();
}
public class Goalkeeper : IPlayer, IGoalkeeper
{
public void KeepBall()
{
//Operations
}
public void KickBall()
{
//Operations
}
}
public class Striker : IPlayer
{
public void KickBall()
{
//Operations
}
}