CodeGym/Java Blogu/Rastgele/SOLID: Java'da sınıf tasarımının beş temel ilkesi
John Squirrels
Seviye
San Francisco

SOLID: Java'da sınıf tasarımının beş temel ilkesi

grupta yayınlandı
Sınıflar, uygulamaların yapı taşlarıdır. Tıpkı bir binadaki tuğlalar gibi. Kötü yazılmış sınıflar sonunda sorunlara neden olabilir. SOLID: Java'da sınıf tasarımının beş temel ilkesi - 1Bir sınıfın düzgün yazıp yazmadığını anlamak için, "kalite standartlarına" ne kadar uyduğunu kontrol edebilirsiniz. Java'da bunlar sözde SOLID ilkeleridir ve biz onlar hakkında konuşacağız.

Java'da SOLID ilkeleri

SOLID, OOP ve sınıf tasarımının ilk beş ilkesinin büyük harflerinden oluşan bir kısaltmadır. İlkeler 2000'li yılların başında Robert Martin tarafından ifade edildi ve ardından kısaltma daha sonra Michael Feathers tarafından tanıtıldı. İşte SOLID ilkeleri:
  1. Tek Sorumluluk İlkesi
  2. Açık Kapalı İlke
  3. Liskov İkame İlkesi
  4. Arayüz Ayırma Prensibi
  5. Bağımlılık Tersine Çevirme İlkesi

Tek Sorumluluk İlkesi (SRP)

Bu ilke , bir sınıfı değiştirmek için asla birden fazla neden olmaması gerektiğini belirtir . Her nesnenin, sınıfta tamamen kapsanan bir sorumluluğu vardır. Bir sınıfın tüm hizmetleri bu sorumluluğu desteklemeye yöneliktir. Bu tür sınıfları gerektiğinde değiştirmek her zaman kolay olacaktır, çünkü sınıfın nelerden sorumlu olduğu ve nelerden sorumlu olmadığı açıktır. Başka bir deyişle, değişiklikler yapabileceğiz ve sonuçlarından, yani diğer nesneler üzerindeki etkiden korkmayacağız. Ek olarak, bu tür bir kodun test edilmesi çok daha kolaydır, çünkü testleriniz bir işlevsellik parçasını diğerlerinden ayrı olarak kapsar. Siparişleri işleyen bir modül hayal edin. Bir sipariş doğru bir şekilde oluşturulmuşsa, bu modül onu bir veri tabanına kaydeder ve siparişi onaylamak için bir e-posta gönderir:
public class OrderProcessor {

    public void process(Order order){
        if (order.isValid() && save(order)) {
            sendConfirmationEmail(order);
        }
    }

    private boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }

    private void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
Bu modül üç nedenden dolayı değişebilir. İlk olarak, siparişleri işleme mantığı değişebilir. İkincisi, siparişlerin kaydedilme şekli (veritabanı türü) değişebilir. Üçüncüsü, onayın gönderilme şekli değişebilir (örneğin, e-posta yerine kısa mesaj göndermemiz gerektiğini varsayalım). Tek sorumluluk ilkesi, bu sorunun üç yönünün aslında üç farklı sorumluluk olduğunu ima eder. Bu, farklı sınıflarda veya modüllerde olmaları gerektiği anlamına gelir. Farklı zamanlarda ve farklı nedenlerle değişebilen birkaç varlığı birleştirmek, kötü bir tasarım kararı olarak kabul edilir. Bir modülü, her biri tek bir işlevi yerine getiren üç ayrı modüle bölmek çok daha iyidir:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}

public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}

Açık Kapalı Prensibi (OCP)

