View Javadoc

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 }