rinde.sim.util.spec.Specification Maven / Gradle / Ivy
/**
*
*/
package rinde.sim.util.spec;
/**
* A specification implementation inspired by the specification
* pattern. It can be used to easily recombine specifications (i.e.
* conditions) into arbitrary complex specifications.
*
* Example:
*
*
* ISpecification<Object> TRUE = new ISpecification<Object>() {
* @Override
* public boolean isSatisfiedBy(Object context) {
* return true;
* }
* };
* ISpecification<Object> IS_NULL = new ISpecification<Object>() {
* @Override
* public boolean isSatisfiedBy(Object context) {
* return context == null;
* }
* };
* Specification.of(TRUE).not().orNot(IS_NULL).and(TRUE).build()
* .isSatisfiedBy(null);
*
*
* The above example only returns true
when
* {@link ISpecification#isSatisfiedBy(Object)} is supplied with a non-null
* object.
* @author Rinde van Lon
*/
// FIXME replace with Predicates?
public final class Specification {
private Specification() {}
/**
* Start creating a new {@link ISpecification} instance using the specified
* instance as a base.
* @param base The {@link ISpecification} to use as base.
* @param The type of specification.
* @return A reference to a builder for creating {@link ISpecification}
* instances.
*/
public static Builder of(ISpecification base) {
return new Builder(base);
}
/**
* A specification or condition.
* @param The type that is used in the {@link #isSatisfiedBy(Object)}
* method.
* @author Rinde van Lon
*/
public interface ISpecification {
/**
* @param context The context to inspect.
* @return true
if this specification is satisfied by the
* specified context object, false
otherwise.
*/
boolean isSatisfiedBy(T context);
}
/**
* A builder for recombining {@link ISpecification}s.
* @param The type of the {@link ISpecification}.
* @author Rinde van Lon
*/
public static final class Builder {
private ISpecification specification;
Builder(ISpecification spec) {
this.specification = spec;
}
/**
* Recombines the current specification with the specified spec using the
* logical AND operator.
* @param spec The specification to add.
* @return This builder.
*/
public Builder and(ISpecification spec) {
specification = new AndSpecification(specification, spec);
return this;
}
/**
* First applies the NOT operator to the specified spec and then recombines
* it with the current spec using the logical AND operator.
* @param spec The specification to add.
* @return This builder.
*/
public Builder andNot(ISpecification spec) {
return and(new NotSpecification(spec));
}
/**
* Recombines the current specification with the specified spec using the
* logical OR operator.
* @param spec The specification to add.
* @return This builder.
*/
public Builder or(ISpecification spec) {
specification = new OrSpecification(specification, spec);
return this;
}
/**
* First applies the NOT operator to the specified spec and then recombines
* it with the current spec using the logical OR operator.
* @param spec The specification to add.
* @return This builder.
*/
public Builder orNot(ISpecification spec) {
return or(new NotSpecification(spec));
}
/**
* Recombines the current specification with the specified spec using the
* logical XOR operator.
* @param spec The specification to add.
* @return This builder.
*/
public Builder xor(ISpecification spec) {
specification = new XorSpecification(specification, spec);
return this;
}
/**
* Negates the current specification.
* @return This builder.
*/
public Builder not() {
specification = new NotSpecification(specification);
return this;
}
/**
* @return The new specification.
*/
public ISpecification build() {
return specification;
}
}
static final class AndSpecification implements ISpecification {
private final ISpecification spec1;
private final ISpecification spec2;
AndSpecification(ISpecification one, ISpecification other) {
spec1 = one;
spec2 = other;
}
@Override
public boolean isSatisfiedBy(T context) {
return spec1.isSatisfiedBy(context) && spec2.isSatisfiedBy(context);
}
}
static final class OrSpecification implements ISpecification {
private final ISpecification spec1;
private final ISpecification spec2;
OrSpecification(ISpecification one, ISpecification other) {
spec1 = one;
spec2 = other;
}
@Override
public boolean isSatisfiedBy(T context) {
return spec1.isSatisfiedBy(context) || spec2.isSatisfiedBy(context);
}
}
static final class NotSpecification implements ISpecification {
private final ISpecification spec;
NotSpecification(ISpecification specification) {
spec = specification;
}
@Override
public boolean isSatisfiedBy(T context) {
return !spec.isSatisfiedBy(context);
}
}
static final class XorSpecification implements ISpecification {
private final ISpecification spec1;
private final ISpecification spec2;
XorSpecification(ISpecification one, ISpecification other) {
spec1 = one;
spec2 = other;
}
@Override
public boolean isSatisfiedBy(T context) {
return spec1.isSatisfiedBy(context) != spec2.isSatisfiedBy(context);
}
}
}