You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The intent of this design pattern is to introduce a functional interface that will add a
16
-
functionality for container-like objects to easily return filtered versions of themselves.
20
+
The Filterer pattern aims to apply a series of filters to data objects, where each filter processes the data based on specific rules and criteria, and passes the data to the next filter in the sequence.
17
21
18
22
## Explanation
19
23
20
24
Real world example
21
25
22
-
> We are designing a threat (malware) detection software which can analyze target systems for
23
-
> threats that are present in it. In the design we have to take into consideration that new
24
-
> Threat types can be added later. Additionally, there is a requirement that the threat detection
25
-
> system can filter the detected threats based on different criteria (the target system acts as
26
-
> container-like object for threats).
26
+
> We are designing a threat (malware) detection software which can analyze target systems for threats that are present in it. In the design we have to take into consideration that new Threat types can be added later. Additionally, there is a requirement that the threat detection system can filter the detected threats based on different criteria (the target system acts as container-like object for threats).
27
27
28
28
In plain words
29
29
30
-
> Filterer pattern is a design pattern that helps container-like objects return filtered versions
31
-
> of themselves.
30
+
> Filterer pattern is a design pattern that helps container-like objects return filtered versions of themselves.
32
31
33
32
**Programmatic Example**
34
33
35
-
To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem`
36
-
interfaces.
34
+
To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` interfaces.
Notice the `filtered` method that returns instance of `Filterer` interface which is defined as:
54
55
55
56
```java
57
+
56
58
@FunctionalInterface
57
59
publicinterfaceFilterer<G, E> {
58
-
Gby(Predicate<? super E>predicate);
60
+
Gby(Predicate<? super E>predicate);
59
61
}
60
62
```
61
63
62
-
It is used to fulfill the requirement for system to be able to filter itself based on threat
63
-
properties. The container-like object (`ThreatAwareSystem` in our case) needs to have a method that
64
-
returns an instance of `Filterer`. This helper interface gives ability to covariantly specify a
65
-
lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the
66
-
container-like objects.
64
+
It is used to fulfill the requirement for system to be able to filter itself based on threat properties. The container-like object (`ThreatAwareSystem` in our case) needs to have a method that returns an instance of `Filterer`. This helper interface gives ability to covariantly specify a lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the container-like objects.
67
65
68
-
In our example we will be able to pass a predicate that takes `? extends Threat` object and
69
-
return `? extends ThreatAwareSystem` from `Filtered::by` method. A simple implementation
70
-
of `ThreatAwareSystem`:
66
+
In our example we will be able to pass a predicate that takes `? extends Threat` object and return `? extends ThreatAwareSystem` from `Filtered::by` method. A simple implementation of `ThreatAwareSystem`:
Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify
135
-
different return covariant type by specifying different generic types. Our interfaces are clean and
136
-
not cluttered by default implementations. We we will be able to filter
137
-
`ProbabilisticThreatAwareSystem` by `ProbableThreat` properties:
128
+
Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify different return covariant type by specifying different generic types. Our interfaces are clean and not cluttered by default implementations. We will be able to filter `ProbabilisticThreatAwareSystem` by `ProbableThreat` properties:
Pattern can be used when working with container-like objects that use subtyping, instead of
210
-
parametrizing (generics) for extensible class structure. It enables you to easily extend filtering
211
-
ability of container-like objects as business requirements change.
198
+
This pattern is useful in scenarios where data needs to be processed in discrete steps, and each step's output is the input for the next step. Common in stream processing, audio/video processing pipelines, or any data processing applications requiring staged transformations.
212
199
213
200
## Tutorials
214
201
215
-
*[Article about Filterer pattern posted on it's author's blog](https://blog.tlinkowski.pl/2018/filterer-pattern/)
202
+
*[Article about Filterer pattern posted on its author's blog](https://blog.tlinkowski.pl/2018/filterer-pattern/)
216
203
*[Application of Filterer pattern in domain of text analysis](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html)
217
204
218
-
## Known uses
205
+
## Known Uses
219
206
220
-
One of the uses is present on the blog presented in
221
-
[this](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) link. It presents how
222
-
to use `Filterer` pattern to create text issue analyzer with support for test cases used for unit
223
-
testing.
207
+
* Stream processing libraries in Java, such as Apache Kafka Streams, utilize this pattern to build complex data processing pipelines.
208
+
* Image processing software often uses filters to apply effects or transformations to images sequentially.
224
209
225
210
## Consequences
226
211
227
-
Pros:
228
-
* You can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes.
212
+
Benefits:
213
+
214
+
* Increases flexibility by allowing different filters to be added or reorganized without affecting other parts of the system.
215
+
* Enhances testability, as filters can be tested independently.
216
+
* Promotes loose coupling between the stages of data processing.
217
+
218
+
## Trade-offs:
219
+
220
+
* Potential performance overhead from continuous data passing between filters.
221
+
* Complexity can increase with the number of filters, potentially affecting maintainability.
222
+
223
+
## Related Patterns
229
224
230
-
Cons:
231
-
* Covariant return types mixed with generics can be sometimes tricky
225
+
* Chain of Responsibility: Filters can be seen as a specialized form of the Chain of Responsibility, where each filter decides if and how to process the input data and whether to pass it along the chain.
226
+
* Decorator: Similar to Decorator in that both modify behavior dynamically; however, filters focus more on data transformation than on adding responsibilities.
232
227
233
228
## Credits
234
229
235
-
* Author of the pattern : [Tomasz Linkowski](https://tlinkowski.pl/)
230
+
*[Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3W8sn2W)
231
+
*[Kafka: The Definitive Guide: Real-Time Data and Stream Processing at Scale](https://amzn.to/49N3nRU)
232
+
*[Java Performance: The Definitive Guide](https://amzn.to/3vRW3qj)
0 commit comments