我有一套东西。该对象根据请求参数计算某些数字。我们叫他们计算器吧。每个计算器都有此计算器最适合的特定类型请求的说明。例如,
Calculator1 : with this parameters : price > 10, gender = male, geo_id = 1, 2 or 3.
Calculator2 : with this parameters : price < 5, gender = male, geo_id = 1, 2. 对于请求:price = 11, gender = male, geo_id = 2,我应该得到最合适的calculator1,然后是calculator2。
对于请求:price = 4, gender = male, geo_id = 2,我应该得到calculator2,然后是calculator1。
对于请求:price = 3, gender = female, geo_id = 5,我应该只得到第二个。
现在我和Lucene一起做了,但是它并不适合这个任务。你能给我推荐一些图书馆或方法吗?
发布于 2014-01-22 12:08:44
我的建议是使用比较器。请看下面课程的草图。
import java.util.HashMap;
import java.util.Map;
public abstract class Calculator {
public static Map<String, Integer> weights;
static {
weights = new HashMap<String, Integer>();
weights.put("price", 10);
weights.put("gender", 2);
weights.put("geo", 5);
}
public abstract int calculate(Map<String, Integer> request);
public abstract int fitnessFor(Map<String, Integer> request);
}您可以使用权重来调整单个请求参数的相对重要性。
import java.util.Map;
public class Calculator1 extends Calculator {
public int calculate(Map<String, Integer> request) {
return -1;
}
@Override
public int fitnessFor(Map<String, Integer> request) {
int fitness = -1;
Integer price = request.get("price");
if (price == null)
return fitness;
if (price > 10)
fitness += weights.get("price");
return fitness;
}
public String toString() { return "Calculator1"; }
}Calculator1只关心昂贵的物品。
import java.util.Map;
public class Calculator2 extends Calculator {
public int calculate(Map<String, Integer> request) {
return -1;
}
@Override
public int fitnessFor(Map<String, Integer> request) {
int fitness = -1;
Integer price = request.get("price");
if (price == null)
return fitness;
if (price < 5)
fitness += weights.get("price");
Integer gender = request.get("gender");
if (gender == null)
return fitness;
if (gender == 1)
fitness += weights.get("gender");
return fitness;
}
public String toString() { return "Calculator2"; }
}Calculator2关心的是价格较低的商品(尤指价格较低的商品)。如果是性别1。
比较器只是比较计算器相对于请求的适配性:
import java.util.Comparator;
import java.util.Map;
public class CalcComparator implements Comparator<Calculator> {
private Map<String, Integer> request;
public CalcComparator(Map<String, Integer> request) {
this.request = request;
}
@Override
public int compare(Calculator c1, Calculator c2) {
int c1Fitness = c1.fitnessFor(request);
int c2Fitness = c2.fitnessFor(request);
if (c1Fitness == c2Fitness)
return 0;
if (c1Fitness < c2Fitness)
return 1;
return -1;
}
}试一试:
public class Main {
public static void main(String[] args) {
Map<String, Integer> request = new HashMap<String, Integer>();
request.put("price", 5);
request.put("gender", 1);
List<Calculator> calculators = new ArrayList<Calculator>();
calculators.add(new Calculator1());
calculators.add(new Calculator2());
Collections.sort(calculators, new CalcComparator(request));
System.out.println("For request: "+request);
for (Calculator c : calculators) {
System.out.println("\t"+c.toString() + "( fitness " + c.fitnessFor(request) + ")");
}
}
}这只是一个说明这个想法的草图。您可能希望为请求参数引入一个枚举,可能会引入一个请求类,很可能完全改变适应度的计算方式,使某些字段成为私有字段并封装它们,等等。
其优点是,您可以根据所有计算器的适合性,轻松地获得它们的排序。
发布于 2014-01-22 11:07:45
你也许可以试试这样的方法:
public enum Calculator
{
CALC1
{
@Override
protected int matchCount( Map parameters )
{
// TODO count how many conditions match
return 0;
}
@Override
protected int calc( Map parameters )
{
// TODO
return 0;
}
},
CALC2
{
@Override
protected int matchCount( Map parameters )
{
// TODO count how many conditions match
return 0;
}
@Override
protected int calc( Map parameters )
{
// TODO
return 0;
}
};
protected abstract int matchCount( Map parameters );
protected abstract int calc( Map parameters );
public int doCalc( Map parameters )
{
Calculator mostSuited = null;
int maxCount = 0;
for ( Calculator calc : values() )
{
int matchCount = calc.matchCount( parameters );
if ( matchCount > maxCount )
{
mostSuited = calc;
}
}
return mostSuited.calc( parameters );
}
}使用上面的方法是通过调用:int result = Calculator.doCalc( parameters )
发布于 2014-01-22 11:19:58
如果我正确地理解了您,我建议您使用规格说明设计模式,这种模式在这种情况下是使用的。像Lucene这样的高级图书馆不需要这样简单的任务。规范模式的优点是它将所有过滤逻辑分组和封装。您的实现可能会有所不同,但下面是一个简单的示例,说明了它的样子。
public interface Specification<T> {
boolean isSatisfiedBy(T candidate);
Specification<T> and(Specification<T> specification);
Specification<T> or(Specification<T> specification);
Specification<T> not(Specification<T> specification);
}
public abstract class Calculator {
// ...
}
public class Calculator1 extends Calculator implements Specification<Request> {
public boolean isSatisfiedBy(Request request) {
// check if the request fits this calculator
}
}
public class Calculator2 extends Calculator implements Specification<Request> {
public boolean isSatisfiedBy(Request request) {
// check if the request fits this calculator
}
}然后,您可以拥有一个集合或一个计算器池,以便
public class Calculators {
private final List<RequestSpecification> calculators;
public Calculator getOneSuitedFor(Request request) {
for (Calculator calculator : calculators) {
if (calculator.isSatisfiedBy(request)) {
return calculator;
}
}
return null;
}
}在这里,你将如何使用它
Calculator calculator = Calculators.getOneSuitedFor(request);或者,如果需要,您可以通过使用组合(参见上面的参考链接)来继续并扩展它,这允许根据上下文的不同规范进行逻辑链接和组合。然而,这将需要与上面的类设计略有不同,但更灵活。
final Request request;
Specification<Calculator> price = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.supportsPrice(request.getPrice());
}
};
Specification<Calculator> gender = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.supportsGender(request.getGender());
}
};
Specification<Calculator> region = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.supportsRegion(request.getRegion());
}
};
Specification calcSpec = price.and(gender).and(region);
boolean isSatisfied = calcSpec.isSatisfiedBy(calculator);另一个有趣的例子是使用命名规范。
Specification<Calculator> teenager = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.getAge() >= 13 && calculator.getAge() <= 19;
}
};
Specification<Calculator> male = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.getGender().equals("male");
}
};
Specification<Calculator> fromEurope = new Specification<>() {
public boolean isSatisfiedBy(Calculator calculator) {
return calculator.getRegion().equals("Europe");
}
};
Specification<Calculator> calcSpec = teenager.and(male).and(fromEurope);
boolean isSatisfied = calcSpec.isSatisfiedBy(calculator);https://stackoverflow.com/questions/21277865
复制相似问题