In meiner Android-App habe ich einige sehr ähnliche Klassen, nennen wir sie FooA
und FooB
.Generieren mit statischen Factory-Methoden und Konstanten in Java
Für jede dieser Klassen habe ich eine Schema-Klasse, die Konstanten für die Spalten der Tabelle enthält - FooASchema
und FooBSchema
:
public final class FooASchema {
public static final String TABLE_NAME = "foo_a_table";
public static final String COL_CATEGORY_ID = "category_id";
public static final String COL_PROPERTY_A = "property_a";
public static final String COL_PROPERTY_B = "property_b";
// COL_PROPERTY_C = ...
}
public final class FooBSchema {
public static final String TABLE_NAME = "foo_b_table";
public static final String COL_CATEGORY_ID = "category_id";
public static final String COL_OTHER_PROPERTY_A = "other_property_a";
// COL_OTHER_PROPERTY_B = ...
}
Beide FooA
und FooB
haben eine statische Factory-Methode, die mir ermöglicht zu schaffen sie mit einem Cursor
:
public static FooA from(Cursor cursor) {
int categoryId = cursor.getInt(cursor.getColumnIndex(FooASchema.COL_CATEGORY_ID));
String propertyA = cursor.getString(cursor.getColumnIndex(FooASchema.COL_PROPERTY_A));
String propertyB = cursor.getString(cursor.getColumnIndex(FooASchema.COL_PROPERTY_B));
// int propertyC = ...
return FooA(id, propertyA, propertyB, ...);
}
public static FooB from(Cursor cursor) {
int categoryId = cursor.getInt(cursor.getColumnIndex(FooBSchema.COL_CATEGORY_ID));
int otherA = cursor.getInt(cursor.getColumnIndex(FooASchema.COL_OTHER_PROPERTY_A));
// String otherB = ...
return FooB(id, otherA, otherB, ...);
}
Schließlich habe ich zwei util-Klassen, die ich verwenden, um Daten abzurufen aus den Tabellen:
public final class FooAUtils {
public static ArrayList<FooA> getFooAs(Context context, int categoryId) {
ArrayList<FooA> fooAs = new ArrayList<>();
Cursor cursor = MyDbHelper.getInstance(context).getReadableDatabase.query(
FooASchema.TABLE_NAME,
null,
FooASchema.COL_CATEGORY_ID + "=?",
new String[] {String.valueOf(categoryId)},
null,
null,
null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
fooAs.add(FooA.from(cursor));
cursor.moveToNext();
}
cursor.close();
return fooAs;
}
// ...
}
public final class FooBUtils {
public static ArrayList<FooA> getFooBs(Context context, int categoryId) {
ArrayList<FooB> fooBs = new ArrayList<>();
Cursor cursor = MyDbHelper.getInstance(context).getReadableDatabase.query(
FooBSchema.TABLE_NAME,
null,
FooBSchema.COL_CATEGORY_ID + "=?",
new String[] {String.valueOf(categoryId)},
null,
null,
null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
fooBs.add(FooB.from(cursor));
cursor.moveToNext();
}
cursor.close();
return fooBs;
}
// ...
}
können Sie sehen, dass die meisten der Code zwischen FooA
-related Klassen und FooB
-related Klassen sehr ähnlich sind, und vor allem in den util Klassen -, wo der Code fast identisch ist.
Ich möchte versuchen, diese Duplizierung zu reduzieren, und ich habe versucht, dies mit Generika zu tun (ich habe über sie gelesen, aber ich habe sie noch nicht in einem Projekt verwendet).
Zum Beispiel möchte ich in der Lage sein, eine generische Util-Klasse zu haben. Hier ist, wie ich dachte, dass ich es umsetzen könnte:
public final class FooUtils {
public static <T> get(Context context, int categoryId) {
ArrayList<T> items = new ArrayList<>();
Cursor cursor = MyDbHelper.getInstance(context).getReadableDatabase.query(
BaseSchema.TABLE_NAME,
null,
BaseSchema.COL_CATEGORY_ID + "=?",
new String[] {String.valueOf(categoryId)},
null,
null,
null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
items.add(T.from(cursor)); // ??
cursor.moveToNext();
}
cursor.close();
}
// ...
}
Wo:
public interface BaseSchema {
public static final String TABLE_NAME; // can't make this abstract?
public static final String COL_CATEGORY_ID = "category_id";
}
public final class FooASchema implements BaseSchema { ... }
public final class FooBSchema implements BaseSchema { ... }
Aber wie Sie sehen können, kann ich nicht T.from(cursor)
tun, und ich kann nicht eine abstrakte Konstante TABLE_NAME
haben, dass die Unterklassen können implementieren.
Wie kann ich meine statische Fabrikmethode auf diese Weise aufrufen?
Gibt es einen besseren Weg, dies zu erreichen und die Code-Duplizierung zu reduzieren?
Betrachten wir einen Rahmen oder eine Bibliothek für diese Verwendung. Was Sie tun möchten, ist als solches nicht möglich. Generics arbeiten nur mit Instanzen; nicht mit Typen. Vielleicht sollten Sie diesen Ansatz nur mit Fabriken in Betracht ziehen. – tynn