文章目录
【Java设计模式】过滤器模式
一、概述
Java中的过滤器设计模式对于创建动态和可扩展的过滤解决方案至关重要。该模式允许将一系列过滤器应用于数据对象,增强了数据处理的灵活性和可扩展性。
二、别名
- 过滤器
- 管道和过滤器
三、过滤器设计模式的意图
过滤器设计模式的目的是使容器类对象能够返回自身的过滤版本。
四、通过实际示例详细解释过滤器模式
实际示例:
想象一个图书馆系统使用过滤器模式来动态组合过滤标准,如类型、作者和可用性。这个Java模式使系统更具可维护性和可扩展性。图书馆系统不是为每个可能的标准组合编写单独的方法,而是采用过滤器设计模式。每个过滤标准都被封装为一个对象,这些过滤对象可以在运行时动态组合,以创建复杂的过滤逻辑。例如,用户可以通过组合可用性过滤器和出版年份过滤器来搜索既可用又在2010年后出版的书籍。这种方法使系统更加灵活,更易于维护,因为可以添加新的过滤标准而无需修改现有代码。
五、Java中过滤器模式的编程示例
为了说明这一点,我们在Java中使用过滤器设计模式来构建一个恶意软件检测系统。这个系统可以根据各种标准过滤威胁,展示了该模式的灵活性和动态性。在设计中,我们必须考虑到以后可以添加新的威胁类型。此外,要求威胁检测系统能够根据不同的标准过滤检测到的威胁(目标系统充当威胁的容器类对象)。
为了建模威胁检测系统,我们引入了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();
}
请注意filtered
方法,它返回Filterer
接口的实例,该接口定义为:
@FunctionalInterface
public interface Filterer<G, E> {
G by(Predicate<? super E> predicate);
}
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());
}
}
现在,如果我们引入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();
}
我们将能够根据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());
}
}
现在让我们看看完整的示例在实际中的运行情况,展示过滤器模式在实践中的工作方式。
@Slf4j
public class App {
public static void main(String[] args) {
filteringSimpleThreats();
filteringSimpleProbableThreats();
}
private static void filteringSimpleProbableThreats() {
LOGGER.info("### 按概率过滤ProbabilisticThreatAwareSystem ###");
var trojanArcBomb = new SimpleProbableThreat("Trojan - ArcBomb", 1, ThreatType.TROJAN, 0.99);
var rootkit = new SimpleProbableThreat("Rootkit - Kernel", 2, ThreatType.ROOTKIT, 0.8);
List<ProbableThreat> probableThreats = List.of(trojanArcBomb, rootkit);
var probabilisticThreatAwareSystem =
new SimpleProbabilisticThreatAwareSystem("Sys - 1", probableThreats);
LOGGER.info("过滤ProbabilisticThreatAwareSystem。初始:"
+ probabilisticThreatAwareSystem);
// 使用过滤器进行过滤
var filteredThreatAwareSystem = probabilisticThreatAwareSystem.filtered()
.by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0);
LOGGER.info("按概率 = 0.99 过滤:" + filteredThreatAwareSystem);
}
private static void filteringSimpleThreats() {
LOGGER.info("### 按ThreatType过滤ThreatAwareSystem ###");
var rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple - Rootkit");
var trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple - Trojan");
List<Threat> threats = List.of(rootkit, trojan);
var threatAwareSystem = new SimpleThreatAwareSystem("Sys - 1", threats);
LOGGER.info("过滤ThreatAwareSystem。初始:" + threatAwareSystem);
// 使用过滤器进行过滤
var rootkitThreatAwareSystem = threatAwareSystem.filtered()
.by(threat -> threat.type() == ThreatType.ROOTKIT);
LOGGER.info("按threatType = ROOTKIT 过滤:" + rootkitThreatAwareSystem);
}
}
运行示例将产生以下控制台输出。
08:33:23.568 [main] INFO com.iluwatar.filterer.App -- ### 按ThreatType过滤ThreatAwareSystem ###
08:33:23.574 [main] INFO com.iluwatar.filterer.App -- 过滤ThreatAwareSystem。初始:SimpleThreatAwareSystem(systemId=Sys - 1, issues=[SimpleThreat(threatType=ROOTKIT, id=1, name=Simple - Rootkit), SimpleThreat(threatType=TROJAN, id=2, name=Simple - Trojan)])
08:33:23.576 [main] INFO com.iluwatar.filterer.App -- 按threatType = ROOTKIT 过滤:SimpleThreatAwareSystem(systemId=Sys - 1, issues=[SimpleThreat(threatType=ROOTKIT, id=1, name=Simple - Rootkit)])
08:33:23.576 [main] INFO com.iluwatar.filterer.App -- ### 按概率过滤ProbabilisticThreatAwareSystem ###
08:33:23.581 [main] INFO com.iluwatar.filterer.App -- 过滤ProbabilisticThreatAwareSystem。初始:SimpleProbabilisticThreatAwareSystem(systemId=Sys - 1, threats=[SimpleProbableThreat{probability=0.99} SimpleThreat(threatType=TROJAN, id=1, name=Trojan - ArcBomb), SimpleProbableThreat{probability=0.8} SimpleThreat(threatType=ROOTKIT, id=2, name=Rootkit - Kernel)])
08:33:23.581 [main] INFO com.iluwatar.filterer.App -- 按概率 = 0.99 过滤:SimpleProbabilisticThreatAwareSystem(systemId=Sys - 1, threats=[SimpleProbableThreat{probability=0.99} SimpleThreat(threatType=TROJAN, id=1, name=Trojan - ArcBomb)])
六、何时在Java中使用过滤器模式
- 当需要对对象集合进行动态和灵活的过滤时,使用过滤器模式。
- 对于过滤逻辑经常变化或需要以各种方式组合的应用程序,这个Java设计模式是理想的选择。
- 在需要将过滤逻辑与核心业务逻辑分离的场景中,过滤器模式是理想的选择。
七、过滤器模式在Java中的实际应用
- Java中的流处理库,如Apache Kafka Streams,利用此模式构建复杂的数据处理管道。
- 图像处理软件经常使用过滤器来顺序地对图像应用效果或转换。
八、过滤器模式的好处和权衡
好处:
- 通过允许添加或重新组织不同的过滤器而不影响系统的其他部分,增加了灵活性。
- 增强了可测试性,因为过滤器可以独立测试。
- 促进了数据处理阶段之间的松散耦合。
权衡:
- 过滤器之间连续的数据传递可能会导致潜在的性能开销。
- 随着过滤器数量的增加,复杂性可能会增加,可能会影响可维护性。