Java Programlama Dilinde SOLID İlkelerini Uygulama

Java Programlama Dilinde SOLID İlkelerini Uygulama

SOLID, yazılım tasarımlarını daha anlaşılır, esnek, sağlam ve sürdürülebilir hale getirmeyi amaçlayan 5 tasarım ilkesinin kısaltmasıdır . Bu uygulamaları benimsemek, kod kokularının önlenmesine de katkıda bulunabilir.

5 SOLID ilkesi şunlardır:

  • S - The single-responsibility principle
  • O - The open-closed principle
  • L - The Liskov substitution principle
  • I - The interface segregation principle
  • D - The dependency inversion principle

1. Tek Sorumluluk İlkesi (The single-responsibility principle)

Bu ilke, “ bir sınıfın değişmesi için tek bir neden olması gerektiğini ” ifade eder , bu da her sınıfın tek bir sorumluluğu olması gerektiği anlamına gelir.

public class Vehicle {
    public void details() {}
    public double price() {}
    public void addNewVehicle() {}
}

Burada sınıfın değişmesi için birden çok nedeni vardır, çünkü Vehiclesınıfın üç ayrı sorumluluğu vardır: ayrıntıları yazdırma, yazdırma fiyatı ve Veritabanına yeni bir araç ekleme.

Tek sorumluluk ilkesi hedefine ulaşmak için, yalnızca tek bir işlevi gerçekleştiren ayrı bir sınıf uygulamalıyız.

public class VehicleDetails {
    public void details() {}
}

public class CalculateVehiclePrice {
    public double price() {}
}

public class AddVehicle {
    public void addNewVehicle() {}
}

2. Açık-Kapalı Prensibi (The open-closed principle)

Bu ilke, “ yazılım varlıklarının (sınıflar vb.) genişletilmeye açık, ancak değiştirilmeye kapalı olması gerektiğini ” belirtir . Bu, bir sınıftaki hiçbir şeyi değiştirmeden genişletilebilir olması gerektiği anlamına gelir.

Bu prensibi bir bildirim hizmeti örneği ile anlayalım.

public class NotificationService{
    public void sendNotification(String medium) {
         if (medium.equals("email")) {}
    }
}

Burada e-posta dışında yeni bir ortam tanıtmak istiyorsanız, diyelim ki bir cep telefonu numarasına bildirim gönderin, o zaman NotificationService sınıfında kaynak kodunu değiştirmeniz gerekiyor.

Bunu aşmak için kodunuzu, herkesin özelliğinizi genişleterek yeniden kullanabileceği ve herhangi bir özelleştirmeye ihtiyaç duyarsa sınıfı genişletip üzerine özelliklerini ekleyebileceği şekilde tasarlamanız gerekir.

Aşağıdaki gibi yeni bir arayüz oluşturabilirsiniz:

public interface NotificationService {
    public void sendNotification(String medium);
}

Eposta bildirimi:

public class EmailNotification implements NotificationService {
    public void sendNotification(String medium){
        // write Logic using for sending email
    }
}

Mobil Bildirim:

public class MobileNotification implements NotificationService {
    public void sendNotification(String medium){
        // write Logic using for sending notification via mobile
    }
}

3. Liskov İkame Prensibi (The Liskov substitution principle)

Bu ilke, " türetilmiş sınıfların, temel sınıflarının yerine geçebilmesi gerektiğini " belirtir . Başka bir deyişle, A sınıfı B sınıfının bir çocuğuysa, programın mevcut davranışını kesintiye uğratmadan B'yi A ile değiştirebilmeliyiz.

Rectangle temel sınıfından türetilen bir kare sınıf örneğini ele alalım:

public class Rectangle {
    private double height;
    private double width;
    public void setHeight(double h) { height = h; }
    public void setWidht(double w) { width = w; }
}
public class Square extends Rectangle {
    public void setHeight(double h) {
        super.setHeight(h);
        super.setWidth(h);
    }
    public void setWidth(double w) {
        super.setHeight(w);
        super.setWidth(w);
    }
}

Rectangle Sınıfta genişlik ve yükseklik ayarı son derece mantıklı görünüyor . Ancak square sınıfında SetWidth() ve SetHeight() anlamlı değildir çünkü birini ayarlamak diğerini ona uyacak şekilde değiştirir.

Bu durumda, Rectangle temel sınıfını türetilmiş Square sınıfıyla değiştiremeyeceğiniz için Square, Liskov ikame testinde başarısız olur. Square sınıfının ekstra kısıtlamaları vardır, yani yükseklik ve genişlik aynı olmalıdır. Bu nedenle, Rectangle sınıfının Square sınıfıyla değiştirilmesi beklenmeyen davranışlara neden olabilir.

