2

アプリケーションは、プレゼンテーション層、サービス層、およびデータアクセス層を使用して構造化されています。多くの場合、データアクセス層から一部のデータを取得する必要がある複数のサービスとAPIがあります。このようなデータを取得するには、あるレイヤーから別のレイヤーに検索条件を渡す必要があることがよくあります。たとえば、from_date、to_date、email_id、user_idなどの属性を渡すことができます。これで、多くの個別のパラメーターを渡す代わりに、SearchCriteriaなどのオブジェクトを渡そうとしています。繰り返しますが、異なるサービス/APIには異なるSearchCriteriaが必要です。

問題は、すべてのサービスで使用できるように、どのように汎用化するかです。1つの方法は、SEARCH_KEYの値へのマップを保持するSearchCriteriaオブジェクトを作成することです。ここで、SEARCH_KEYは列挙型(FROM_DATE、TO_DATEなどの値を持つ)にすることができます。SEARCH_KEYによっては、キーを取得して使用することができます。ただし、これは、1つのレイヤーがこのマップから期待する値のタイプ(整数、文字列)を知っている場合にのみ機能します。あるレイヤーが別のレイヤーに結合されていますが、これは良くないと思います。私はこの質問に答えました-同様の問題を解決するジェネリックスの利点を備えた複数の値型のマップ。それは良いデザインですか?より良い選択肢はありますか?

4

4 に答える 4

7

JPA のようなものを使用している場合は、JPA Criteria APIを参照してください。これで、基本的なフィルター クラスを作成できます。

public abstract class AbstractFilter<T> {
    private EntityManager em;
    private Class<T> entityClass;
    private List<Predicate> predicates;
    private CriteriaBuilder cb;

    public AbstractFilter(EntityManager em, Class<T> clazz) {...}

    protected void add(Predicate predicate) {
        if (predicates == null) predicates = new ArrayList<>();
        if (predicate != null) predicates.add(predicate);
    }

    protected <X> void addEqual(Expression<X> expression, X value) {
        if (expression != null && value != null && cb != null)
            add(cb.equal(expression, value));
    }

    protected abstract void buildPredicates(Root<T> root);

    public List<T> getResultList() {
        this.cb = em.getCriteriaBuilder();
        CriteriaQuery<T> query = cb.createCriteria(entityClass);
        Root<T> root = query.from(entityClass);
        buildPredicates(root);
        return em.createQuery(query.select(root).where(predicates)).getResultList();
    }
}

public class UserFilter<User> {
    private String firstName, lastName;  // plus getter and setter
    private Gender gender;               // plus getter and setter

    public UserFilter(EntityManager em) { super(em, User.class); }

    protected void buildPredicates(Root<User> user) {
        addEqual(user.get(User_.firstName), getFirstName());
        addEqual(user.get(User_.lastName), getLastName());
        addEqual(user.get(User_.gender), getGender());
    }
}

------

UserFilter filter = new UserFilter(entityManager);
filter.setFirstName("Joe");
filter.setGender(Gender.Male);
List<User> users = filter.getResultList();

これはフィルター クラスの非常に基本的なサンプルにすぎません。フィルターにaddXXX(Expression, ?)メソッドを追加したり、並べ替えやページングなどの機能を追加したりできます。EntityManagerメソッド内のパラメーターなど、他のレイヤーから分離する場合は、DAOで を設定する必要があることに注意してくださいgetResultList(EntityManager)


別の解決策は、次のようなオブジェクトの例です。

User example = new User();
example.setFirstName("J*");
example.setGender(Gender.Male);
List<User> users = userDao.find(example);

DAO 実装がフィルタリング自体を行う場所。

于 2012-08-02T06:31:56.947 に答える
0

このようなことができます

parameterKeys を保持する Enum を記述します

enum ParameterKeys {

  SERIAL_NUMBER,
  SEARCH_KEY,
  FROM_DATE,
  ISVALID

}

パラメータ値を保持するクラスを書く

public class Parameter {

    private Object value;
    private Class<?> clazz;

    public Parameter(Object value) {
        setValue(value);
    }

    public void setValue(Object value) {
        this.value = value;
        this.clazz = value.getClass();
    }

    public Object getValue() {
        return clazz.cast(value);
    }

}

パラメータマップを作成してみてください

 public class Main {

        public static void main(String[] args) {
            Map<String,Parameter> _params = new HashMap<String, Parameter>();
            _params.put(ParameterKeys.SERIAL_NUMBER, new Parameter(1));
                 _params.put(ParameterKeys.SEARCH_KEY, new Parameter("query"));
            _params.put(ParameterKeys.FROM_DATE, new Parameter(new Date()));
            _params.put(ParameterKeys.ISVALID, new Parameter(1));
        System.out.println(_params.get(ParameterKeys.SERIAL_NUMBER).getValue().getClass().getCanonicalName());
    System.out.println(_params.get(ParameterKeys.SEARCH_KEY).getValue().getClass().getCanonicalName());     System.out.println(_params.get(ParameterKeys.FROM_DATE).getValue().getClass().getCanonicalName());    System.out.println(_params.get(ParameterKeys.FROM_DATE).getValue().getClass().getCanonicalName());

        }

    }

出力は次のようになります。

java.lang.Integer
java.lang.String
java.util.Date
java.lang.Boolean

このマップをさまざまなレベルに渡すことができます

于 2012-08-02T05:20:22.330 に答える
0

実行時の処理で十分な場合は、これを試すことができます

public enum ParameterKeys {

  SERIAL_NUMBER {
      public Class<?> getType() {
          return Integer.class;
      }
  },
  SEARCH_KEY{
      public Class<?> getType() {
          return String.class;
      }
  },
  FROM_DATE{
      public Class<?> getType() {
          return Date.class;
      }
  },
  ISVALID{
      public Class<?> getType() {
          return Boolean.class;
      }
  };

public abstract Class<?> getType();

}

public class Parameter {

private Object value;
private Class<?> clazz;
private ParameterKeys key;

public Parameter(Object value,ParameterKeys key) throws Exception {
    this.key = key;
    setValue(value);
}

public void setValue(Object value) throws Exception{
    this.value = value;
    this.clazz = value.getClass();
    if(!clazz.getCanonicalName().equals(key.getType().getCanonicalName())) {
        throw new Exception("Type Mismatch between Parameter Key : " + key + " and Value : " + value);
    }
}

public Object getValue() {
    return clazz.cast(value);
}

}

public class Main {

public static void main(String[] args) {
    Map<ParameterKeys,Parameter> _params = new HashMap<ParameterKeys, Parameter>();
    try {
    _params.put(ParameterKeys.SERIAL_NUMBER, new Parameter(1,ParameterKeys.SERIAL_NUMBER));
    _params.put(ParameterKeys.SEARCH_KEY, new Parameter("query",ParameterKeys.SEARCH_KEY));
    _params.put(ParameterKeys.FROM_DATE, new Parameter(new Date(),ParameterKeys.FROM_DATE));
    _params.put(ParameterKeys.FROM_DATE, new Parameter(true,ParameterKeys.FROM_DATE));
    } catch(Exception e) {
        System.out.println(e.getMessage());
    }

}

}

これにより、次の例外が出力されます

パラメータのキー: FROM_DATE と値: true の型の不一致

于 2012-08-02T07:48:06.740 に答える