Tyvrel, wziąłem pod uwagę Twoje porady, dzięki. Mniej więcej tak to robiłem tylko znacznie bardziej burdelowo. Co powiecie na taką implementację:
App:
Scrapper<Integer> ageScrapper = new ScrapperAgeFactory.produceDefault();
Optional<Integer> age = ageScrapper .scrapeFrom(text).findFirst();
główny scrapper, który wyciąga wartości zmiennej:
public class Scrapper<T> {
private final TextCleaner textCleaner;
private final LinesFindingStrategy linesFinderStrategy;
private final VariableFindingService <T> varFindingServiceLineFound;
private final VariableFindingService <T> varFindingServiceLineNotFound;
private final Predicate<T> isTraitValueValid;
private Scrapper(Builder<T> builder) {
// inicjowanie pól builderem...
}
public List<T> scrapeFrom(String text) {
text = textCleaner.apply(text);
List<String> lines = linesFinderStrategy.find(text);
List<T> traitValues = lines.size() > 0 ?
varFindingServiceLineFound.find(lines.get(0)) :
varFindingServiceLineNotFound.find(text);
return traitValues.stream()
.filter(isTraitValueValid)
.collect(Collectors.toList());
}
public static class Builder<T> {
// implementacja buildera...
}
}
fabryka scrapper przykładowo dla zmiennej age
:
public interface ScrapperDefaultFactory<T> {
Scrapper<T> produceDefault();
}
public class ScrapperAgeFactory implements ScrapperDefaultFactory<Integer> {
@Override
public Scrapper<Integer> produceDefault() {
int maxAge = 120;
int minAge = 18;
return new Scrapper.Builder<Integer>()
.setTextCleaner(new TextCleanerDefault())
.setLineFindingStrategy(new LineFindingStrategyByKeyWord("wiek:?")) // nie dopisuje implementacji, zwyczajnie wyciąga linie tekstu ze słowem kluczowym
.setVarFindingServiceLineFound(new AgeFindingServiceFactory().produceDefaultLineFound())
.setVarFindingServiceLineNotFound(new AgeFindingServiceFactory().produceDefaultLineNotFound())
.setIsTraitValueValidPredicate(x -> x >= minAge && x <= maxAge)
.build();
}
}
Service zawierają wiele Strategy, które odpalają są odpalane po kolei przez serwis:
public class VariableFindingService<T> {
protected List<VariableFindingStrategy<T>> strategies = new LinkedList<>();
public List<T> find(String text) {
return strategies.stream()
.flatMap(strategy -> strategy.find(text).stream())
.collect(Collectors.toList());
}
public VariableFindingService<T> addFirst(VariableFindingStrategy<T> component) {
this.strategies .add(0, component);
return this;
}
public VariableFindingService<T> addLast(VariableFindingStrategy<T> component) {
this.strategies .add(component);
return this;
}
public void clearComponents() {
strategies onents.clear();
}
}
public class VariableFindingStrategy<T> {
private final String fragmentWithTraitPattern;
private final String traitPattern;
private final Function<String, T> normalizer;
public VariableFindingStrategy(String fragmentWithTraitPattern, String traitPattern, Function<String, T> normalizer) {
this.fragmentWithTraitPattern = fragmentWithTraitPattern;
this.traitPattern = traitPattern;
this.normalizer = normalizer;
}
public List<T> find(String text) {
return new PatternFinderFunction(fragmentWithTraitPattern).apply(text).stream() // PatternFinderFunction to zwykład funkcja do wyciągania paternów z tekstu, nie dopisuję implementacji
.flatMap(fragment -> new PatternFinderFunction(traitPattern).apply(fragment).stream())
.map(normalizer::apply)
.collect(Collectors.toList());
}
}
fabryka takiego strategy wyglądałaby przykładowo dla age
tak:
public class AgeFindingServiceFactory implements VariableFindingServiceDefaultLineFoundFactory<Integer>,
VariableFindingServiceDefaultLineNotFoundFactory<Integer> {
@Override
public VariableFindingService <Integer> produceDefaultLineFound() {
VariableFindingService <Integer> service = new VariableFindingService <>();
return service .addFirst(new VariableFindingStrategy <Integer>("\\d+ lat", "\\d+", Integer::parseInt))
.addFirst(new VariableFindingStrategy <Integer>("\\d+ mies.", "\\d+", x -> Integer.parseInt(x) * 12))
.addFirst(new VariableFindingStrategy <Integer>("\\d+ miesięcy", "\\d+", x -> Integer.parseInt(x) * 12))
//.addFirst(new VariableFindingStrategy <Integer>("rocznik \\d{2}", x -> sysdate() - todate("19" + x)))
.addFirst(new VariableFindingStrategy <Integer>("\\d+", "\\d+", x -> Integer.parseInt(x)));
}
@Override
public VariableFindingService <Integer> produceDefaultLineNotFound() {
VariableFindingService <Integer> service= new VariableFindingService <>();
return service.addFirst(new VariableFindingStrategy <Integer>("\\d+ lat", "\\d+", Integer::parseInt))
.addFirst(new VariableFindingStrategy <Integer>("\\d+ mies.", "\\d+", x -> Integer.parseInt(x) * 12))
.addFirst(new VariableFindingStrategy <Integer>("\\d+ miesięcy", "\\d+", x -> Integer.parseInt(x) * 12));
}
}
Może być?