Java过滤器工厂实现

Posted

技术标签:

【中文标题】Java过滤器工厂实现【英文标题】:Java Filter Factory implementation 【发布时间】:2019-08-30 08:54:22 【问题描述】:

受 FilenameFilter.java 的启发,我想使用类似的方法/设计模式来解决我的问题。我从 sftp 服务器中选择文件基于:

    如果超过 n 天 如果它超过 n 天并且它的名称是某种模式。

我已经定义了一个功能接口 SemanticFileFilter 如下:

public interface SftpFileFilter

    boolean accept(LsEntry sftpFile);

用于 sftp 的 LsEntry 基本上类似于 java 中的 File。

想要定义 SftpFileFilterFactory 以在一个地方获取 SftpFileFilter 的所有实现,如下所示:

    public class SftpFileFilterFactory 
    
        public static final SftpFileFilter OLD_FILE_FILTER =  new SftpFileFilter()
        
//ERROR: because Interface function method should take only 1 parameter
            //@Override
            public boolean accept(LsEntry lsEntry,int nDays)
            
                //checks if files if older than nDays
            
        ;

        public static final SftpFileFilter PATTERN_MATCH_OLD_FILE_FILTER =  new SftpFileFilter()
        
//ERROR: because Interface function method should take only 1 parameter
            //@Override
            public boolean accept(LsEntry lsEntry,int nDays, String pattern)
            
                //checks if files if older than nDays and matches pattern "pattern"
            
        ;
    

如何设计我的接口的函数方法或工厂实现,以便将来如果需要定义更多类似的过滤器,我不需要在代码更改上费心,只需定义新的过滤器。

我们还应该能够链接过滤器。也就是说,为旧文件定义一个过滤器,为模式匹配定义另一个过滤器。如果两者都需要使用,它们应该能够链接在一起,因此两者都可以使用。

【问题讨论】:

【参考方案1】:

您的问题提醒Command 设计模式。您需要实现不同的条件并提供额外的参数,您可以使用构造函数并创建类或使用Java 8 lambda 表达式。见下例:

import java.util.ArrayList;
import java.util.List;

public class DesignPatterns 

    public static void main(String[] args) 
        List<SftpFileFilter> filters = new ArrayList<>();
        filters.add(new OlderThanNDaysFilter(10));
        filters.add(new NameSftpFileFilter("tmp.txt"));
        // you can use lambda as well
        filters.add((file) -> file.getName().length() > 0);
    


interface SftpFileFilter 
    boolean accept(LsEntry sftpFile);


class OlderThanNDaysFilter implements SftpFileFilter 

    private final int days;

    public OlderThanNDaysFilter(int days) 
        this.days = days;
    

    @Override
    public boolean accept(LsEntry sftpFile) 
        return sftpFile.isOlder(days);
    


class NameSftpFileFilter implements SftpFileFilter 

    private final String name;

    public NameSftpFileFilter(String name) 
        this.name = name;
    

    @Override
    public boolean accept(LsEntry sftpFile) 
        return sftpFile.getName().equals(name);
    

这些对象太小,不需要为它创建工厂。如有必要,您可以创建和使用它们。当然,您可以创建factory,它会创建一些预定义的过滤器:

class ConditionFactory 
    private static final SftpFileFilter OLDER_THAN_TEN = new OlderThanNDaysFilter(10);
    private static final SftpFileFilter PASSWORDS_FILE = new NameSftpFileFilter("passwords.txt");

    public SftpFileFilter createOlderThan10Days() 
        return OLDER_THAN_TEN;
    

    public SftpFileFilter createPasswordsFile() 
        return PASSWORDS_FILE;
    

    public SftpFileFilter createNameFilter(final String name) 
        return new NameSftpFileFilter(Objects.requireNonNull(name));
    

    public SftpFileFilter createOlderThan(final int days) 
        return new OlderThanNDaysFilter(days);
    

这是过滤器实现和客户端代码之间的良好分离,客户端代码不知道按名称过滤是如何实现的,并且可以轻松交换。

Java 8中你可以直接使用java.util.function.Predicate或者通过你的接口扩展它:

interface SftpFileFilter extends Predicate<LsEntry> 
    boolean accept(LsEntry sftpFile);

    @Override
    default boolean test(LsEntry lsEntry) 
        return accept(lsEntry);
    

【讨论】:

以上是关于Java过滤器工厂实现的主要内容,如果未能解决你的问题,请参考以下文章

101JAVA设计模式--业务逻辑实现扩展,框架使用分析总结

Spring Gateway断言工厂与过滤器工厂

Spring Cloud Gateway 内置的过滤器工厂

Spring Cloud Gateway 内置的过滤器工厂

微服务——统一网关

微服务——统一网关