Dependency Inversion Principle (Bağımlılığı Tersine Çevirme İlkesi)
Bu yazımızda, SOLID ilkelerinin “D” harfi ile temsil edilen üyesi “Dependency Inversion Principle” kavramına odaklanacağız.
“Dependency Inversion Principle” (DIP) Nedir?
Robert C. Martin, “Dependency Inversion” olarak adlandırdığı ilkesiyle, yüksek seviyeli modüllerin düşük seviyeli modüllere doğrudan bağlı olmaması gerektiğini belirtmektedir.
“Dependency”, programlama bağlamında, bir modülün veya sınıfın işlevselliğini yerine getirebilmesi için başka bir modüle veya sınıfa ihtiyaç duyması anlamına gelir. Yani, bir kod parçasının başka bir koddan gelen veriye, işlevselliğe veya davranışa bağlı olması durumudur.
“Inversion” ise “tersine çevirme” anlamına gelmektedir ve bu bağlamda, geleneksel bağımlılık ilişkisinin tersine çevrilmesini ifade eder. Zira geleneksel olarak, yüksek seviyeli modüller düşük seviyeli modüllere bağımlı olmaktadır.
Bir bütün olarak “dependency inversion” kavramına baktığımızda ise bu ilişki tersine çevrilmektedir: Yüksek seviyeli modüller ve düşük seviyeli modüller artık doğrudan birbirlerine bağlı değildir; bunun yerine her ikisi de ortak bir soyutlamaya (abstract sınıflar veya interfaceler) bağlanır.
“Bağımlılığı Tersine Çevirme İlkesi” olarak Türkçeye çevireceğimiz bu kavram bize yüksek seviyeli modüllerin düşük seviyeli modüllere doğrudan bağlı olmaması gerektiğini belirtir ve iki temel kural içermektedir:
- Yüksek Seviye Modüllerin Düşük Seviye Modüllere Bağımlılığı Olmamalıdır: Bu kural, yüksek seviye iş mantığının, düşük seviye iş mantığının detaylarına bağımlı olmaması gerektiği anlamına gelir. Bunun yerine, her ikisi de soyutlamalara bağımlı olmalıdır.
- Soyutlamalar Detaylara Bağımlı Olmamalıdır: Detaylar (düşük seviyeli işlevsellik), soyutlamalara (genel işlevsellik) bağlı olmalıdır. Haliyle, sistem tasarımında esneklik artacak ve bu da modüller arasındaki bağımlılığı azaltacaktır.
Bunu şöyle bir örnekle açıklayabiliriz: Diyelim ki bir okulunuz var ve bu okulda çeşitli etkinlikler için bir takvim kullanıyorsunuz. Bu etkinlikler spor günleri, sanat gösterileri, bilim fuarları gibi çeşitli aktiviteleri içeriyor olsun. Eğer okulunuzun etkinlik takvimi (yüksek seviyeli modül), belirli bir etkinlik türüne (örneğin, sadece spor etkinliklerine – düşük seviyeli modül) bağlıysa, bu durumda diğer etkinlik türlerini takvime eklemek zor olur. Yani, eğer takvim sadece futbol maçlarını planlıyorsa ve birdenbire bir sanat gösterisi düzenlemek isterseniz, bu yeni etkinliği takvime uyumlu hale getirmek çetrefilli bir hale gelecektir.
İşte bağımlılığı tersine çevirmesi burada devreye girer ve der ki, “Takviminizi belirli bir etkinlik türüne değil, genel bir ‘etkinlik planlama’ soyutlamasına bağlayın.” Bu durumda, okulunuzun etkinlik takvimi çeşitli etkinlik türleri için esnek olur ve futbol maçları, sanat gösterileri, bilim fuarları gibi farklı etkinlik türlerini kolaylıkla planlayabilirsiniz.
Bu örneğimizi Python kullanarak aşağıdaki gibi kodlayabiliriz. İlk olarak “Dependency Inversion Principle” kullanmadan nasıl bir şey olduğunu gösterelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class FootballMatch: def get_event_date(self): # Futbol maçının tarihini döndürür return "2023-12-10" class ArtShow: def get_event_date(self): # Sanat gösterisinin tarihini döndürür return "2023-12-15" class SchoolCalendar: def __init__(self): self.events = [] def add_football_match(self, match): self.events.append(match.get_event_date()) def add_art_show(self, show): self.events.append(show.get_event_date()) # Kullanımı calendar = SchoolCalendar() calendar.add_football_match(FootballMatch()) calendar.add_art_show(ArtShow()) print(calendar.events) |
Yukarıdaki kodumuzda, SchoolCalendar
sınıfı FootballMatch
ve ArtShow
gibi spesifik etkinlik türlerine doğrudan bağımlıdır. Eğer yeni bir etkinlik türü eklemek istersek, SchoolCalendar
sınıfını değiştirmemiz gerekecektir. Bunu önlemek için “Dependency Inversion Principle” uygulayabiliriz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
from abc import ABC, abstractmethod class Event(ABC): @abstractmethod def get_event_date(self): pass class FootballMatch(Event): def get_event_date(self): return "2023-12-10" class ArtShow(Event): def get_event_date(self): return "2023-12-15" class SchoolCalendar: def __init__(self): self.events = [] def add_event(self, event: Event): self.events.append(event.get_event_date()) # Kullanımı calendar = SchoolCalendar() calendar.add_event(FootballMatch()) calendar.add_event(ArtShow()) print(calendar.events) |
Bu kodda ise, SchoolCalendar
sınıfı artık spesifik etkinlik türlerine değil, Event
soyutlamasına (interfase) bağımlıdır. Yeni bir etkinlik türü eklemek istediğimizde, sadece Event
arayüzünü uygulayan yeni bir sınıf oluşturmamız yeterlidir, bu sayede SchoolCalendar
sınıfını değiştirmemize gerek kalmaz.