How to implement general pagination

后端 未结 2 439
一整个雨季
一整个雨季 2020-12-22 22:08

I am not looking for a Hibernate/JPA/JDBC implementation, but for a general design pattern.

Googling \"pagination\" gives me loads of information, lot of interestin

相关标签:
2条回答
  • 2020-12-22 22:42

    If I were you I would return not the result (Set) itself but something that encapsulates retrieval of the result. Some sort of ResultBuilder. Look:

    public interface ResultBuilder<T> {
    
        ResultBuilder<T> withOffset(int offset);
    
        ResultBuilder<T> withLimit(int limit);
    
        ResultBuilder<T> orderedBy(String property);
    
        List<T> result();
    }
    

    and then change DAO method signature:

    ResultBuilder<Person> findPersonsByName(String name);
    

    This way you can factor out business-irrelevant arguments from find-family methods. If you don't want to make client specify this params then don't make him.

    Just to be clear:

    public final class HibernateGenericResultBuilder<T> implements ResultBuilder<T> {
    
        private final Criteria criteria;
    
        public HibernateGenericResultBuilder(Criteria criteria) {
            this.criteria = criteria;
        }
    
        @Override public ResultBuilder<T> withOffset(int offset) {
            criteria.setFirstResult(offset);
            return this;
        }
    
        @Override public ResultBuilder<T> withLimit(int limit) {
            criteria.setMaxResults(limit);
            return this;
        }
    
        @Override public ResultBuilder<T> orderedBy(String property) {
            criteria.addOrder(Order.asc(property));
            return this;
        }
    
        @Override public List<T> result() {
            return new LinkedHashSet<T>(criteria.list());
        }
    }
    
    0 讨论(0)
  • 2020-12-22 22:46

    I would consider applying the Strategy Pattern here.

    Basically, instead of supplying the start and limit as parameters or wrapping them in a varargs, make a real object, put them there, and move the responsibility of setting the paging on the criteria to this object.

    Roughly speaking (I'm not compiling...):

    public interface PagingSpecification {
        void apply(Criteria criteria);
    }
    
    public class ConcretePagingSpecification implements PagingSpecification {
        private int start;
        private int limit;
    
        public ConcretePagingSpecification(int start, int limit) {
           this.start = start;
           this.limit = limit;
        }
    
        public void apply(Criteria crit) {
           crit.setFirstResult(start);
           crit.setMaxResults(limit);         
        }
    }
    

    And then of course pass this into your finders and call it in the obvious places.

    One advantage of this is that you can make a NullPagingSpecification implementation which does nothing, so that you can use the same code when you don't actually want paging.

    Another is that you can move things like the next() and previous() methods you're likely to need (to allow actual paging) into the PagingSpecification classes as well, and share yet more code.

    0 讨论(0)
提交回复
热议问题