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 }