名称/分类
过滤器
目的
此设计模式的目的是引入一个功能接口,该接口将添加用于类似容器的对象轻松返回其过滤版本的功能。
解释
真实世界例子
我们正在设计一个威胁(恶意软件)检测软件,可以分析目标系统的攻击存在于其中的威胁。在设计中我们必须考虑到这一点 可以添加威胁类型。此外,还要求威胁检测系统可以根据不同的标准过滤检测到的威胁(目标系统充当容器状的威胁对象)。
通俗的说
过滤器模式是一种设计模式,可以帮助类似容器的对象返回过滤后的版本。
程序示例
为了对上述威胁检测示例进行建模,我们将介绍Threat 和 ThreatAwareSystem接口
public interface Threat {
String name();
int id();
ThreatType type();
}
public interface ThreatAwareSystem {
String systemId();
List<? extends Threat> threats();
Filterer<? extends ThreatAwareSystem, ? extends Threat> filtered();
}请注意返回 Filterer 接口实例的 filtered 方法 该接口定义为:
@FunctionalInterface
public interface Filterer<G, E> {
G by(Predicate<? super E> predicate);
}它用于满足系统能够根据威胁属性进行自我过滤的要求.类似容器的对象(在本例中为 ThreatAwareSystem)需要有一个返回 Filterer 实例的方法。这个帮助接口提供了协变地指定表示容器类对象的接口的子接口中的逆变 Predicate 的下限。
在我们的示例中,我们将能够传递一个接受 ? extends Threat 对象和从 Filtered::by 方法中的返回 ? extends ThreatAwareSystem.一个简单的实现关于 ThreatAwareSystem :
public class SimpleThreatAwareSystem implements ThreatAwareSystem {
private final String systemId;
private final ImmutableList<Threat> issues;
public SimpleThreatAwareSystem(final String systemId, final List<Threat> issues) {
this.systemId = systemId;
this.issues = ImmutableList.copyOf(issues);
}
@Override
public String systemId() {
return systemId;
}
@Override
public List<? extends Threat> threats() {
return new ArrayList<>(issues);
}
@Override
public Filterer<? extends ThreatAwareSystem, ? extends Threat> filtered() {
return this::filteredGroup;
}
private ThreatAwareSystem filteredGroup(Predicate<? super Threat> predicate) {
return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate));
}
private List<Threat> filteredItems(Predicate<? super Threat> predicate) {
return this.issues.stream()
.filter(predicate)
.collect(Collectors.toList());
}
}重写 filtered 方法,根据给定的断言过滤威胁列表。
现在,如果我们引入一个新的 Threat 接口子类型,它增加了特定威胁出现的可能性:
public interface ProbableThreat extends Threat {
double probability();
}我们还可以引入一个新的接口,该接口代表一个能够感知威胁及其概率的系统:
public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem {
@Override
List<? extends ProbableThreat> threats();
@Override
Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered();
}请注意,我们是如何覆盖 ProbabilisticThreatAwareSystem 中的 filtered 方法并通过指定不同的泛型,可以获得不同的通用返回类型。默认实现下,我们的接口是规范的。我们将能够通过 ProbableThreat 属性过滤 ProbabilisticThreatAwareSystem:
public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem {
private final String systemId;
private final ImmutableList<ProbableThreat> threats;
public SimpleProbabilisticThreatAwareSystem(final String systemId, final List<ProbableThreat> threats) {
this.systemId = systemId;
this.threats = ImmutableList.copyOf(threats);
}
@Override
public String systemId() {
return systemId;
}
@Override
public List<? extends ProbableThreat> threats() {
return threats;
}
@Override
public Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered() {
return this::filteredGroup;
}
private ProbabilisticThreatAwareSystem filteredGroup(final Predicate<? super ProbableThreat> predicate) {
return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate));
}
private List<ProbableThreat> filteredItems(final Predicate<? super ProbableThreat> predicate) {
return this.threats.stream()
.filter(predicate)
.collect(Collectors.toList());
}
}现在,如果我们想按威胁类型过滤 ThreatAwareSystem ,我们可以:
Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit");
Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan");
List<Threat> threats = List.of(rootkit, trojan);
ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats);
ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered()
.by(threat -> threat.type() == ThreatType.ROOTKIT);或者如果我们想过滤 ProbabilisticThreatAwareSystem:
ProbableThreat malwareTroyan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99);
ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8);
List<ProbableThreat> 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);类图

适用性
在处理使用子类型而不是子类型的容器类对象时,可以使用模式可扩展类结构的参数化(泛型)。它使您能够轻松扩展过滤功能,随着业务需求的变化,类似容器的对象的能力也随之变化。
教程
- Article about Filterer pattern posted on it's author's blog
- Application of Filterer pattern in domain of text analysis
已知使用
实例在博客链接.它展示了如何使用 Filterer 模式创建文本问题分析器,支持单元测试用例测试。
后果
Pros:
- 您可以轻松地为类似容器的对象引入新的子类型,并为其中包含的对象引入子类型,同时还可以轻松地筛选这些新子类型的新属性.
Cons:
- 泛型与泛型混合有时会很棘手
鸣谢
- 该模式的作者 : Tomasz Linkowski