Adding composite specification (Issue#1093) (#1094)

* Resolution proposition to Issue#1055 (UML diagram left to do)

* Deciding not to modify the UML diagram for now

* Resolution proposition to Issue#1093

* Code reformatting
This commit is contained in:
Martin Vandenbussche
2019-11-17 13:25:32 +01:00
committed by Ilkka Seppälä
parent 19b129c28e
commit 73f9b8bef1
20 changed files with 494 additions and 75 deletions

View File

@ -31,9 +31,10 @@ import com.iluwatar.specification.creature.Octopus;
import com.iluwatar.specification.creature.Shark;
import com.iluwatar.specification.creature.Troll;
import com.iluwatar.specification.property.Color;
import com.iluwatar.specification.property.Mass;
import com.iluwatar.specification.property.Movement;
import com.iluwatar.specification.selector.AbstractSelector;
import com.iluwatar.specification.selector.ColorSelector;
import com.iluwatar.specification.selector.MassEqualSelector;
import com.iluwatar.specification.selector.MassGreaterThanSelector;
import com.iluwatar.specification.selector.MassSmallerThanOrEqSelector;
import com.iluwatar.specification.selector.MovementSelector;
@ -77,13 +78,8 @@ public class App {
List<Creature> darkCreatures =
creatures.stream().filter(new ColorSelector(Color.DARK)).collect(Collectors.toList());
darkCreatures.forEach(c -> LOGGER.info(c.toString()));
// find all red and flying creatures
LOGGER.info("Find all red and flying creatures");
List<Creature> redAndFlyingCreatures =
creatures.stream()
.filter(new ColorSelector(Color.RED).and(new MovementSelector(Movement.FLYING)))
.collect(Collectors.toList());
redAndFlyingCreatures.forEach(c -> LOGGER.info(c.toString()));
LOGGER.info("\n");
// so-called "parameterized" specification
LOGGER.info("Demonstrating parameterized specification :");
// find all creatures heavier than 500kg
@ -98,5 +94,26 @@ public class App {
creatures.stream().filter(new MassSmallerThanOrEqSelector(500.0))
.collect(Collectors.toList());
lightCreatures.forEach(c -> LOGGER.info(c.toString()));
LOGGER.info("\n");
// so-called "composite" specification
LOGGER.info("Demonstrating composite specification :");
// find all red and flying creatures
LOGGER.info("Find all red and flying creatures");
List<Creature> redAndFlyingCreatures =
creatures.stream()
.filter(new ColorSelector(Color.RED).and(new MovementSelector(Movement.FLYING)))
.collect(Collectors.toList());
redAndFlyingCreatures.forEach(c -> LOGGER.info(c.toString()));
// find all creatures dark or red, non-swimming, and heavier than or equal to 400kg
LOGGER.info("Find all scary creatures");
AbstractSelector<Creature> scaryCreaturesSelector = new ColorSelector(Color.DARK)
.or(new ColorSelector(Color.RED)).and(new MovementSelector(Movement.SWIMMING).not())
.and(new MassGreaterThanSelector(400.0).or(new MassEqualSelector(400.0)));
List<Creature> scaryCreatures =
creatures.stream()
.filter(scaryCreaturesSelector)
.collect(Collectors.toList());
scaryCreatures.forEach(c -> LOGGER.info(c.toString()));
}
}

View File

@ -23,7 +23,9 @@
package com.iluwatar.specification.property;
/** Mass property. */
/**
* Mass property.
*/
public class Mass {
private double value;

View File

@ -0,0 +1,44 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.specification.selector;
import java.util.function.Predicate;
/**
* Base class for selectors.
*/
public abstract class AbstractSelector<T> implements Predicate<T> {
public AbstractSelector<T> and(AbstractSelector<T> other) {
return new ConjunctionSelector<>(this, other);
}
public AbstractSelector<T> or(AbstractSelector<T> other) {
return new DisjunctionSelector<>(this, other);
}
public AbstractSelector<T> not() {
return new NegationSelector<>(this);
}
}

View File

@ -25,12 +25,11 @@ package com.iluwatar.specification.selector;
import com.iluwatar.specification.creature.Creature;
import com.iluwatar.specification.property.Color;
import java.util.function.Predicate;
/**
* Color selector.
*/
public class ColorSelector implements Predicate<Creature> {
public class ColorSelector extends AbstractSelector<Creature> {
private final Color color;

View File

@ -0,0 +1,47 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.specification.selector;
import java.util.List;
/**
* A Selector defined as the conjunction (AND) of other (leaf) selectors.
*/
public class ConjunctionSelector<T> extends AbstractSelector<T> {
private List<AbstractSelector<T>> leafComponents;
@SafeVarargs
ConjunctionSelector(AbstractSelector<T>... selectors) {
this.leafComponents = List.of(selectors);
}
/**
* Tests if *all* selectors pass the test.
*/
@Override
public boolean test(T t) {
return leafComponents.stream().allMatch(comp -> (comp.test(t)));
}
}

View File

@ -0,0 +1,47 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.specification.selector;
import java.util.List;
/**
* A Selector defined as the disjunction (OR) of other (leaf) selectors.
*/
public class DisjunctionSelector<T> extends AbstractSelector<T> {
private List<AbstractSelector<T>> leafComponents;
@SafeVarargs
DisjunctionSelector(AbstractSelector<T>... selectors) {
this.leafComponents = List.of(selectors);
}
/**
* Tests if *at least one* selector passes the test.
*/
@Override
public boolean test(T t) {
return leafComponents.stream().anyMatch(comp -> comp.test(t));
}
}

View File

@ -0,0 +1,47 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.specification.selector;
import com.iluwatar.specification.creature.Creature;
import com.iluwatar.specification.property.Mass;
/**
* Mass selector for values exactly equal than the parameter.
*/
public class MassEqualSelector extends AbstractSelector<Creature> {
private final Mass mass;
/**
* The use of a double as a parameter will spare some typing when instantiating this class.
*/
public MassEqualSelector(double mass) {
this.mass = new Mass(mass);
}
@Override
public boolean test(Creature t) {
return t.getMass().equals(mass);
}
}

View File

@ -25,14 +25,17 @@ package com.iluwatar.specification.selector;
import com.iluwatar.specification.creature.Creature;
import com.iluwatar.specification.property.Mass;
import java.util.function.Predicate;
/** Mass selector for values greater than the parameter. */
public class MassGreaterThanSelector implements Predicate<Creature> {
/**
* Mass selector for values greater than the parameter.
*/
public class MassGreaterThanSelector extends AbstractSelector<Creature> {
private final Mass mass;
/** The use of a double as a parameter will spare some typing when instantiating this class. */
/**
* The use of a double as a parameter will spare some typing when instantiating this class.
*/
public MassGreaterThanSelector(double mass) {
this.mass = new Mass(mass);
}

View File

@ -25,14 +25,17 @@ package com.iluwatar.specification.selector;
import com.iluwatar.specification.creature.Creature;
import com.iluwatar.specification.property.Mass;
import java.util.function.Predicate;
/** Mass selector for values smaller or equal to the parameter. */
public class MassSmallerThanOrEqSelector implements Predicate<Creature> {
/**
* Mass selector for values smaller or equal to the parameter.
*/
public class MassSmallerThanOrEqSelector extends AbstractSelector<Creature> {
private final Mass mass;
/** The use of a double as a parameter will spare some typing when instantiating this class. */
/**
* The use of a double as a parameter will spare some typing when instantiating this class.
*/
public MassSmallerThanOrEqSelector(double mass) {
this.mass = new Mass(mass);
}

View File

@ -25,12 +25,11 @@ package com.iluwatar.specification.selector;
import com.iluwatar.specification.creature.Creature;
import com.iluwatar.specification.property.Movement;
import java.util.function.Predicate;
/**
* Movement selector.
*/
public class MovementSelector implements Predicate<Creature> {
public class MovementSelector extends AbstractSelector<Creature> {
private final Movement movement;

View File

@ -0,0 +1,46 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.specification.selector;
/**
* A Selector defined as the negation (NOT) of a (leaf) selectors. This is of course only useful
* when used in combination with other composite selectors.
*/
public class NegationSelector<T> extends AbstractSelector<T> {
private AbstractSelector<T> component;
NegationSelector(AbstractSelector<T> selector) {
this.component = selector;
}
/**
* Tests if the selector fails the test (yes).
*/
@Override
public boolean test(T t) {
return !(component.test(t));
}
}

View File

@ -25,12 +25,11 @@ package com.iluwatar.specification.selector;
import com.iluwatar.specification.creature.Creature;
import com.iluwatar.specification.property.Size;
import java.util.function.Predicate;
/**
* Size selector.
*/
public class SizeSelector implements Predicate<Creature> {
public class SizeSelector extends AbstractSelector<Creature> {
private final Size size;