Aşağıdaki (anti) desenin adı nedir? Avantajları ve dezavantajları nelerdir?


28

Son birkaç ay boyunca, aşağıdaki tekniği / kalıbı birkaç kez tökezledim. Ancak, belirli bir isim bulamıyorum, ne de tüm avantaj ve dezavantajlarından% 100 emin değilim.

Desen aşağıdaki gibi gider:

Bir Java arayüzünde, her zamanki gibi bir dizi ortak yöntem tanımlanır. Bununla birlikte, bir iç sınıf kullanıldığında, arabirimden varsayılan bir örnek sızdırılır.

public interface Vehicle {
    public void accelerate();
    public void decelerate();

    public static class Default {
         public static Vehicle getInstance() {
             return new Car(); // or use Spring to retrieve an instance
         }
    }
 }

Benim için en büyük avantaj, bir geliştiricinin sadece bir örnek oluşturmak istediği durumlarda, örneğin arayüzü hakkında değil uygulamaları hakkında bilmesi gerektiği gerçeğinde görünüyor.

 Vehicle someVehicle = Vehicle.Default.getInstance();
 someVehicle.accelerate();

Ayrıca, bu tekniğin, yapılandırmaya bağlı olarak dinamik olarak örnekler sağlamak amacıyla Spring ile birlikte kullanıldığını gördüm. Bu bakımdan, modülerleşmeye de yardımcı olabileceği gözüküyor.

Yine de, arayüzü uygulamalardan biriyle eşleştirdiği için bunun arayüzün kötüye kullanımı olduğu hissini sallayamıyorum. (Bağımlılık inversiyon ilkesi vb.) Herhangi biri bana bu tekniğin nasıl adlandırıldığını, avantajlarını ve dezavantajlarını açıklayabilir mi?

Güncelleştirme:

Bir süre göz önünde bulundurulduktan sonra, desenin aşağıdaki singleton versiyonunun çok daha sık kullanıldığını tekrar kontrol ettim ve fark ettim. Bu versiyonda, genel statik bir örnek yalnızca bir kez başlatılan arayüzden (alanın nihai olması nedeniyle) ortaya çıkar. Buna ek olarak, örnek hemen hemen her zaman Bahar veya uygulamadan arayüzü ayıran jenerik bir fabrika kullanılarak alınır.

public interface Vehicle {
      public void accelerate();
      public void decelerate();

      public static class Default {
           public static final Vehicle INSTANCE = getInstance();

           private static Vehicle getInstance() {
                return new Car(); // or use Spring/factory here
           }
      }
 }

 // Which allows to retrieve a singleton instance using...
 Vehicle someVehicle = Vehicle.Default.INSTANCE;

Özetle: Bunun temelde bir örneği veya bir singletonu arayüzü aracılığıyla göstermesini sağlayan özel bir singleton / fabrika modeli olduğu görülüyor. Dezavantajları ile ilgili olarak, aşağıdaki cevap ve yorumlarda birkaç kişi isimlendirilmiştir. Şimdiye kadar, avantaj kolaylık olarak görünüyor.


bir tür singleton deseni?
Bryan Chen

Arayüzün uygulamaları hakkında "bilmemesi" gerektiği konusunda haklısınız. Muhtemelen Vehicle.Defaultbir fabrika sınıfı olarak paket isim alanına taşınmalıdır, örn VehicleFactory.
ağustos

7
Bu arada,Vehicle.Default.getInstance() != Vehicle.Default.getInstance()
Konrad Morawski

20
Buradaki antipattern, hayvan analoji antipatterniyle yakından ilgili olan araba benzetme antipatternini kullanmaktır. Çoğu yazılımın tekerlekleri veya bacakları yoktur.
Pieter B

@PieterB: :-)))) Günümü yaptın!
Doktor Brown,

Yanıtlar:


24

Default.getInstanceIMHO , singleton düzeninden alınan bir adlandırma kuralına uydurulmuş (ancak sonuncunun bir uygulaması olmadan), sadece çok özel bir fabrika yöntem biçimidir . Mevcut formda bu, " tek sorumluluk ilkesi " nin ihlalidir , çünkü arayüz (zaten bir sınıf API bildirme amacına hizmet eden), ayrı bir durumda çok daha iyi olacak olan varsayılan bir örnek sağlama sorumluluğunu üstlenir. sınıf.VehicleFactory

