2017-01-25 3 views
3

Обычно при использовании Dagger 2 и андроид я следующее:Разница между ничтожной Inject (активность деятельности) и SomeComponent getSomeComponent()

@Singleton 
@Component(modules = {ApplicationModule.class}) 
public interface ApplicationComponent { 


    void inject(MainActivity activity); 
} 

public class MainActivity extends Activity { 
    @Inject SharedPreferences mSharedPrefs; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     ((DemoApplication) getApplication()) 
        .getComponent() 
        .inject(this); 
    } 
} 

Но в последнее время я видел это:

@Singleton 
@Component(modules = {ApplicationModule.class}) 
public interface ApplicationComponent { 
    SharedPreferences getSharedPreferences(); 
} 

public class MainActivity extends Activity { 
    SharedPreferences mSharedPrefs; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mSharedPrefs = ((DemoApplication) getApplication()) 
       .getComponent().getSharedPreferences(); 
    } 
} 

I пропустили класс DemoApplication и класс Module, они являются стандартными.

В чем разница между этими двумя подходами? Pro и Con тоже? Может быть, правильно или нет?

+0

Связанный: [Что является целью неинжекционных методов в компонентах в кинжале 2] (https://stackoverflow.com/questions/41472319/what-is-the-purpose-of-the-non-inject -methods-in-components-in-dagger-2/41472320) –

+0

Спасибо за это, я сделал поиск, но не нашел это –

ответ

2

dependency inversion principle Разработка программного обеспечения предполагает, что мы должны стараться и зависеть от абстракций, а не от конкреций.

По этой причине вы должны предпочесть аннотации @Inject (аннотация) для ввода в поле в вашей деятельности, а не вызов метода обеспечения из компонента кинжала (бетон).

Почему? Вы заметите, что аннотации @Inject являются частью пакета javax.inject. Это стандарт API-интерфейсов для инъекций, введенных в Java, как часть JSR330. Существуют и другие рамки DI, такие как Guice и Toothpick, которые могут использовать эти аннотации. Если вам придется переключать рамки DI в будущем, это будет проще, если вы используете аннотации @Inject. Да, бывает, что вам нужно изменить рамки DI. Roboguice является примером популярной структуры DI, которая недавно была удалена.

Чтобы проиллюстрировать это, давайте рассмотрим вашу активность, добавить несколько зависимостей, и извлечь метод для инъекций, как это:

public class MainActivity extends Activity { 
    @Inject SharedPreferences mSharedPrefs; 
    @Inject Foo foo; 
    @Inject Bar bar; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
    } 

    @VisibleForTesting 
    protected void injectMembers() { 
     ((DemoApplication) getApplication()) 
      .getComponent() 
      .inject(this); 
    } 
} 

появляется дикая основа (новый) DI! Теперь вам нужно изменить приложение, чтобы быстро его использовать! Вы используете JSR330. Это суперэффективно! (перевод: вы можете повторно использовать свои аннотации JSR330 @Inject, потому что их поддерживает новый каркас DI). Если вы изменили на новый Guice подобной структуры, все, что вам нужно будет сделать, это переписать метод:

@VisibleForTesting 
    protected void injectMembers() { 
     GuiceLikeInjector.getInjector(this).injectMembers(); 
    } 

В отличие от этого, если вы вводили эти поля вручную с помощью .getSharedPreferences(), getFoo() это не очень эффективно - вы должны изменить много строк кода.

+0

Спасибо за это.Причина, по которой я изначально спросила, состоит в том, что новый коллега захотел сделать некоторый рефакторинг во втором стиле опций. Мне было трудно убедить их, что один вариант был лучше/более нормальным, спасибо, что помогли мне построить лучший аргумент. –

+0

@ i'm_not_josh Я рад, что это помогло. Несмотря на то, что синтаксис может показаться немного необычным, JSR330 является удивительным! –

1

Если вы посмотрите на сгенерированный код Component, вы заметите, что он реализует метод inject(MainActivity), устанавливая введенные поля напрямую, используя ссылку на операцию, которую вы передаете. Итак, оба варианта делают то же самое.

Я предпочитаю первый подход по двум основным причинам. Во-первых, гораздо яснее, что поля вводятся, когда они аннотируются как таковые, а во-вторых, он намного лучше очищает код. В примере, который вы дали вам ввести одно поле, и это труднее увидеть выгоду, но я думаю, что это становится намного более очевидным, когда вам нужно ввести 10 полей, где вам нужно будет назначить их все в onCreate() и объявить геттеры для них в компоненте.

+0

Спасибо за это, вы сделаете несколько действительных баллов. –