Я разрабатываю простой Объект Доступа к данным для своего JAVA-приложения. У меня есть несколько классов (записи), который представляет одну строку в таблицах как User
и Fruit
.
Я хотел бы иметь отдельный метод для получения всех записей определенного типа.
В настоящий момент у меня есть он как это:
public List<User> getAllUsers() {
...
}
public List<Fruit> getAllFruits() {
...
}
....
Но я хотел бы иметь единственный полиморфный метод как этот (несправедливость):
public List<T> getAllRecords(Class<T> type) {
if(type instanceof User) {
// Use JDBC and SQL SELECT * FROM user
} else if(type instanceof Fruit) {
// Use JDBC and SQL SELECT * FROM fruit
}
return collection;
}
Пример для использования:
List<Fruit> fruits = myDataAccessObject.getAllRecrods(Fruit.class);
List<User> users = myDataAccessObject.getAllRecords(User.class);
Как я могу сделать это в Java?
Поскольку вы говорите, что не хотите использовать методы доступа к данным в разных классах (в комментарии к ответу Аниша), я подумал, почему бы не попробовать что-то подобное.
public class Records {
public interface RecordFetcher<T>{
public List<T> getRecords();
}
static RecordFetcher<Fruit> Fruit=new RecordFetcher<Fruit>(){
public List<Fruit> getRecords() {
...
}
};
static RecordFetcher<User> User=new RecordFetcher<User>(){
public List<User> getRecords() {
...
}
};
public static void main(String[] args) {
List<Fruit> fruitRecords=Records.Fruit.getRecords();
List<User> userRecords=Records.User.getRecords();
}
}
РЕДАКТИРОВАТЬ:
Я хотел бы добавить еще одну мою реализацию.
public class Test
{
public static void main(String[] args)
{
Test dataAccess=new Test();
List<Fruit> FruitList=dataAccess.getAllRecords(Fruit.myType);
List<User> UserList=dataAccess.getAllRecords(User.myType);
}
<T> List<T> getAllRecords(T cl)
{
List<T> list=new ArrayList<T>();
if(cl instanceof Fruit)
{
// Use JDBC and SQL SELECT * FROM fruit
}
else if(cl instanceof User)
{
// Use JDBC and SQL SELECT * FROM user
}
return list;
}
}
class Fruit
{
static final Fruit myType;
static {myType=new Fruit();}
}
class User
{
static final User myType;
static {myType=new User();}
}
РЕДАКТИРОВАТЬ :
Я думаю, что эта реализация соответствует вашему запросу
public class Test
{
public static void main(String[] args) throws InstantiationException, IllegalAccessException
{
Test dataAccess=new Test();
List<Fruit> FruitList=dataAccess.getAllRecords(Fruit.class);
List<User> UserList=dataAccess.getAllRecords(User.class);
}
<T> List<T> getAllRecords(Class<T> cl) throws InstantiationException, IllegalAccessException
{
T inst=cl.newInstance();
List<T> list=new ArrayList<T>();
if(inst instanceof Fruit)
{
// Use JDBC and SQL SELECT * FROM user
}
else if(inst instanceof User)
{
// Use JDBC and SQL SELECT * FROM fruit
}
return list;
}
}
В зависимости от того, как вы на самом деле извлекаете данные, вы можете сделать что-то вроде этого:
private static <T> List<T> getAll(Class<T> cls){
List<T> fromSql = (List<T>) sql.query("SELECT * FROM objects WHERE type="+cls.getName());
return fromSql;
}
Это требует, чтобы ваш объект sql
возвращал правильный тип списка, который O / R мапперы, такие как iBatis.
Если вам нужно различать переданные типы, вы все равно можете сделать переключатель / регистр на cls
.
Похоже, вы хотите адаптировать то, что Джош Блох называет Шаблон безопасного гетерогенного контейнера : вы передаете токен типа Class
и хотите вернуть List
.
Обычный старый THC может сопоставить Class
с T
безопасным способом, но поскольку вам действительно нужен List
вместо , то вы хотите использовать то, что Нил Гафтер назвал токенами супертипа .
Следующий фрагмент адаптирован из кода Сумасшедшего Боба Ли, опубликованного в блоге Нила Гафтера:
public abstract class TypeReference<T> {
private final Type type;
protected TypeReference() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class<?>) {
throw new RuntimeException("Missing type parameter.");
}
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
}
public Type getType() {
return this.type;
}
}
Теперь вы можете создать токен супертипа следующим образом:
TypeReference<String> stringTypeRef =
new TypeReference<String>(){};
TypeReference<Integer> integerTypeRef =
new TypeReference<Integer>(){};
TypeReference<List<Boolean>> listBoolTypeRef =
new TypeReference<List<Boolean>>(){};
По сути, вы передаете TypeReference
вместо Class
. Разница в том, что нет List
, но вы можете создать TypeReference
. >
Итак, теперь мы можем сделать наш контейнер следующим образом (следующий текст адаптирован из исходного кода Джоша Блоха):
public class Favorites {
private Map<Type, Object> favorites =
new HashMap<Type, Object>();
public <T> void setFavorite(TypeReference<T> ref, T thing) {
favorites.put(ref.getType(), thing);
}
public <T> T getFavorite(TypeReference<T> ref) {
@SuppressWarnings("unchecked")
T ret = (T) favorites.get(ref.getType());
return ret;
}
}
Теперь мы можем соединить два вместе:
Favorites f = new Favorites();
f.setFavorite(stringTypeRef, "Java");
f.setFavorite(integerTypeRef, 42);
f.setFavorite(listBoolTypeRef, Arrays.asList(true, true));
String s = f.getFavorite(stringTypeRef);
int i = f.getFavorite(integerTypeRef);
List<Boolean> list = f.getFavorite(listBoolTypeRef);
System.out.println(s); // "Java"
System.out.println(i); // "42"
System.out.println(list); // "[true, true]"
Нил Гафтер утверждал в своем блоге, что с еще несколькими колокольчиками и свистки, TypeReference
для токенов супертипов будет достойным включением в JDK.
Вы очень близки.
public <T> LinkedList<T> getAllRecords(List<T> list) {
...
}
Это называется Общий метод .
Вам нужно указать такой параметр, как List
. Затем, основываясь на типе переданного вами списка, Java определит возвращаемый универсальный тип.
Изменить:
Поли ответил очень хорошо. Вам должно быть достаточно легко сделать следующее и не создавать класс TypeReference
.
List<Fruit> fruit = myDataAccessObject.getAllRecrods(new LinkedList<Fruit>());
List<User> users = myDataAccessObject.getAllRecords(new LinkedList<User>());
Я правда не знаю, нужно ли вам это в таком виде. Но вот полиморфный подход. Это может где-то помочь.
Создавайте разные объекты для разных таблиц, все реализующие общий интерфейс. Это означает, что вы представляете каждую таблицу как объект.
import java.util.LinkedList;
public class DataAccessTest
{
/**
* @param args
*/
public static void main(String[] args)
{
DataAccess myDataAccessObject = new DataAccess();
Type type1 = new Fruit();
Type type2 = new User();
LinkedList<Type> list1 = myDataAccessObject.getAllRecords(type1);
LinkedList<Type> list2 = myDataAccessObject.getAllRecords(type2);
LinkedList<Type> list3 = myDataAccessObject.getAllRecords(new Fruit());
LinkedList<Type> list4 = myDataAccessObject.getAllRecords(new User());
}
}
class DataAccess
{
public LinkedList<Type> getAllRecords(Type type)
{
return type.getAllRecords();
}
}
interface Type
{
public LinkedList<Type> getAllRecords();
}
class Fruit implements Type
{
public LinkedList<Type> getAllRecords()
{
LinkedList<Type> list = new LinkedList<Type>();
list.add(new Fruit());
return list;
}
}
class User implements Type
{
public LinkedList<Type> getAllRecords()
{
LinkedList<Type> list = new LinkedList<Type>();
list.add(new User());
return list;
}
}