我有一组对象。此对象根据请求参数计算某些数字。我们称他们为计算器。每个计算器都有描述这个计算器最适合的指定类型的请求。 例如,
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一起做,但它并不适合这项任务。你能推荐我一些图书馆或方法吗?
答案 0 :(得分:2)
我的建议是使用比较器。请参阅以下课程的草图。
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关注价格较低的商品esp。如果他们是性别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) + ")");
}
}
}
这只是一个草图来说明这个想法。您可能希望为请求参数引入一个枚举,可能会引入一个Request类,很可能完全改变计算适应性的方法,将某些字段设为私有并封装它们等等。
优势在于您可以根据请求的适用性轻松获得所有计算器的订购。
答案 1 :(得分:1)
您可以尝试这样的事情:
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 )
答案 2 :(得分:1)
如果我理解正确,我建议您使用Specification设计模式,这种模式在这种情况下使用。像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);
答案 3 :(得分:0)
创建一个计算器基类:
public static abstract class Calculator {
// This Contains the common score calculation methods.
public int getScore(int price, String gender, int geo_id) {
int score = 0;
if (gender.equalsIgnoreCase("male"))
score++;
if (getGeoIds().contains(geo_id))
score++;
return score;
}
public ArrayList<Integer> getGeoIds() {
// Fetching the common list of geo points to be compared.
ArrayList<Integer> lst = new ArrayList<Integer>();
lst.add(1);
lst.add(2);
return lst;
}
public abstract void doCalculation();
}
然后通过从此基础扩展来创建计算器类。
public static class Calcualtor1 extends Calculator {
@Override
public int getScore(int price, String gender, int geo_id) {
// fetching score from common score calculation.
int score = super.getScore(price, gender, geo_id);
// Adding its own score logic.
if (price > 10)
score++;
return score;
}
@Override
public void doCalculation() {
// Do your actual work.
}
@Override
public ArrayList<Integer> getGeoIds() {
ArrayList<Integer> lst = super.getGeoIds();
// Adding the geo id to compare for this calculator.
lst.add(3);
return lst;
}
}
public static class Calcualtor2 extends Calculator {
@Override
public int getScore(int price, String gender, int geo_id) {
// fetching score from common score calculation.
int score = super.getScore(price, gender, geo_id);
// Adding its own score logic.
if (price < 5)
score++;
return score;
}
@Override
public void doCalculation() {
// Do your actual work.
}
}
初始值:
//To store the list of available calculators.
private static ArrayList<Class<? extends Calculator>> calculators;
static {
//Initializing the calculator list in static constructor.
calculators = new ArrayList<Class<? extends Calculator>>();
calculators.add(Calcualtor1.class);
calculators.add(Calcualtor2.class);
}
实际处理:
public static void main(String[] args) {
int price = 10;
String gender = "male";
int geo_id = 2;
Calculator calculator = null;
int score = 0;
for (Class<? extends Calculator> calClass : calculators) {
Calculator cal = null;
try {
cal = calClass.newInstance();
} catch (Exception e) {
continue;
}
int calScore = cal.getScore(price, gender, geo_id);
if (calScore > score) {
calculator = cal;
score = calScore;
}
}
if (calculator != null) {
calculator.doCalculation();
}
}