2014-12-02 4 views
1

Я прочитал post Кристиана Грубера, и я начал задаваться вопросом, как использовать синглэты в приложении.
В моем приложении у меня есть класс DBHelper, основной целью которого является сохранение ключей в моей базе данных. У меня также много (по крайней мере двух) разных DAO.
Теперь - я не вижу причины, почему мои несколько видов деятельности/классов должны быть больше, чем просто один экземпляр DAO. Более того, зачем DAO нужен экземпляр DBHelper только для себя? Я уверен, что они могут поделиться, особенно я не предсказываю ситуации, когда оба DAO хотели бы выполнить некоторую операцию в моей базе данных одновременно. Итак, давайте посмотрим некоторые классы:Как использовать Singleton в Dagger 1.x?

  • DBHelper

    @Singleton 
    public class DBHelper extends SQLiteOpenHelper { 
         //some not relevant configuration stuff 
         private Context context; 
    
         @Inject 
         public DBHelper(Context context) { 
          super(context, DATABASE_NAME, null, DATABASE_VERSION); 
          this.context = context; 
         } 
    
        @Override 
        public void onCreate(SQLiteDatabase db) { 
          //db.execSQL, creating tables and stuff 
        } 
    
        @Override 
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
          //dropping tables, creating a new one 
          onCreate(db); 
        } 
    } 
    
  • пример DAO

    public interface SomeDataDAO { 
         void hai(); 
        } 
    
        public class SomeDataDAOImpl implements SomeDataDAO { 
         private DBHelper dbHelper; 
    
         public SomeDataDAOImpl(DBHelper dbHelper){ 
           this.dbHelper = dbHelper; 
         } 
         @Override 
         public void hai() { 
           SQLiteDatabase database = dbHelper.getWritableDatabase(); 
           dbHelper.doSomeDatabaseStuff() 
         } 
        } 
    
  • SomeDataModule

    @Module(
         injects = { MainActivity.class, SomeServiceImpl.class } 
         ) 
    public class SomeDataModule { 
         private Context appContext; 
    
         @Provides @Singleton 
         public SomeDataDAO provideSomeDataDao(DBHelper dbHelper){ 
          return new SomeDataDAOImpl(dbHelper); 
         } 
    
         @Provides @Singleton 
         public ISomeService provideSomeService(SomeServiceImpl impl){ 
          return impl; 
         } 
    
         @Provides 
         public Context getAppContext(){ 
          return this.appContext; 
         } 
         public SomeDataModule(){ 
          this.appContext = MainActivity.getAppContext(); 
         } 
    } 
    
  • Теперь давайте посмотрим два примера потребителей зависимостей

    public class MainActivity extends ActionBarActivity { 
        @Inject 
        SomeDataDAO someDataDAO; 
        private ObjectGraph objectGraph; 
        @Inject 
        ISomeService someService; 
        private static Context appContext; 
    
    
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState); 
         appContext = getApplicationContext(); 
         objectGraph = ObjectGraph.create(SomeDataModule.class); 
         objectGraph.inject(this); 
         someService.doSomeStuff(); 
        } 
    
        public static Context getAppContext() { 
         return appContext; 
        } 
    } 
    


    public class SomeServiceImpl implements ISomeService { 
        private ObjectGraph objectGraph; 
        @Inject public SomeDataDAO someDataDAO; 
    
        public SomeServiceImpl(){ 
         objectGraph = ObjectGraph.create(GraphDataModule.class); 
         objectGraph.inject(this); 
        } 
    
        public void doSomeStuff(){ 
         someDataDAO.hai(); 
        } 
    
    } 
    


Он работает, но когда я inject(this) дважды, Dagger, очевидно, создает мне два экземпляра DBHelper, как он считает, «Один синглтон с одним экземпляром графа». Как обернуть мой SomeDataModule в ApplicationModule, так что у меня есть только один экземпляр DBHelper во всем приложении? Добавление @Singleton к DBHelper, к сожалению, было недостаточно.

+0

Если вы должны пойти синглтон, почему бы не использовать Глобальный класс со статическими членами и методами? –

+0

@KristyWelsh Я изучаю Android и кинжал. Даже если в этом конкретном случае класс со статическими элементами и методами может быть лучше, я хотел бы знать, как достичь своей цели с помощью инъекции зависимостей, особенно когда у меня есть довольно простой пример прямо сейчас. Кстати, это даже правильный шаблон дизайна? Я не думаю, что когда-либо сталкивался с таким подходом. Я встретил класс со статическими полями, давая константы, SQL и т. Д., Но никогда не распространяя DAO. – spoko

ответ

3

Простой, короткий и ответ, который решает незначительный недостаток дизайна и с этой проблемой заключается в следующем. Вместо того, чтобы создать новый ObjectGraph, чтобы ввести экземпляр SomeDataDAO в ваш SomeServiceImpl, вам действительно нужно передать SomeDataDAO вашему конструктору. То есть на самом деле то, что инъекции зависимостей, как правило, означает: использовать конструктор какого-либо объекта, чтобы ввести его зависимостей:

public class SomeServiceImpl implements ISomeService { 

    private final SomeDataDAO someDataDAO; 

    @Inject 
    public SomeServiceImpl(SomeDataDAO someDataDAO){ 
     this.someDataDAO = someDataDAO; 
    } 

    public void doSomeStuff(){ 
     someDataDAO.hai(); 
    } 
} 

Теперь это где происходит волшебство. Обратите внимание на аннотацию @Inject для конструктора? Он сообщает кинжалу использовать этот конструктор всякий раз, когда запрашивается экземпляр SomeServiceImpl, и запрашивает параметры ObjectGraph.

Так что, когда у вас есть этот метод Provides ниже, Кинжал уже знает, что SomeServiceImpl зависит от SomeDataDAO, и использует свой метод provideSomeDataDAO, чтобы обеспечить этот экземпляр. И, эй, это синглтон, так что это тот же самый экземпляр, что и любой другой экземпляр SomeDataDAO, полученный этим ObjectGraph!

@Provides @Singleton 
    public ISomeService provideSomeService(SomeServiceImpl impl){ 
     return impl; 
    } 

В самом деле, вы не хотите использовать ObjectGraph.inject(...) слишком часто, вы на самом деле хотите использовать вышеуказанные методы.Однако есть случаи, когда вы не решаете, как выглядит конструктор. Например, в Android это, например, классы Activity и View. Для этих особых случаев было создано ObjectGraph.inject, поэтому вы можете добавлять свои зависимости с помощью кинжала.

Заключительное примечание: В SomeServiceImpl Я сделал someDataDAOprivate. Как вы, вероятно, знаете, это предпочтительный способ обработки полей экземпляра, и это позволяет использовать конструкторы для инъекций.

Оказывается, этот ответ не в том, что короткий на всех: O)

+0

[Это] (https://github.com/square/dagger/tree/master/examples/android-activity-graphs) - пример того, как кстати можно использовать несколько модулей. – nhaarman

Смежные вопросы