Bu ilke şu şekilde açıklanmaktadır: yazılım varlıkları (sınıflar, modüller, işlevler, vb.) genişlemeye açık, değişiklik için kapalı olmalıdır . Bu, sınıfın mevcut kodunda değişiklik yapmadan sınıfın dış davranışını değiştirmenin mümkün olması gerektiği anlamına gelir. Bu ilkeye göre, sınıflar öyle tasarlanmıştır ki, bir sınıfı belirli koşullara uyacak şekilde ayarlamak, onu genişletmeyi ve bazı işlevleri geçersiz kılmayı gerektirir. Bu, sistemin esnek olması, kaynak kodunu değiştirmeden değişen koşullarda çalışabilmesi gerektiği anlamına gelir. Sipariş işlemeyi içeren örneğimize devam ederek, bir sipariş işlenmeden önce ve onay e-postası gönderildikten sonra bazı eylemler gerçekleştirmemiz gerektiğini varsayalım. değiştirmek yerineOrderProcessorsınıfın kendisini, Open Closed İlkesini ihlal etmeden amacımıza ulaşmak için genişleteceğiz:
public class OrderProcessorWithPreAndPostProcessing extends OrderProcessor {

    @Override
    public void process(Order order) {
        beforeProcessing();
        super.process(order);
        afterProcessing();
    }

    private void beforeProcessing() {
        // Take some action before processing the order
    }

    private void afterProcessing() {
        // Take some action after processing the order
    }
}

Liskov İkame İlkesi (LSP)

Bu, daha önce bahsettiğimiz açık kapalı prensibinin bir çeşididir. Şu şekilde tanımlanabilir: Nesneler, bir programın özelliklerini değiştirmeden alt sınıfların nesneleri ile değiştirilebilir. Bu, bir temel sınıfı genişleterek oluşturulan bir sınıfın, istemcinin bakış açısından işlevselliğin tehlikeye atılmaması için yöntemlerini geçersiz kılması gerektiği anlamına gelir. Yani, bir geliştirici sınıfınızı genişletir ve onu bir uygulamada kullanırsa, geçersiz kılınan yöntemlerin beklenen davranışını değiştirmemelidir. Alt sınıflar, istemcinin bakış açısından işlevselliğin bozulmaması için temel sınıfın yöntemlerini geçersiz kılmalıdır. Bunu aşağıdaki örnekte ayrıntılı olarak inceleyebiliriz. Bir siparişi doğrulamaktan ve siparişteki tüm malların stokta olup olmadığını kontrol etmekten sorumlu bir sınıfımız olduğunu varsayalım.isValid()true veya false döndüren yöntem :
public class OrderStockValidator {

    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if (!item.isInStock()) {
                return false;
            }
        }

        return true;
    }
}
Ayrıca bazı siparişlerin diğerlerinden farklı şekilde doğrulanması gerektiğini varsayalım, örneğin bazı siparişler için siparişteki tüm malların stokta olup olmadığını ve tüm malların paketlenip paketlenmediğini kontrol etmemiz gerekiyor. OrderStockValidatorBunu yapmak için, sınıfı oluşturarak sınıfı genişletiyoruz OrderStockAndPackValidator:
public class OrderStockAndPackValidator extends OrderStockValidator {

    @Override
    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if ( !item.isInStock() || !item.isPacked() ){
                throw new IllegalStateException(
                     String.format("Order %d is not valid!", order.getId())
                );
            }
        }

        return true;
    }
}
Ancak burada Liskov ikame ilkesini ihlal ettik, çünkü sipariş doğrulamayı geçemezse false döndürmek yerine , yöntemimiz bir IllegalStateException. Bu kodu kullanan istemciler şunu beklemezler: true veya false dönüş değeri beklerler . Bu, çalışma zamanı hatalarına yol açabilir.

Arayüz Ayırma İlkesi (ISP)

Bu ilke, aşağıdaki ifade ile karakterize edilir: Müşteri, kullanmayacağı yöntemleri uygulamaya zorlanmamalıdır . Arayüz ayırma ilkesi, çok "kalın" olan arayüzlerin daha küçük, daha spesifik olanlara bölünmesi gerektiği anlamına gelir, böylece küçük arayüzler kullanan istemciler yalnızca çalışmaları için ihtiyaç duydukları yöntemleri bilirler. Sonuç olarak, bir arabirim yöntemi değiştiğinde, bu yöntemi kullanmayan istemcilerin değişmemesi gerekir. Şu örneği ele alalım: Bir geliştirici olan Alex, bir "rapor" arabirimi oluşturmuş ve iki yöntem eklemiştir: generateExcel()vegeneratedPdf(). Artık bir müşteri bu arayüzü kullanmak istiyor, ancak raporları Excel'de değil, yalnızca PDF formatında kullanmayı amaçlıyor. Bu işlevsellik bu müşteriyi tatmin edecek mi? Hayır. İstemci, biri büyük ölçüde ihtiyaç duyulmayan ve yalnızca yazılımı tasarlayan Alex sayesinde var olan iki yöntemi uygulamak zorunda kalacak. İstemci ya farklı bir arabirim kullanacak ya da Excel raporları yöntemiyle hiçbir şey yapmayacaktır. Peki çözüm nedir? Mevcut arayüzü iki küçük ara yüze bölmektir. Biri PDF raporları için, diğeri Excel raporları için. Bu, müşterilerin yalnızca ihtiyaç duydukları işlevselliği kullanmasına izin verir.

