1 /* 2 * Copyright 2006-2010 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package net.sourceforge.domian.specification; 17 18 19 /** 20 * Part of the Evans/Fowler <i>Specifications</i> pattern. 21 * <p/> 22 * <i>Note on type parameterization</i>:<br/> 23 * Domian specifications are typed. 24 * It is only relevant to send candidate objects of correct type to a {@link Specification} for approval. 25 * Generics should be used when creating specifications, making this specification type vs. candidate type a compile-time issue. 26 * 27 * @author Eirik Torske 28 * @see <a href="http://www.martinfowler.com/apsupp/spec.pdf">The Specifications Pattern</a> 29 * @since 0.1 30 */ 31 public interface Specification<T> { 32 33 ////////////////////////////// 34 // Generators/Builders 35 ////////////////////////////// 36 37 /** 38 * Alias of <code>and</code> method. 39 * 40 * @param accessibleObjectName the name of the accessible object to specify 41 * @param accessibleObjectSpecification the specification coupled to the accessible object 42 * @param <F> the type of the accessible object to specify 43 * @return a conjunction of this specification and the accessible object specification 44 * @throws IllegalArgumentException if any of the parameters are null 45 * @throws UnsupportedOperationException if this method is called <i>twice</i> in the overall specification expression (<i>fluent interface constraint</i>) 46 */ 47 <F> CompositeSpecification<T> where(String accessibleObjectName, Specification<F> accessibleObjectSpecification); 48 49 /** 50 * Creates a <i>conjunction</i> of two specifications: 51 * <ol> 52 * <li/>This composite specification 53 * <li/>A parameterized specification based on the <code>java.lang.reflect.AccessibleObject</code> name parameter and the accompanying specification parameter 54 * </ol> 55 * 56 * @param otherSpecification the specification to combine with this specification 57 * @return a new composite specification: this specification <i><b>AND</b></i> the parameterized specification 58 * @throws IllegalArgumentException if any of the parameters are null 59 * @throws IllegalArgumentException if the accessible object name is illegal 60 * @throws IllegalArgumentException if the type of the accessible object and the type of the specification are not compatible 61 * @throws UnsupportedOperationException if this method is not placed behind a <i>where</i> clause in the overall specification expression (<i>fluent interface constraint</i>) 62 */ 63 CompositeSpecification<T> and(Specification<? super T> otherSpecification); 64 65 // TODO: consider... 66 //CompositeSpecification<T> but(Specification<? extends T> otherSpecification); 67 68 /** 69 * Creates a <i>disjunction</i> out of two specifications: 70 * <ol> 71 * <li/>This composite specification 72 * <li/>The given specification parameter 73 * </ol> 74 * 75 * @param otherSpecification the specification to combine with this specification 76 * @return a new composite specification: this specification <i><b>OR</b></i> the specification parameter 77 * @throws IllegalArgumentException if the parameter is null 78 */ 79 CompositeSpecification<T> or(Specification<? super T> otherSpecification); 80 81 82 ////////////////////////////// 83 // Analysis 84 ////////////////////////////// 85 86 /** @return the specification type */ 87 Class<T> getType(); 88 89 /** 90 * <i>Specification satisfaction.</i> 91 * 92 * @param candidate The candidate object 93 * @return <code>true</code> only if this specification is <i>satisfied by/approves</i> the given candidate (<code>null</code> is never approved) 94 */ 95 Boolean isSatisfiedBy(T candidate); 96 97 /** 98 * <i>Specification subsumption.</i> 99 * <p/> 100 * Given: 101 * <ol> 102 * <li/><code>Set K consisting of candidates specified by specA : specA.isSatisfiedBy(candidate)</code> 103 * <li/><code>Set L consisting of candidates specified by specB : specB.isSatisfiedBy(candidate)</code> 104 * </ol> 105 * Then:<br/> 106 * <code>if specA.isGeneralizationOf(specB) => Set K contains Set L [Set K UNION Set L = Set K]</code> 107 * 108 * @param otherSpecification The candidate specification 109 * @return <code>true</code> only if this specification is <i>a generalization</i> of the given candidate specification 110 * @throws IllegalArgumentException if parameter is null 111 * @since 0.3 112 */ 113 Boolean isGeneralizationOf(Specification<? extends T> otherSpecification); 114 115 /** 116 * <i>Specification subsumption.</i> 117 * <p/> 118 * Given: 119 * <ol> 120 * <li/><code>Set K consisting of candidates specified by specA : specA.isSatisfiedBy(candidate)</code> 121 * <li/><code>Set L consisting of candidates specified by specB : specB.isSatisfiedBy(candidate)</code> 122 * </ol> 123 * Then:<br/> 124 * <code>if specA.isSpecializationOf(specB) => Set L contains Set K [Set K UNION Set L = Set L]</code> 125 * 126 * @param otherSpecification The candidate specification 127 * @return <code>true</code> only if this specification is <i>a special case</i> of the given candidate specification 128 * @throws IllegalArgumentException if parameter is null 129 * @since 0.3 130 */ 131 Boolean isSpecialCaseOf(Specification<? super T> otherSpecification); 132 133 /** 134 * Two specifications are <i>disjoint</i> if the two sets of satisfiable objects have no objects in common. 135 * 136 * @param otherSpecification The candidate specification 137 * @return <code>true</code> only if this specification is <i>disjoint</i> with the given candidate specification 138 * @throws IllegalArgumentException if parameter is null 139 * @since 0.5 140 */ 141 // TODO: is this the appropriate type parameterization? 142 Boolean isDisjointWith(Specification<?> otherSpecification); 143 144 // TODO: consider... 145 //Boolean isIntersectionOf(Specification specification); 146 // TODO: ...and 147 //Boolean intersectsWith(Specification specification); 148 149 // TODO v0.5.1: to be included, I guess... 150 //String specificationToString(); 151 }