Я не согласен с тем, как я хочу построить свою архитектуру базы данных. Прежде всего, я использую одноэлементный шаблон для базы данных, чтобы застраховать один ее экземпляр (чтобы он был потокобезопасным), а также чтобы получить работоспособную ссылку на базу данных, где бы у меня ни был контекст.
Во всем приложении я выполняю много разных операций с базами данных, например, для некоторых действий нужно изменить только таблицу «Meals», а для некоторых нужно изменить, например, «Meals» и «MealFoods».
Для каждой из этих таблиц я создал вспомогательный класс, чтобы отделить операции CRUD каждой таблицы от класса DatabaseManager (который расширяет SQLiteOpenHelper). Это, конечно, сделано для простоты и более чистого кода.
Первый подход:
Этот подход сохраняет все вспомогательные классы внутри DatabaseManager.
DatabaseManager.java:
public class DatabaseManager extends SQLiteOpenHelper {
private static String dbName = "logs.db";
private static final int dbVersion = 1;
private final Context context;
public MealsDBHelper mealsDBHelper;
public MealFoodsDBHelper mealFoodsDBHelper;
private DatabaseManager(@NonNull Context context) {
super(context, dbName, null, dbVersio);
this.context = context.getApplicationContext();//Saving as application context to avoid leaks
mealsDBHelper = new MealsDBHelper(context);
mealFoodsDBHelper = new MealFoodsDBHelper(context);
}
private static DatabaseManager instance;
public static synchronized DatabaseManager getInstance(Context context) {
if (instance == null) {
instance = new DatabaseManager(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
//...
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//...
}
}
Давайте посмотрим на класс MealsDBHelper, который почти все, что он делает, — это помогает передавать операции CRUD с базой данных. (Например, пользователь хочет изменить название своей еды)
public class MealsDBHelper {
public static final String MEALS_TABLE_NAME = "Meals";
public static final String MEAL_ID_COLUMN = "Meal_ID";
public static final String MEAL_NAME_COLUMN = "Meal_Name";
public static final String MEAL_POS_COLUMN = "Meal_Pos";
public static final String MEAL_DATE_COLUMN = "Date";
private Context context; //A context object to pass on to the DatabaseManager.getInstance method in all the different methods inside this class
public MealsDBHelper(Context context){
this.context = context;
}
//For example one of few methods that do operations on the 'Meals' table in the database.
public void updateMealName(long mealId, String meal_name) {
UserDataDB.getInstance(context).getWritableDatabase().execSQL("UPDATE " + MEALS_TABLE_NAME + " SET " + MEAL_NAME_COLUMN + " = '" + meal_name + "' WHERE " + MEAL_ID_COLUMN + " = " + mealId);
}
}
Теперь, независимо от того, изменяет ли действие 1, 2 или даже 3 таблицы, я могу обновить название блюда следующим образом:
DatabaseManager.getInstance(context).mealsDBHelper.updateMealName(mealId, mealName);
Это потому, что DatabaseManager содержит ссылку на все другие вспомогательные классы.
Что мне нравится в этом подходе, так это то, что я могу просто получить доступ к каждой таблице и выполнять с ней операции в соответствии со своими потребностями, и что мне не нравится, так это то, что класс DatabaseManager содержит ссылку для всех помощников, и я не уверен, что лучше так сделать ..
Второй подход:
Этот подход не сохраняет все вспомогательные классы внутри DatabaseManager.
DatabaseManager.java:
public class DatabaseManager extends SQLiteOpenHelper {
private static String dbName = "logs.db";
private static final int dbVersion = 1;
private final Context context;
private DatabaseManager(@NonNull Context context) {
super(context, dbName, null, dbVersio);
this.context = context.getApplicationContext();//Saving as application context to avoid leaks
}
private static DatabaseManager instance;
public static synchronized DatabaseManager getInstance(Context context) {
if (instance == null) {
instance = new DatabaseManager(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
//...
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//...
}
}
Теперь, если в моей деятельности необходимо изменить таблицы Meals и MealFoods, я могу создать в onCreate помощников, например:
public class AddFoodActivity extends AppCompatActivity{
MealsDBHelper mealsDBHelper;
MealFoodsDBHelper mealFoodsDBHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(..);
mealsDBHelper = new MealsDBHelper(this);
mealFoodsDBHelper = new MealFoodsDBHelper(this);
}
//Then whenever I need to modify the table I use:
mealsDBHelper.updateMealName(mealId, mealName);
}
Что мне нравится в этом подходе, так это то, что я могу использовать простую строку для изменения таблицы в соответствии с моими потребностями, и что мне не нравится, так это то, что мне нужно определять вспомогательные ссылки для каждого действия, и это как бы делает код непоследовательным. .
В принципе, есть ли недостатки у использования одного из методов?
Признаюсь, в этом посте я оставил большой кусок кода, но это только потому, что я думаю, что это не сильно повлияет на ваше понимание проблемы, потому что это более общая проблема.
Большое спасибо за любую помощь.