Guice'deki @ImplementedBy ek açıklamasının ardındaki motivasyon nedir?


10

Kısa süre önce Google Guice'de sunulan @ImplementedByek açıklamaları okudum . Programlayıcının, bağımlılık enjeksiyonunda ileride kullanmak üzere bir arayüz ve uygulaması arasında bir bağ belirlemesini sağlar. Tam zamanında bağlama örneğidir .

Aşağıdaki sözdizimini kullanarak, modüllerimdeki açık bağlantıları tanımlamaya alışkınım:

bind(SomeInterface.class).to(SomeInterfaceImplementation.class);

Belgelere göre, bu, @ImplementedByek açıklamanın aşağıdaki kullanımına eşdeğerdir :

@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
    //method declarations
}

Burada görebildiğim tek kazanç, kodun biraz daha kısa olması. Aynı zamanda, bu yaklaşımın aynı dokümanlar tarafından doğru bir şekilde işaret edilen bir dezavantajı vardır:

@ImplementedByDikkatli kullanın ; arayüzden uygulamaya derleme zamanı bağımlılığı ekler.

Böyle bir bağımlılık birçok durumda bir sorun olmayabilir ama ben şahsen bir kod kokusu olarak görüyorum.

Hangi kullanım durumları @ImplementedByek açıklamayı kullanmaya değer kılar ?

Olası bir yol, onu bir kütüphane veya çerçeve kodunda kullanmak gibi görünmektedir. Dokümanlarda açıklandığı gibi ek açıklama, açık bir şekilde kolayca geçersiz kılınabilen varsayılan bir bağlama sağlayabilir .

Bir tür hem bir bind()ifadede (ilk argüman olarak) hem de @ImplementedByek açıklama içeriyorsa, bind()ifade kullanılır. Ek açıklama, bir bağlayıcıyla geçersiz kılınabilen varsayılan bir uygulamayı önerir .

Bu şekilde, bir kütüphanenin geliştiricisi olarak, kullanıcılara istemci kodunun herhangi bir yerinde özelleştirilebilen kutudan çıkma bir bağlantı sağlayabilirim.

Ek açıklamanın var olmasının tek nedeni bu mu? Yoksa özlediğim bir şey var mı? Genişletilecek bir kütüphane / çerçeve değil, sadece bazı iş mantığıyla ilgilenen bir uygulama olan kodda kullanarak herhangi bir şey kazanabilir miyim?


2
İlişkili, muhtemelen yinelenen soru (başlığınız daha net olsa da): Guice'in @ImplementedBy kötülük mü?
Jeff Bowman

Kesin bir kopya değil, ama bu konuda bazı ilginç tartışmalar oldu: stackoverflow.com/questions/6197178/…
Richard Vodden

Yanıtlar:


8

Burada tehlike kullanıldığını düşünüyorum sadece@ImplementedBy ek açıklama. bind()Modülünüzdeki ifadelerle birlikte kullanıldığında, uygun şekilde kullanılır , tamamdır.

Varsayılan bir uygulamaya sahip olmak test için harikadır; çok fazla bağımlılığı olan bir sınıfı test ettiğinizde veya birçok şeyin bağımlı olduğu bir sınıfınız varsa (bu yüzden her seferinde bir sahte tanımlamanız gerekir) açıkça bir sahte enjeksiyon tanımlamak istemezsiniz. ).

Örneğin, bir sınıfınız olabilir:

@ImplementedBy(NoOpDataService.class)
interface DataService {
    Map<String, MyPOJO> getData();
}

Ve sonra NoOpDataService:

class NoOpDataService implements DataService {
    @Override
    public Map<String, MyPOJO> getData() {
        return Collections.emptyMap();
    }
}

Bunu asla gerçek kodunuzda kullanmayacaksınız; Guice modülünüzde aslında bir şey yapan bir uygulamayı bağlarsınız. Ancak, enjekte edilen sınıflar üzerindeki tüm testlerin DataServiceartık sahte bir bağlamaya sahip olması gerekmez.

tl; dr Arayüzlerinizin uygulamanıza bağlı olması bir kod kokusu olabilir; aynı zamanda boilerplate kodunu kaldırarak testi kolaylaştırır. Bu özelliği uygulamak zor değil; ve kötüye kullanım için küçük bir potansiyel olsa da, sonuçta sonuçlar çok kötü olamaz (bir hizmet sürprizle başlar) ve gerçekleşse bile düzeltilmesi çok zor olmaz.


3
Üretime test kodu eklensin mi?
Basilevs
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.