2015-08-23 12 views
5

Ho la seguente mappa dei criteri di ricerca:parametri Passo a Predicati

private final Map<String, Predicate> searchMap = new HashMap<>(); 

private void initSearchMap() { 
    Predicate<Person> allDrivers = p -> p.getAge() >= 16; 
    Predicate<Person> allDraftees = p -> p.getAge() >= 18 
      && p.getAge() <= 25 
      && p.getGender() == Gender.MALE; 
    Predicate<Person> allPilots = p -> p.getAge() >= 23 
      && p.getAge() <=65; 

    searchMap.put("allDrivers", allDrivers); 
    searchMap.put("allDraftees", allDraftees); 
    searchMap.put("allPilots", allPilots); 
} 

sto usando questa mappa nel modo seguente:

pl.stream() 
    .filter(search.getCriteria("allPilots")) 
    .forEach(p -> { 
     p.printl(p.getPrintStyle("westernNameAgePhone")); 
    }); 

Vorrei sapere, come posso passare alcuni parametri nella mappa dei predicati?

I.e. Vorrei ottenere un predicato da una mappa tramite la sua stringa abbreviata e inserire un parametro nell'estratto da un predicato di mappa.

pl.stream() 
    .filter(search.getCriteria("allPilots",45, 56)) 
    .forEach(p -> { 
     p.printl(p.getPrintStyle("westernNameAgePhone")); 
    }); 

Ecco la link da Googled questo approccio mappa-predicato.

+1

ciò che si vorrebbe fare sarebbe non compilare, e non hai spiegato cosa dovrebbe fare. –

+0

Ho appena dato un esempio. Certo, non verrà compilato. Ecco cosa mi piacerebbe fare: vorrei ottenere un predicato da una mappa con la sua stringa abbreviata e inserire un parametro nell'estratto da un predicato di mappa. –

+1

Per quale parametro verrà utilizzato? Qual è l'obiettivo di 45 nel tuo esempio? –

risposta

4

Sembra che ciò che si desidera non sia memorizzare un predicato in una mappa. Quello che vuoi è essere in grado di memorizzare qualcosa in una mappa che è in grado di creare un Predicate<Person> da un parametro int. Quindi, ciò che si vuole è qualcosa di simile:

Map<String, IntFunction<Predicate<Person>>> searchMap = new HashMap<>(); 

Si potrebbe riempire in questo modo:

searchMap.put("allPilots", maxAge -> 
    (p -> p.getAge() >= 23 
    && p.getAge() <= maxAge)); 

E woult usare in questo modo:

Predicate<Person> allPilotsAgedLessThan45 = 
    searchMap.get("allPilots").apply(45); 

Naturalmente, che avrebbe essere più chiaro se hai creato la tua interfaccia di funzione:

@FunctionalInterface 
public MaxAgePersonPredicateFactory { 
    Predicate<Person> limitToMaxAge(int maxAge); 
} 

Si potrebbe ancora riempire la mappa nello stesso modo, ma si dovrebbe quindi avere il codice un po 'più leggibili dalla quando lo si utilizza:

Predicate<Person> allPilotsAgedLessThan45 = 
    searchMap.get("allPilots").limitToMaxAge(45); 
+0

Esattamente quello che stavo cercando. Grazie! –

+1

Dato che l'OP vuole passare in due parametri int, questa non dovrebbe essere una BiFunzione > invece di un IntFunction? – KumarM

+0

@KumarM Ho perso il secondo parametro nella domanda e ho notato solo il 45. Ma sì, se ha bisogno di due parametri, la firma della fabbrica dovrà cambiare. –

1

Da quanto ho capito, ciò che si vuole fare è ignorare alcuni parametri in una chiamata Predicate , ma penso che questo porterà alla confusione. Se sto chiedendo il predicato che determina se qualcuno è eleggibile per essere un pilota, non voglio dovermi preoccupare di sapere quali siano i requisiti al momento in cui lo chiamo.

Generazione predicati al volo utilizzando un Map sarebbe difficile - penserei che il modo più bello sarebbe quello di avere invece un Map<String, PredicateFactory>, dove il PredicateFactory è una sorta di classe complicato che genera predicati dato alcuni parametri:

Map<String, PredicateFactory<T>> predicates = new HashMap<>(); 

public Predicate<T> get(String name, Object... params) { 
    return predicates.get(name).apply(params); 
} 

a mio parere, il modo migliore per generare "dinamici" predicati è con metodi statici:

public class PredicatesQuestion { 

    public static void main(String[] args) { 
     List<Person> people = Arrays.asList(new Person(20, Gender.MALE), 
       new Person(45, Gender.FEMALE), new Person(50, Gender.MALE), 
       new Person(65, Gender.MALE)); 

     people.stream() 
       .filter(personIsBetweenAges(16, 25)) 
       .forEach(person -> { 
        System.out.println(person.getAge() + ", " + person.getGender()); 
       }); 
    } 

    private static Predicate<Person> personIsMale() { 
     return person -> person.getGender() == Gender.MALE; 
    } 

    private static Predicate<Person> personIsBetweenAges(int lower, int upper) { 
     return personIsAtLeast(lower).and(personIsYoungerThan(upper)); 
    } 

    private static Predicate<Person> personIsAtLeast(int age) { 
     return person -> person.getAge() >= age; 
    } 

    private static Predicate<Person> personIsYoungerThan(int age) { 
     return person -> person.getAge() < age; 
    } 
} 

E 'quindi banale per creare predicati descrittivi come richiesto:

private static Predicate<Person> personIsOfDrivingAge() { 
    return personIsAtLeast(17); 
} 

private static Predicate<Person> couldBePilot() { 
    return personIsBetweenAges(23, 65).and(personIsMale()); 

} 

E il genere di cosa si sta cercando di raggiungere con l'override alcuni parametri rimane chiaro con un po 'di composizione:

people.stream() 
     .filter(couldBePilot().and(personIsBetweenAges(45, 56))) 
     .forEach(person -> { 
      System.out.println(person.getAge() + ", " + person.getGender()); 
     });