2015-05-19 12 views
6

mam tej klasy abstrakcyjnej gdzie mam zdefiniowane pewne metody, które wdrażają działania bazy danych (pobrać wiersze, włóż, usuwać itd.)Czy jest złą praktyką, aby powrócić rodzajowy wewnątrz klasy abstrakcyjnej różnych generycznego parametru

teraz Chcę utworzyć metodę, która zwróci kilka wierszy (np. Całą tabelę), ale zamiast klas domen chcę, aby zwróciła odpowiednie klasy modelu (zasadniczo jest to to samo co domena, ale bez list relacji i innych rzeczy, które wrzucam nie potrzebujesz warstwy prezentacji).

Abstrakcyjna klasa jest

public abstract class DomainService<T extends Domain> { 

    protected abstract Logger getLogger(); 

    protected final Validator validator; 

    protected DomainService() { 
     ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 
     this.validator = factory.getValidator(); 
    } 

    abstract public void insert(T object) throws ValidationException; 

    abstract public void delete(T object) throws EntityNotFoundException; 

    abstract public List<T> fetchAll(); 
} 

i chcę dodać inną metodę, która będzie nazywać fetchAll() a następnie iteracyjne każdą pozycję i stworzyć odpowiednik modelu i powrotu że lista.

public <K extends Model> List<K> fetchAllModels(Class<K> modelClass) { 
     List<T> domains = fetchAll(); 
     List<K> models = new ArrayList<K>(domains.size()); 

     for (T domain : domains) { 
      K model = modelClass.newInstance(); 
      models.add(model.fillIn(domain)); 
     } 

     return models; 
    } 

Pomijając, że jest to kod I choć właśnie teraz pisząc na pytanie, czy jest dopuszczalne, aby dodać parametr dla rodzajowy, który nie jest zdefiniowany w klasie. IMO klasa może mieć metody zwracające inne typy danych, więc nie powinno to stanowić problemu. W moim przypadku przekazuję klasę, dzięki czemu mogę utworzyć instancję modelu, a następnie użyć domeny do wypełnienia członów. Miałem dwie opinie:

  • Ta, którą napisałem, dodając metodę do klasy modelu, aby utworzyć ją samodzielnie z obiektu domeny. Myślałem o konstruktorze, który przyjmuje obiekt domeny jako argument, ale myślę, że jest to trochę kłopotliwe, aby wywołać konstruktora przy użyciu generycznych (To wymagałoby co najmniej narzędzi do odczytywania), więc myślę o metodzie wypełnienia szczegóły po utworzeniu instancji za pomocą domyślnego konstruktora. Również model jest na wyższej warstwie i myślę, że wyższe warstwy powinny używać niższych (Database-> Domain classes-> Access classes (DAO) -> Service classes-> Servlet classes ----> JSP wyświetlających dane)

  • mogę dodać metodę do klasy domeny, który przemienia domenę do swojego modelu i nazywają to bez konieczności przechodzenia klasę modelu

    public <K> List<K> fetchAllModels() { 
        List<T> domains = fetchAll(); 
        List<K> models = new ArrayList<K>(domains.size()); 
    
        for (T domain : domains) { 
         models.add(domain.createModel()); 
        } 
    
        return models; 
    } 
    

ale czuję, że klasa domeny powinna być jak wyczyść reprezentację tabeli w bazie danych za pomocą jedynych metod związanych z kolumnami.

Czy lepiej dodać parametr do klasy. Mam zamiar używać go tylko do tej metody ...

jakieś przemyślenia komentarze zawsze mile widziane

+0

Nie jestem pewien, czy mam ciebie, ale tak; jeśli masz parametry typu, które są wymagane tylko dla pojedynczych metod; powinieneś to zrobić w ten sposób - nie ma potrzeby, aby był to parametr klasy. – GhostCat

+1

Popraw mnie, jeśli się mylę, ale myślę, że opcja B nie może działać z powodu typu wnioskowania, w jaki sposób kompilator Java może wnioskować, że typ _K_ podaje tylko informacje o typie _T_? – superbob

+0

Zlekceważenie powyższego, pomyliłem pytania. K extends Model, który jest podstawową klasą abstrakcyjną. A domena # createModel zwraca typ modelu. –

Odpowiedz

4

jest to dopuszczalne, aby dodać parametr dla rodzajowy, który nie jest zdefiniowany w klasie

Absolutnie. Robi się cały czas.

Preferuję twoje pierwsze rozwiązanie, przekazując model do metody.

Ale to, czego naprawdę potrzebujesz, to funkcja, która tworzy K z T. W java8, można to zrobić bardzo zwięźle.

public <K extends Model> List<K> fetchAllModels(Function<T,K> func) { 
... 
      K model = func.apply(domain); 

i że masz model 'M' dla domeny 'D'

public M(D domain) // constructor 

można przekazać konstruktora jako func (lub przynajmniej wydaje się, że tak)

service.fectchAllModels(M::new) 

Jeśli używasz Stream, fetchAllModels() staje się znacznie prostsze

abstract public Stream<T> fetchAll(); 

public <K extends Model> Stream<K> fetchAllModels(Function<T,K> func) { 
    return fetchAll().map(func) 
} 

A więc, dlaczego potrzebujemy tej metody? Wystarczy zrobić

// fetch domains, convert each to M 
Stream<M> models = service.fetchAll().map(M::new); 

Więc możemy usunąć fetchAllModels() i usunąć wszelkie zależności od modelu od domeny.

+0

Dziękuję. Używam Java 7, ale będę o tym pamiętać –

Powiązane problemy