4. Arayüz Ayrıştırma İlkesi (The interface segregation principle)

Bu ilke Arayüzler için geçerlidir ve tek sorumluluk ilkesine benzer. “** İstemci kullanmadığı bir arabirimi uygulamaya veya istemciler kullanmadıkları yöntemlere bağımlı olmaya asla zorlanmamalıdır.**“.

Bunu bir araç arayüzü örneği ile anlayalım:

public interface Vehicle {
    public void drive();
    public void stop();
    public void refuel();
    public void openDoors();
}

Bike, Şimdi bu Araç arayüzünü kullanarak bir sınıf oluşturduğumuzu varsayalım.

public class Bike implements Vehicle {
    public void drive() {}
    public void stop() {}
    public void refuel() {}

    // Can not be implemented
    public void openDoors() {}
}

Bisikletin kapıları olmadığı için son işlevi uygulayamıyoruz.

Bunu düzeltmek için, hiçbir sınıfın ihtiyaç duymadığı herhangi bir arabirimi veya yöntemi uygulamak zorunda kalmaması için arabirimleri küçük çoklu arabirimlere ayırmanız önerilir.

public interface Vehicle {
    public void drive();
    public void stop();
    public void refuel();
}
public interface Doors{
    public void openDoors();
}

İki sınıf oluşturma - Car ve Bike

public class Bike implements Vehicle {
    public void drive() {}
    public void stop() {}
    public void refuel() {}
}
public class Car implements Vehicle, Door {
    public void drive() {}
    public void stop() {}
    public void refuel() {}
    public void openDoors() {}
}

5. Bağımlılık Tersine Çevirme İlkesi (The dependency inversion principle)

Dependency Inversion Principle (DIP), " varlıkların somut uygulamalara (sınıflara) değil, soyutlamalara (soyut sınıflar ve arayüzler) bağlı olması gerektiğini belirtir . Ayrıca, yüksek seviyeli modül düşük seviyeli modüle değil, her ikisine de bağlı olmalıdır. soyutlamalara dayanmalıdır ".

Müşterilerin en sevdikleri kitapları belirli bir rafa koymalarını sağlayan bir kitapçı olduğunu varsayalım.

Bu işlevi uygulamak için bir Book sınıf ve bir Shelf sınıf oluşturuyoruz. Kitap sınıfı, kullanıcıların raflarda depoladıkları her kitabın incelemelerini görmelerine olanak tanır. Raf sınıfı, raflarına bir kitap eklemelerine izin verecektir. Örneğin,

public class Book {
    void seeReviews() {}
}


public class Shelf {
     Book book;
     void addBook(Book book) {}
}

Her şey yolunda görünüyor, ancak high-level Shelf sınıf low-level'e bağlı Book olduğundan, yukarıdaki kod Dependency Inversion Principle'ı ihlal ediyor. Bu, mağaza bizden müşterilerin kendi yorumlarını da raflara eklemelerini sağlamamızı istediğinde açıkça ortaya çıkıyor. Talebi karşılamak için yeni bir UserReview sınıf oluşturuyoruz:

public class UserReview{
     void seeReviews() {}
}

Şimdi, Kullanıcı İncelemelerini de kabul edebilmesi için Shelf sınıfını değiştirmeliyiz. Ancak bu, Açık/Kapalı İlkesini de açıkça bozacaktır.

Çözüm, alt düzey sınıflar (Kitap ve UserReview) için bir soyutlama katmanı oluşturmaktır. Bunu Ürün arabirimini tanıtarak yapacağız, her iki sınıf da onu uygulayacak. Örneğin, aşağıdaki kod kavramı gösterir.

public interface Product {
    void seeReviews();
}

public class Book implements Product {
    public void seeReviews() {}
}

public class UserReview implements Product {
    public void seeReviews() {}
}

Artık Raf, uygulamaları yerine Ürün arayüzüne başvurabilir (Kitap ve Kullanıcı İncelemesi). Yeniden düzenlenmiş kod ayrıca, müşterilerin raflarına da koyabilecekleri yeni ürün türlerini (örneğin, Dergi) daha sonra tanıtmamıza da olanak tanır.

public class Shelf {
    Product product;
    void addProduct(Product product) {}
    void customizeShelf() {}
}

Sonuç

Bu yazıda size SOLID Code'un beş ilkesi sunuldu. SOLID ilkelerine bağlı kalmak, projenizi daha az komplikasyonla genişletilebilir, kolayca değiştirilebilir, iyi test edilmiş hale getirebilir.

Yorumlar

Bu gönderi için yorum yapılmadı.