--- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ layout: pattern title: Filterer folder: filterer permalink: /patterns/filterer/ description: Design pattern that helps container-like objects to return filtered version of themselves.# short meta description that shows in Google search results categories: - Functional tags: - Extensibility --- ## Name / classification Filterer ## Intent The intent of this design pattern is to to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. ## Explanation Real world example > We are designing a threat(malware) detection system. We can have different types of threats and systems. We have a requirement that > system should be aware of threats that are present in it. In the design we have to take into consideration that new Threat types can be > added later. Also there is a requirement that a system can filter itself based on the threats that it possesses (system acts as container-like object for threats). > In plain words > We need to be able to filter different types of systems(container-like objects) based on properties of Threats that they contain. > Adding new properties for Threats should be easy (we still need the ability to filter by those new properties). **Programmatic Example** To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` interfaces. ```java public interface Threat { String name(); int id(); ThreatType type(); } public interface ThreatAwareSystem { String systemId(); List threats(); Filterer filtered(); } ``` Notice the `filtered` method that returns instance of `Filterer` interface which is defined as : ```java @FunctionalInterface public interface Filterer { G by(Predicate predicate); } ``` 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. 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 `ThreadAwareSystem` : ```java public class SimpleThreatAwareSystem implements ThreatAwareSystem { private final String systemId; private final ImmutableList issues; public SimpleThreatAwareSystem(final String systemId, final List issues) { this.systemId = systemId; this.issues = ImmutableList.copyOf(issues); } @Override public String systemId() { return systemId; } @Override public List threats() { return new ArrayList<>(issues); } @Override public Filterer filtered() { return this::filteredGroup; } private ThreatAwareSystem filteredGroup(Predicate predicate) { return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate)); } private List filteredItems(Predicate predicate) { return this.issues.stream() .filter(predicate) .collect(Collectors.toList()); } } ``` the `filtered` method is overridden to filter the threats list by given predicate. Now if we introduce new subtype of `Thread` interface that adds probability with which given thread can appear : ```java public interface ProbableThreat extends Threat { double probability(); } ``` we can also introduce a new interface that represents a system that is aware of threats with their probabilities : ````java public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { @Override List threats(); @Override Filterer filtered(); } ```` Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify different return covariant type by specifing different generic types. Our interfaces are clean and not cluttered by default implementations. We we will be able to filter `ProbabilisticThreatAwareSystem` by `ProbableThreat` properties : ```java public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { private final String systemId; private final ImmutableList threats; public SimpleProbabilisticThreatAwareSystem(final String systemId, final List threats) { this.systemId = systemId; this.threats = ImmutableList.copyOf(threats); } @Override public String systemId() { return systemId; } @Override public List threats() { return threats; } @Override public Filterer filtered() { return this::filteredGroup; } private ProbabilisticThreatAwareSystem filteredGroup(final Predicate predicate) { return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate)); } private List filteredItems(final Predicate predicate) { return this.threats.stream() .filter(predicate) .collect(Collectors.toList()); } } ``` Now if we want filter `ThreatAwareSystem` by threat type we can do : ```java Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); List threats = List.of(rootkit, trojan); ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() .by(threat -> threat.type() == ThreatType.ROOTKIT); ``` or if we want to filter `ProbabilisticThreatAwareSystem` : ```java ProbableThreat malwareTroyan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); List probableThreats = List.of(malwareTroyan, rootkit); ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem =new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); ``` ## Class diagram ![Filterer](./etc/filterer.png "Filterer") ## Applicability Pattern can be used when working with container-like objects that use subtyping, instead of parametrizing(generics) for extensible class structure. It enables you to easily extend filtering ability of container-like objects as business requirements change. ## Tutorials * [Article about Filterer pattern posted on it's author's blog](https://blog.tlinkowski.pl/2018/filterer-pattern/) * [Application of Filterer pattern in domain of text analysis](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) ## Known uses One of the uses is present on the blog presented in [this](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) link. It presents how to use `Filterer` pattern to create text issue analyzer with support for test cases used for unit testing. ## Consequences Pros : * 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. Cons : * covariant return types mixed with generics can be sometimes tricky ## Credits * Author of the pattern : [Tomasz Linkowski](https://tlinkowski.pl/)