2015-04-18 3 views
2

У меня есть следующий интерфейсКак сделать алмазный оператор Тип аргументов динамический в java?

public interface Splitter<T, V> { 
    V[] split(T arg); 
} 

Ниже реализация метода завод, который я использую, чтобы получить реализацию Splitter.

Factory Method Реализация

public static <T, V> Splitter<T, V> getSplitter(Class<T> key1, Class<V> key2) { 

    if (key1 == Company.class && key2 == Department.class) 
     return (Splitter<T, V>) new CompanySplitterImpl(); 

    // more cases 
} 

Ниже мой вызов на стороне клиента, который отлично компилируется

Splitter<Company, Department> split = getSplitter(Company.class, Department.class); 

Я хочу, чтобы избежать тесной связи на стороне клиента кода с реализацией. Есть ли способ избежать жестко заданных параметров типа, т. Е. Избегать использования Компании и Департамента (Splitter<Company, Department>) со стороны вызываемого абонента и вместо этого использовать некоторую переменную? Есть ли выход, через который они могут быть загружены из какого-либо внешнего файла свойств?

FYI: Я не уверен в его возможности на Java?

+2

О каких жестко заданных параметрах вы говорите? И какую переменную вы хотите использовать? –

+0

Я понятия не имею, о чем вы спрашиваете. Укажите код, который вы хотели бы иметь. –

+0

@RohitJain Отредактировано вопросом – Vinit89

ответ

1

Одна вещь, которую вы можете сделать, - это иметь фабрику, которая ничего не знает о конкретных реализациях и вместо этого сама регистрируется (или содержит предопределенный список) и спрашивает каждую реализацию, может ли она обрабатывать типы или нет. Например, если заранее определенный список, как ваш пример выше:

public class SplitterFactory { 
    private Set<Splitter> splitters = new HashSet<>() {{ 
     add(new CompanySplitterImpl()); 
    }}; 

    public static <T, V> Splitter<T, V> getSplitter(Class<T> key1, Class<V> key2) 
    { 
     for (Splitter splitter : splitters) { 
      if (splitter.canAccept(key1, key2)) { 
       return splitter; 
     }  
     // no matched splitter 
    } 
} 

Очевидно, что это очень наивное решение, и вы могли бы более эффективно осуществлять поиск. Если во время компиляции вы не знаете свои типы, у вас также может быть механизм регистрации с фабрикой для включения новых во время выполнения. Поскольку сам Splitter теперь отвечает за то, какие типы он может обрабатывать, он полностью расширяется.

+1

Ваш набор «разделителей» определяется с использованием «разделителя». Не рекомендуется. – RealSkeptic

0

Не очень хороший способ, но один путь будет:

String companyClass = "Company"; 
String departmentClass = "Department"; 
Splitter split = getSplitter(Class.forName(companyClass), Class.forName(departmentClass));//raw splitter 
System.out.println(split.split(new Company()));//you could use reflection here to create instance from companyClass String. 
+1

Как использовать сырые типы хорошо? – RealSkeptic

1

Вы могли бы сделать простой класс карты, которые вы можете перечислить их до:

public final class SplitterMap { 

    private final List<SplitterType<?, ?>> list = new ArrayList<>(); 

    private class SplitterType<T, V> { 

     private final Class<T> key1; 
     private final Class<V> key2; 
     private final Class<? extends Splitter<T, V>> clazz; 

     private SplitterType(Class<?> key1, Class<?> key2, Class<? extends Splitter<T, V> clazz) { 
      this.key1 = key1; 
      this.key2 = key2; 
      this.clazz = clazz; 
     } 

     private boolean matches(Class<?> key1, Class<?> key2) { 
      return this.key1 == key1 && this.key2 == key2; 
     } 
    } 

    public <T, V> void put(Class<T> key1, Class<V> key2, Class<? extends Splitter<T, V> clazz) { 
     list.add(new SplitterType<T, V>(key1, key2, clazz)); 
    } 

    public <T, V> Splitter<T, V> get(Class<T> key1, Class<V> key2) { 
     for (SplitterType<?, ?> type : list) { 
      if (type.matches(key1, key2)) { 
       try { 
        return ((SplitterType<T, V>) type).clazz.newInstance(); 
       } catch (Exception e) { 
       } 
      } 
     } 
     return null; // not found 
    } 
} 

Тогда вы можете просто сделать:

SplitterMap map = new SplitterMap(); 
map.put(Company.class, Department.class, CompanySplitterImpl.class); 
Splitter<Company, Department> splitter = map.get(Company.class, Department.class); 
0

Во-первых, я предполагаю, что вы хотите что-то вроде

Splitter<Company, Department> s = Splitters.getSplitter() 

Который не без отражения Возможное, из-за

  1. типа стиранием
  2. возвращаемый тип перегрузки не доступны в Java пока

Во-вторых, вы злоупотребляя FactoryMethod шаблон. Который должен выглядеть следующим образом:

interface Splitter<T, V> { 
    V[] split(T arg); 
} 

interface SplitterFactory { 
    <T, V> Splitter<T, V> getSplitter(); 
} 

class CompanySplitterFactory implements SplitterFactory { 
    @Override 
    public Splitter<Company, Department> getSplitter() { 
     return new CompanySplitterImpl(); 
    } 
} 
Смежные вопросы