Bağımlılık Tersine Çevirme İlkesi (DIP)

Java'da bu SOLID ilkesi şu şekilde açıklanmaktadır: sistem içindeki bağımlılıklar soyutlamalara dayalı olarak oluşturulur.. Daha yüksek seviyeli modüller, daha düşük seviyeli modüllere bağlı değildir. Soyutlamalar ayrıntılara bağlı olmamalıdır. Detaylar soyutlamalara bağlı olmalıdır. Yazılımın, çeşitli modüller bağımsız olacak ve soyutlama yoluyla birbirine bağlanacak şekilde tasarlanması gerekir. Bu ilkenin klasik bir uygulaması Spring Framework'tür. Spring Framework'te, tüm modüller birlikte çalışabilen ayrı bileşenler olarak uygulanır. O kadar özerktirler ki, Spring Framework dışındaki program modüllerinde de aynı kolaylıkla kullanılabilirler. Bu, kapalı ve açık ilkelerin bağımlılığı sayesinde elde edilir. Tüm modüller, yalnızca başka bir modülde kullanılabilen soyutlamaya erişim sağlar. Bunu bir örnekle açıklamaya çalışalım. Tek sorumluluk ilkesinden bahsetmişken,OrderProcessorsınıf. Bu sınıfın koduna bir kez daha göz atalım:
public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}
Bu örnekte, sınıfımız OrderProcessoriki özel sınıfa bağlıdır: MySQLOrderRepositoryve ConfirmationEmailSender. Ayrıca bu sınıfların kodlarını da sunacağız:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
Bu sınıflar, soyutlama dediğimiz şeyden çok uzaktır. Ve bağımlılık tersine çevirme ilkesi açısından, belirli uygulamalar yerine gelecekte üzerinde çalışabileceğimiz bazı soyutlamalar oluşturarak başlamak daha iyi olacaktır. İki arayüz oluşturalım: MailSenderve OrderRepository). Bunlar bizim soyutlamalarımız olacak:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
Şimdi bunun için önceden hazırlanmış sınıflarda bu arayüzleri uyguluyoruz:
public class ConfirmationEmailSender implements MailSender {

    @Override
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }

}

public class MySQLOrderRepository implements OrderRepository {

    @Override
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}
OrderProcessorHazırlık çalışmalarını , sınıfımızın somut ayrıntılara değil, soyutlamalara bağlı olması için yaptık . Bağımlılıklarımızı sınıf yapıcısına ekleyerek değiştireceğiz:
public class OrderProcessor {

    private MailSender mailSender;
    private OrderRepository repository;

    public OrderProcessor(MailSender mailSender, OrderRepository repository) {
        this.mailSender = mailSender;
        this.repository = repository;
    }

    public void process(Order order){
        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }
}
Artık sınıfımız belirli uygulamalara değil, soyutlamalara bağlıdır. OrderProcessorBir nesne yaratıldığı anda istenen bağımlılığı ekleyerek davranışını kolayca değiştirebiliriz . Java'da SOLID tasarım ilkelerini inceledik. CodeGym kursunda genel olarak OOP ve Java programlamanın temelleri hakkında daha fazla bilgi edineceksiniz - sıkıcı bir şey değil ve yüzlerce saatlik pratik. Birkaç görevi çözme zamanı :)
Yorumlar
  • Popüler
  • Yeni
  • Eskimiş
Yorum bırakmak için giriş yapmalısınız
Bu sayfada henüz yorum yok