Statik yöntemleri kötüye kullanıyor muyuz?


13

Birkaç ay önce yeni bir projede çalışmaya başladım ve koddan geçerken bana kullanılan statik yöntemlerin miktarını okudum. Sadece yararlı yöntemler olarak değil collectionToCsvString(Collection<E> elements), aynı zamanda birçok iş mantığı da saklanır.

Bunun arkasındaki mantıktan sorumlu adama sorduğumda, bunun Bahar'ın zulmünden kaçmanın bir yolu olduğunu söyledi . Bu düşünme sürecinin etrafında bir şey var: bir müşteri makbuzu oluşturma yöntemi uygulamak için bir hizmetimiz olabilir.

@Service
public class CustomerReceiptCreationService {

    public CustomerReceipt createReceipt(Object... args) {
        CustomerReceipt receipt = new CustomerReceipt();
        // creation logic
        return receipt;
    }
}

Şimdi, adam Bahar tarafından gereksiz yere yönetilen sınıflara sahip olmaktan hoşlanmadığını söyledi, çünkü temel olarak müşteri sınıflarının Bahar fasulyesi olması gerektiğine dair kısıtlama getiriyor. Sonunda bizi vatansız nesnelerle prosedürel bir şekilde çalışmaya zorlayan Spring tarafından yönetilen her şeye sahip oluruz. Az ya da çok burada belirtilenler https://www.javacodegeeks.com/2011/02/domain-driven-design-spring-aspectj.html

Yukarıdaki kod yerine,

public class CustomerReceiptCreator {

    public static CustomerReceipt createReceipt(Object... args) {
        CustomerReceipt receipt = new CustomerReceipt();
        // creation logic
        return receipt;
    }
}

Mümkün olduğunda Spring'in sınıflarımızı yönetmesini önleme noktasına gelebilirim, ama görmediğim her şeyin statik olmasının yararı. Bu statik yöntemler de vatansızdır, bu yüzden çok OO da değildir. Bir şeyle daha rahat hissederdim

new CustomerReceiptCreator().createReceipt()

Statik yöntemlerin bazı ekstra faydaları olduğunu iddia ediyor. Yani:

  • Daha kolay okunur. Statik yöntemi içe aktarın ve sadece eylemi önemsemeliyiz, sınıfın ne yaptığını anlamıyoruz.
  • Açıkçası DB çağrıları ücretsiz bir yöntem, bu yüzden performans açısından ucuz; ve bunu açıklığa kavuşturmak iyi bir şeydir, böylece potansiyel müşterinin koda girmesi ve bunu kontrol etmesi gerekir.
  • Testleri yazmak daha kolay.

Ancak bununla tam olarak doğru olmayan bir şey olduğunu hissediyorum, bu yüzden bu konuda daha deneyimli geliştiricilerin düşüncelerini duymak istiyorum.

Benim sorum şu, bu programlama tarzının potansiyel tuzakları neler?




4
Yukarıda staticaçıkladığınız yöntem sadece sıradan bir fabrika yöntemidir. Fabrika yöntemlerini statik hale getirmek, birçok zorlayıcı nedenden ötürü, genel kabul görmüş bir sözleşmedir. Burada fabrika yönteminin uygun olup olmadığı farklı bir konudur.
Robert Harvey

Yanıtlar:


23

Arasındaki fark nedir new CustomerReceiptCreator().createReceipt()ve CustomerReceiptCreator.createReceipt()? Hemen hemen hiç. Tek önemli fark, ilk vakanın çok daha garip bir sözdizimine sahip olmasıdır. Bir şekilde statik yöntemlerden kaçınmanın kodunuzu daha iyi OO haline getirdiği inancında ilkini takip ederseniz, ciddi şekilde yanılıyorsunuz. Üzerinde tek bir yöntem çağırmak için bir nesne oluşturmak, geniş sözdizimi ile statik bir yöntemdir.

İşlerin farklı olduğu yer, onu enjekte etmek CustomerReceiptCreatoryerine enjekte ettiğiniz zamandır new. Bir örnek ele alalım:

class OrderProcessor {
    @Inject CustomerReceiptCreator customerReceiptCreator;

    void processOrder(Order order) {
        ...
        CustomerReceipt receipt = customerReceiptCreator.createReceipt(order);
        ...
    }
}

Bunu statik yöntem sürümünü karşılaştıralım:

void processOrder(Order order) {
    ...
    CustomerReceipt receipt = CustomerReceiptCreator.createReceipt(order);
    ...
}

Statik versiyonun avantajı, sistemin geri kalanıyla nasıl etkileşime girdiğini kolayca söyleyebilmemdir. Öyle değil. Global değişkenleri kullanmadıysam, sistemin geri kalanının bir şekilde değişmediğini biliyorum. Sistemin başka hiçbir parçasının burada makbuzu etkilemeyeceğini biliyorum Değişmez nesneler kullandıysam, siparişin değişmediğini biliyorum ve createReceipt saf bir işlev. Bu durumda, başka bir yerde tahmin edilemeyen etkiler hakkında endişelenmeden bu çağrıyı serbestçe hareket ettirebilir / kaldırabilirim / vb.

Eğer enjekte etmişsem aynı garantileri veremem CustomerReceiptCreator. Çağrı tarafından değiştirilen dahili duruma sahip olabilir, diğer durumdan etkilenebilir veya değiştirebilirim. İşlevimdeki ifadeler arasında, sıralamanın değiştirilmesinin şaşırtıcı hatalar getireceği şekilde öngörülemeyen ilişkiler olabilir.

Diğer yandan, CustomerReceiptCreatoraniden yeni bir bağımlılığa ihtiyaç duyulursa ne olur ? Bir özellik bayrağını kontrol etmesi gerektiğini varsayalım. Enjekte ediyor olsaydık, şöyle bir şey yapabilirdik:

public class CustomerReceiptCreator {
    @Injected FeatureFlags featureFlags;

    public CustomerReceipt createReceipt(Order order) {
        CustomerReceipt receipt = new CustomerReceipt();
        // creation logic
        if (featureFlags.isFlagSet(Flags::FOOBAR)) {
           ...
        }
        return receipt;
    }
}

Sonra işimiz biter, çünkü arama kodu CustomerReceiptCreatorotomatik olarak enjekte edilecek bir kod ile enjekte edilecektir FeatureFlags.

Statik bir yöntem kullanıyor olsaydık?

public class CustomerReceiptCreator {
    public static CustomerReceipt createReceipt(Order order, FeatureFlags featureFlags) {
        CustomerReceipt receipt = new CustomerReceipt();
        // creation logic
        if (featureFlags.isFlagSet(Flags::FOOBAR)) {
           ...
        }
        return receipt;
    }
}

Fakat bekle! arama kodunun da güncellenmesi gerekir:

void processOrder(Order order) {
    ...
    CustomerReceipt receipt = CustomerReceiptCreator.createReceipt(order, featureFlags);
    ...
}

Tabii ki, bu hala nerede sorusunu bırakır processOrderOnun gets FeatureFlagsgelen. Şanslıysak, iz burada biter, eğer değilse, FeatureFlags'tan geçme gereği yığının daha üstüne itilir.

Burada bir değiş tokuş var. Daha fazla çalışma ile sonuçlanan bağımlılıkların açıkça geçilmesini gerektiren statik yöntemler. Enjekte edilen yöntem işi azaltır, ancak bağımlılıkları dolaylı hale getirir ve böylece gizli kodun akıl yürütmesini zorlaştırır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.