Herkese merhaba, SOLID yazılarıma dördüncü eleman Interface Segregation Prensibi ile devam ediyorum. Interface Segregation Principle (ISP), ‘bir sınıf kullanmadığı metotlara bağımlı olmaya zorlanmamalıdır’ der. Özetle; tek bir genel amaçlı interface (arayüz) yerine, istemcinin sadece ihtiyacı olan metotlara ve özelliklere erişebileceği interface (arayüz)’lere bölünmesidir. Bu sayede kullandığımız yapıya esneklik, clean code ve low coupling (düşük bağımlılık) kazandırmış oluruz.
Interface Segregation Nedir?
Bazen sistemler o kadar farklı seviyelerde birbirine bağımlı olur ki ufak bir değişiklik bütün kod içerisinde değişiklik yapılmasına neden olur. Interface segregation bu bağımlılığın azaltılmasına ve yapıya esneklik kazandırılmasına yardımcı olur.

Yukarıdaki örnekteki gibi bir dönüştürücümüz olduğunu varsayalım. Yeni tipte bir dönüştürücü eklememiz gerektiğinde, ana dönüştürücüde değişiklik yapmamız gerekecek. Bu değişiklik mevcuttaki dönüştürücüleri de etkileyeceği için yüksek bağımlılığa (coupling) neden olabilir. Bu yüzden dönüştürücülerin spesifik ve küçük parçalara bölünmüş olması kodun bakımını kolaylaştırdığı gibi okunabilir olmasını da sağlar.
Ayrıca kullandığımız bu yapıyı 3rd party bir uygulama olarak dışarıya verdiğimizi düşünelim. Telefonunu şarj etmek isteyen birisi neden yanında USB kablosu taşıdığını düşünebilir. Kullanıcı ihtiyacı olmayan bir özelliğe zorlanmamalı. Daha uç bir senaryoda bu şekilde bir kullanım güvenlik açığı da oluşturabilir.
public interface IChargeAdaptor
{
void ChargePhone();
void TransferData();
void WirelessCharge();
}
public class Devices
{
public class Iphone : IChargeAdaptor
{
public void ChargePhone()
{
Console.WriteLine("Charging iPhone...");
}
public void TransferData()
{
Console.WriteLine("Transferring data from iPhone...");
}
public void WirelessCharge()
{
Console.WriteLine("Wireless charging iPhone...");
}
}
public class Mp3Player : IChargeAdaptor
{
public void ChargePhone()
{
Console.WriteLine("Charging MP3 Player...");
}
public void TransferData()
{
Console.WriteLine("Transferring data from MP3 Player...");
}
public void WirelessCharge()
{
//Bir sınıfın implement etmek zorunda olduğu ama desteklemediği metotlarda NotImplementedException fırlatması, tasarımın yanlış olduğuna işarettir.
throw new NotImplementedException("This device does not support wireless charging.");
}
}
}
IChargeAdaptor interface’ini iki cihaza da sorunsuz bir şekilde implement ettik. Ancak Mp3Player sınıfı hiç kullanmadığı bir yeteneğe bağımlı hale geldi. İleride kablosuz şarj metodu üzerinde bir değişiklik yapılırsa, MP3 çalar kodunu da güncellememiz gerekecek. Daha iyi bir tasarımda bu özelliklerin hepsini bir yetenek olarak ele almalıyız.
public interface IChargeable
{
void Charge();
}
public interface IDataTransferable
{
void TransferData();
}
public interface IWirelessChargeable
{
void WirelessCharge();
}
public class Iphone : IChargeable, IDataTransferable, IWirelessChargeable
{
public void Charge()
{
Console.WriteLine("Charging iPhone...");
}
public void TransferData()
{
Console.WriteLine("Transferring data from iPhone...");
}
public void WirelessCharge()
{
Console.WriteLine("Wireless charging iPhone...");
}
}
public class Mp3Player : IChargeable, IDataTransferable
{
public void Charge()
{
Console.WriteLine("Charging MP3 Player...");
}
public void TransferData()
{
Console.WriteLine("Transferring data from MP3 Player...");
}
}
Interface’i mantıklı parçalara bölerek, her cihazın ihtiyacı olan yeteneği kullanmasını sağlıyoruz. Bu sayede projemize esneklik, okunabilirlik ve bakım kolaylığı sağladık. Bir sonraki fazlarda hızlı şarj özelliği eklenmesi gerekirse IFastCharge interface’ini oluşturmamız yeterli olacaktır.
Interface ile kazandırdığımız özellikleri abstract class ile de kazandırabilirdik. C#’ta bir sınıf yalnızca tek bir base class’tan türeyebilir ancak birden fazla interface implement edebilir. OOP içerisinde interface yapısı katmanlar sağladığı için kodu basitleştirir. Aynı zamanda bağımlılıkların azaltılması için bariyer oluşturur.
Son olarak ISP’yi 3 özellik ile özetlememiz gerekirse;
- Unused dependency’yi engellemek
- Coupling’i azaltmak
- Test edilebilirliği artırmak
Bu yazıdaki örneklere github repomdan erişim sağlayabilirsiniz. Bir sonraki yazımda Dependency Inversion Principle inceleyeceğim. Bir sonraki yazıya kadar kendinize çok iyi bakın! 😊