Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
iluwatar committed Sep 13, 2020
1 parent e6cca86 commit 9c648cb
Showing 1 changed file with 43 additions and 25 deletions.
68 changes: 43 additions & 25 deletions specification/README.md
Expand Up @@ -9,36 +9,46 @@ tags:
---

## Also known as

Filter, Criteria

## Intent
Specification pattern separates the statement of how to match a
candidate, from the candidate object that it is matched against. As well as its
usefulness in selection, it is also valuable for validation and for building to
order.

Specification pattern separates the statement of how to match a candidate, from the candidate object
that it is matched against. As well as its usefulness in selection, it is also valuable for
validation and for building to order.

## Explanation

Real world example

> There is a pool of different creatures and we often need to select some subset of them.
> We can write our search specification such as "creatures that can fly", "creatures heavier than 500 kilograms", or as a combination of other search specifications, and then give it to the party that will perform the filtering.
> There is a pool of different creatures and we often need to select some subset of them. We can
> write our search specification such as "creatures that can fly", "creatures heavier than 500
> kilograms", or as a combination of other search specifications, and then give it to the party that
> will perform the filtering.
In Plain Words

> Specification pattern allows us to separate the search criteria from the object that performs the search.
> Specification pattern allows us to separate the search criteria from the object that performs the
> search.
Wikipedia says

> In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic.
> In computer programming, the specification pattern is a particular software design pattern,
> whereby business rules can be recombined by chaining the business rules together using boolean
> logic.
**Programmatic Example**

If we look at our creature pool example from above, we have a set of creatures with certain properties.
Those properties can be part of a pre-defined, limited set (represented here by the enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a Creature).
In this case, it is more appropriate to use what we call "parameterized specification", where the property value can be given as an argument when the Creature is instantiated, allowing for more flexibility.
A third option is to combine pre-defined and/or parameterized properties using boolean logic, allowing for near-endless selection possibilities (this is called "composite specification", see below).
The pros and cons of each approach are detailed in the table at the end of this document.
If we look at our creature pool example from above, we have a set of creatures with certain
properties. Those properties can be part of a pre-defined, limited set (represented here by the
enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a
Creature). In this case, it is more appropriate to use what we call "parameterized specification",
where the property value can be given as an argument when the Creature is instantiated, allowing for
more flexibility. A third option is to combine pre-defined and/or parameterized properties using
boolean logic, allowing for near-endless selection possibilities (this is called "composite
specification", see below). The pros and cons of each approach are detailed in the table at the end
of this document.

```java
public interface Creature {
Expand All @@ -50,7 +60,7 @@ public interface Creature {
}
```

And ``Dragon`` implementation looks like this.
And `Dragon` implementation looks like this.

```java
public class Dragon extends AbstractCreature {
Expand All @@ -61,7 +71,8 @@ public class Dragon extends AbstractCreature {
}
```

Now that we want to select some subset of them, we use selectors. To select creatures that fly, we should use ``MovementSelector``.
Now that we want to select some subset of them, we use selectors. To select creatures that fly, we
should use `MovementSelector`.

```java
public class MovementSelector extends AbstractSelector<Creature> {
Expand All @@ -79,7 +90,8 @@ public class MovementSelector extends AbstractSelector<Creature> {
}
```

On the other hand, when selecting creatures heavier than a chosen amount, we use ``MassGreaterThanSelector``.
On the other hand, when selecting creatures heavier than a chosen amount, we use
`MassGreaterThanSelector`.

```java
public class MassGreaterThanSelector extends AbstractSelector<Creature> {
Expand Down Expand Up @@ -111,7 +123,8 @@ But we could also use our parameterized selector like this:
.collect(Collectors.toList());
```

Our third option is to combine multiple selectors together. Performing a search for special creatures (defined as red, flying, and not small) could be done as follows:
Our third option is to combine multiple selectors together. Performing a search for special
creatures (defined as red, flying, and not small) could be done as follows:

```java
var specialCreaturesSelector =
Expand All @@ -123,8 +136,9 @@ Our third option is to combine multiple selectors together. Performing a search

**More on Composite Specification**

In Composite Specification, we will create custom instances of ``AbstractSelector`` by combining other selectors (called "leaves") using the three basic logical operators.
These are implemented in ``ConjunctionSelector``, ``DisjunctionSelector`` and ``NegationSelector``.
In Composite Specification, we will create custom instances of `AbstractSelector` by combining
other selectors (called "leaves") using the three basic logical operators. These are implemented in
`ConjunctionSelector`, `DisjunctionSelector` and `NegationSelector`.

```java
public abstract class AbstractSelector<T> implements Predicate<T> {
Expand Down Expand Up @@ -163,12 +177,14 @@ public class ConjunctionSelector<T> extends AbstractSelector<T> {
}
```

All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that are as generic as possible,
and we will be able to instantiate the ``AbstractSelector`` class by combining any amount of selectors, as exemplified above.
We should be careful though, as it is easy to make a mistake when combining many logical operators; in particular, we should pay attention to the priority of the operations.\
In general, Composite Specification is a great way to write more reusable code, as there is no need to create a Selector class for each filtering operation.
Instead, we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf" selectors and some basic boolean logic.

All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that
are as generic as possible, and we will be able to instantiate the ``AbstractSelector`` class by
combining any amount of selectors, as exemplified above. We should be careful though, as it is easy
to make a mistake when combining many logical operators; in particular, we should pay attention to
the priority of the operations. In general, Composite Specification is a great way to write more
reusable code, as there is no need to create a Selector class for each filtering operation. Instead,
we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf"
selectors and some basic boolean logic.

**Comparison of the different approaches**

Expand All @@ -181,9 +197,11 @@ Instead, we just create an instance of ``AbstractSelector`` "on the spot", using
| | | + Supports logical operations | - You still need to create the base classes used as leaves |

## Class diagram

![alt text](./etc/specification.png "Specification")

## Applicability

Use the Specification pattern when

* You need to select a subset of objects based on some criteria, and to refresh the selection at various times.
Expand Down

0 comments on commit 9c648cb

Please sign in to comment.