SOLID - Dependency Inversion Principle
4 Eylül 2022 • ☕️ 4 dk okuma • 🏷 bilgisayar, yazılım
Yazar tarafından şu dillere çevrildi: English
Dependency Inversion Prensibi (DIP), nesne yönelimli programlama (OOP) prensiplerinden biridir. DIP, yazılım geliştirme sürecinde, birbirine bağımlı sınıfların oluştuğu ve bu sınıfların birbiriyle sıkı bir şekilde ilişkili olduğu durumlarda, bu bağımlılıkların tersine çevrilmesini ve bağımlılıkların daha az sıkı hale getirilmesini önerir. Bu prensip, sınıfların daha az bağımlı hale getirilmesini ve böylece daha esnek ve yeniden kullanılabilir hale gelmesini sağlar.
DIP, aynı zamanda SOLID prensiplerinin “D” harfini ifade eder. Prensipte, bir üst seviyedeki modül, alt seviyedeki modüle doğrudan bağımlı olmamalıdır. Bunun yerine, üst seviyedeki modül, alt seviyedeki modüle bağımlılığı tersine çevirmeli ve bu modüller arasında bir arayüz sağlamalıdır. Bu sayede, alt seviyedeki modüllerin uygulaması değişse bile üst seviyedeki modülün değiştirilmesi gerekmez.
DIP, kodun bakımı ve test edilebilirliği açısından da önemlidir. Bağımlılıkların tersine çevrilmesi, bir sınıfın değiştirilmesi gerektiğinde, diğer sınıfların etkilenmemesini sağlar. Bu, kodun yeniden kullanılabilirliğini artırır ve bakım maliyetlerini azaltır.
PHP’de, Dependency Inversion prensibini uygulamak için aşağıdaki gibi bir örnek verilebilir:
interface EmailSenderInterface {
public function sendEmail($to, $subject, $message);
}
class EmailSender implements EmailSenderInterface {
public function sendEmail($to, $subject, $message) {
// ... e-posta gönderme işlemi ...
}
}
class Customer {
private $emailSender;
public function __construct(EmailSenderInterface $emailSender) {
$this->emailSender = $emailSender;
}
public function placeOrder() {
// ... müşteri siparişi işleme koyma kodu ...
// e-posta gönderme işlemi
$this->emailSender->sendEmail($this->email, 'Sipariş Onayı', 'Siparişiniz başarıyla alındı.');
}
}
$emailSender = new EmailSender();
$customer = new Customer($emailSender);
$customer->placeOrder();
Yukarıdaki örnekte, Customer sınıfı, EmailSenderInterface arayüzüne bağımlı hale getirildi. EmailSender sınıfı da EmailSenderInterface arayüzünü uyguladığından, EmailSender sınıfı Customer sınıfı tarafından kullanılabilir hale gelir.
Bu şekilde, müşteri sınıfımızın doğrudan bir sınıfa bağımlı olması yerine, bir arayüze bağımlı olması sağlanmıştır. Böylece, farklı bir e-posta gönderme servisi kullanmak istesek bile, sadece yeni bir sınıf oluşturup EmailSenderInterface arayüzünü uygulamak yeterli olacaktır. Bu şekilde, müşteri sınıfını değiştirmeden yeni bir e-posta gönderme servisi kullanabiliriz.
Aşağıdaki PHP kodu ise Dependency Inversion prensibini ihlal eden bir sınıf örneğidir.
class Customer {
private $emailSender;
public function __construct() {
$this->emailSender = new EmailSender();
}
public function placeOrder() {
// ... müşteri siparişi işleme koyma kodu ...
// e-posta gönderme işlemi
$this->emailSender->sendEmail($this->email, 'Sipariş Onayı', 'Siparişiniz başarıyla alındı.');
}
}
class EmailSender {
public function sendEmail($to, $subject, $message) {
// ... e-posta gönderme işlemi ...
}
}
$customer = new Customer();
$customer->placeOrder();
Yukarıdaki örnekte, Customer sınıfı doğrudan EmailSender sınıfına bağımlıdır. Bu, Customer sınıfının esnekliğini azaltır, çünkü müşteri sınıfı, yalnızca EmailSender sınıfını kullanarak e-posta göndermek zorundadır.
Bunun yerine, Customer sınıfı EmailSenderInterface arayüzüne bağımlı hale getirilmeli ve EmailSender sınıfı da bu arayüzü uygulamalıdır. Böylece, müşteri sınıfı daha esnek hale gelir ve farklı e-posta gönderme servisleri kullanılabileceği için daha kolay bir şekilde değiştirilebilir hale gelir.
GoLang dilinde, Dependency Inversion prensibini uygulamak için aşağıdaki gibi bir örnek verilebilir:
type EmailSenderInterface interface {
SendEmail(to string, subject string, message string)
}
type EmailSender struct {}
func (e EmailSender) SendEmail(to string, subject string, message string) {
// ... e-posta gönderme işlemi ...
}
type Customer struct {
EmailSender EmailSenderInterface
Email string
}
func (c Customer) PlaceOrder() {
// ... müşteri siparişi işleme koyma kodu ...
// e-posta gönderme işlemi
c.EmailSender.SendEmail(c.Email, "Sipariş Onayı", "Siparişiniz başarıyla alındı.")
}
func main() {
emailSender := EmailSender{}
customer := Customer{EmailSender: emailSender, Email: "example@example.com"}
customer.PlaceOrder()
}
Yukarıdaki örnekte, Customer sınıfı, EmailSenderInterface arayüzüne bağımlı hale getirilmiştir. EmailSender sınıfı da EmailSenderInterface arayüzünü uyguladığından, EmailSender sınıfı Customer sınıfı tarafından kullanılabilir hale gelir.
Bu şekilde, müşteri sınıfımızın doğrudan bir sınıfa bağımlı olması yerine, bir arayüze bağımlı olması sağlanmıştır. Böylece, farklı bir e-posta gönderme servisi kullanmak istesek bile, sadece yeni bir sınıf oluşturup EmailSenderInterface arayüzünü uygulamak yeterli olacaktır. Bu şekilde, müşteri sınıfını değiştirmeden yeni bir e-posta gönderme servisi kullanabiliriz.
PHP örneğine benzer şekilde, aşağıdaki GoLang kodu da Dependency Inversion prensibini ihlal eden bir örnektir.
type Customer struct {
EmailSender EmailSender
Email string
}
func (c Customer) PlaceOrder() {
// ... müşteri siparişi işleme koyma kodu ...
// e-posta gönderme işlemi
c.EmailSender.SendEmail(c.Email, "Sipariş Onayı", "Siparişiniz başarıyla alındı.")
}
type EmailSender struct {}
func (e EmailSender) SendEmail(to string, subject string, message string) {
// ... e-posta gönderme işlemi ...
}
func main() {
emailSender := EmailSender{}
customer := Customer{EmailSender: emailSender, Email: "example@example.com"}
customer.PlaceOrder()
}
Yukarıdaki örnekte, Customer sınıfı doğrudan EmailSender sınıfına bağımlıdır. Bu, Customer sınıfının esnekliğini azaltır, çünkü müşteri sınıfı, yalnızca EmailSender sınıfını kullanarak e-posta göndermek zorundadır.
Bunun yerine, Customer sınıfı EmailSenderInterface arayüzüne bağımlı hale getirilmeli ve EmailSender sınıfı da bu arayüzü uygulamalıdır. Böylece, müşteri sınıfı daha esnek hale gelir ve farklı e-posta gönderme servisleri kullanılabileceği için daha kolay bir şekilde değiştirilebilir hale gelir.
Kaynaklar
- https://en.wikipedia.org/wiki/Dependency_inversion_principle
- https://blog.logrocket.com/dependency-inversion-principle-typescript/#:~:text=The%20dependency%20inversion%20principle%20is,affecting%20the%20high%2Dlevel%20ones.
- https://dev.to/tamerlang/understanding-solid-principles-dependency-inversion-1b0f