Bu yapının neden olduğu asıl sorun, Vehicleve arasında döngüsel bir bağımlılığa neden olmasıdır Car. Örneğin, şu anki biçimde Vehiclebir kütüphaneye ve Cardiğerine yerleştirmek mümkün olmayacak . Ayrı bir fabrika sınıfı kullanmak ve Default.getInstanceyöntemi oraya yerleştirmek bu sorunu çözecektir. Singleton ile ilgili herhangi bir karışıklığı önlemek için bu yönteme farklı bir ad vermek de iyi bir fikir olabilir. Yani sonuç gibi bir şey olabilir

VehicleFactory.createDefaultInstance()


Cevabınız için teşekkürler! Bu özel örneğin SRP'nin ihlali olduğuna katılıyorum. Ancak, uygulamanın dinamik olarak geri alınması durumunda hala bir ihlal olup olmadığından emin değilim. Örneğin, bir konfigürasyon dosyası tarafından tanımlanan belirli bir örneği almak için Spring (veya benzer bir çerçeve) kullanarak .
Jérôme

1
@ Jérôme: IMHO iç içe geçmiş bir sınıf , özellikle yanıltıcı "getInstance" yöntemiyle VehicleFactoryiç içe geçmiş yapıdan daha gelenekseldir Vehicle.Default. Yay kullanarak döngüsel bağımlılığı atlatmak mümkün olsa da, sadece sağduyu yüzünden ilk değişkeni şahsen tercih ederim. Ve yine de, fabrikayı farklı bir bileşene taşıma, sonradan bahar olmadan çalışacak şekilde uygulama değişikliği yapma şansı bırakıyor
Doc Brown

Çoğu zaman, bir sınıf yerine arayüz kullanmanın nedeni, başka amaçlara sahip sınıfların, arayüz uygulaması gerektiren kodla kullanılabilmesidir. Varsayılan bir uygulayıcı sınıf, sadece "normal" bir şekilde arayüzü uygulayan bir şeye ihtiyaç duyan tüm kod gereksinimlerini karşılayabilirse, bir örnek oluşturmak için bir araç belirlemek, arayüzün yapması için yararlı bir şey gibi görünebilir.
supercat

Eğer Otomobil çok genel, standart bir Araç uygulamasıysa, bu SRP'ye aykırı değildir. Aracın, yalnızca Google'ın bir autodrive()yöntem eklediği zaman değişmesi için hala tek bir nedeni var . Çok genel Otomobiliniz daha sonra bu yöntemi uygulamak için örneğin bir NotImplementedException atarak, ancak Araç üzerinde değişiklik yapmak için ek bir neden vermeyecek şekilde değişmelidir.
user949300

@ user949300: SRP "matematiksel olarak kanıtlanabilir" bir kavram değildir. Yazılım tasarım kararları her zaman "siyah beyaz" değildir. Orijinal kod, üretim kodunda elbette kullanılamayacak kadar kötü değildi ve OP'nin "güncellemesinde" yazdığı gibi, kolaylığın döngüsel bağımlılığa ağır basabileceği durumlar olabilir. Bu yüzden lütfen cevabımı "Ayrı bir fabrika sınıfı kullanmanın size daha iyi hizmet etmeyeceğini düşünün" olarak okuyun. Ayrıca cevabımı verdikten sonra yazarın asıl sorusunu biraz değiştirdiğini de unutmayın.
Doc Brown

3

Bu bana Null Object pattern benziyor .

Ancak bu, Carsınıfın nasıl uygulandığına büyük ölçüde bağlıdır . Eğer "nötr" şekilde uygulanırsa, kesinlikle bir Null nesnesidir. Bu, arabirimdeki tüm boş denetimleri kaldırabilir ve her biri yerine bu sınıfın örneğini koyabiliyorsanız null, kodun yine de düzgün çalışması gerekir.

Ayrıca, eğer bu modelse, arayüzün kendisi ile boş nesnenin uygulanması arasında sıkı bir bağlantı oluşturma problemi yoktur. Çünkü null nesne, bahsedilen arayüzün kullanıldığı her yerde olabilir.


2
Merhaba ve cevabınız için teşekkürler. Benim durumumda "Boş Nesne" modelini uygulamak için kullanılmadığından oldukça emin olmama rağmen, ilginç bir açıklama.
Jérôme
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.