在Java中具有不同参数的接口方法

时间:2013-08-05 15:32:46

标签: java spring design-patterns

寻找关于用Java设计一些代码的一些指导。

目前我有类似的东西......

@Service
class SomeService {
    @Autowired
    private FilterSoldOut filterSoldOut;
    @Autowired
    private FilterMinPriceThreshold filterMinPriceThreshold;

    public List<Product> getProducts() {
        List<Product> products = //...code to get some products

        // Returns list of in-stock products
        products = filterSoldOut.doFilter(products); 

        // Returns list of products above min price
        products = filterMinPriceThreshold.doFilter(minPrice, products);

        return products; 
    }
}

我希望能够做的是使用doFilter方法创建一个Filter接口,然后在SomeService中创建一个List过滤器,由Spring自动装配。然后在getProducts方法中,我可以迭代过滤器列表并调用doFilter。这样我将来可以创建实现Filter接口的新类,并通过Spring配置将它们添加到列表中,并且无需更改代码即可应用新的过滤器。

但是,问题是doFilter方法的参数可能不同。我已经阅读了有关命令模式和访问者模式的内容,但它们似乎并不适合该法案。

有人能建议一个好的模式来实现我所描述的吗?

感谢。

4 个答案:

答案 0 :(得分:1)

有很多方法可以做到这一点。有些很复杂,有些更简单。最简单的方法是使用varargsObject元素数组。这里的问题是你必须将每个objetc转换为正确的类型才能使用它们,如果在未知的顺序中有多种类型,这可能有点棘手。

另一种选择是使用Map<String,Object>(你可以根据需要包装自己的类,lile FilterParams)来存储基于名称的参数,然后你可以获得它们并相应地施放它们。


修改

考虑到参数在运行时会有所不同,您需要某人“充分了解”关于当前配置。

不是模式方面的,但我宁愿保持简单而不使用太多花哨的名字。如何引入一个FilterConfigurator,它有一个简单的重载方法configure,它接收特定的过滤器并根据它的类型进行配置?此配置程序是已通知的实体,它知道这些参数的当前值。

目标是让Service免除配置过滤器的责任。

此外,如果您创建了Filter课程,则可以实施一个doFilter,而无需更改即可调用。{/ p>

还有另一个想法......它涉及FilterFactory创建初始化过滤器,因此过滤器100%从头开始配置。这个工厂可以依赖于同一个FilterConfigurer或自己做。

答案 1 :(得分:0)

正如Cris所说,你可以使用下一个函数定义:

  public List<Product> doFilter(Object...args) {
    if (args.length != 2)
      throw new IllegalArgumentException();
    if (! (args[0] instanceof String))
      throw new IllegalArgumentException();
    if (! (args[2] instanceof Integer))
      throw new IllegalArgumentException();

    String stringArgument = (String) args[0];
    Integer integerArgument = (Integer) args[1];

    // your code here

    return ...;
  }

或使用命令模式:

public interface Command {
}

public class FirstCommand implements Command {
  private String string;

  // constructor, getters and setters
}

public class SecondCommand implements Command {
  private Integer integer;

  // constructor, getters and setters
}

// first service function
public List<Product> doFilter(Command command) {
  if (command instanceof FirstCommand)
    throw new IllegalArgumentException();
  FirstCommand firstCommand = (FirstCommand) command;

  return ...;
}

// second service function
public List<Product> doFilter(Command command) {
  if (command instanceof SecondCommand)
    throw new IllegalArgumentException();
  SecondCommand secondCommand = (SecondCommand) command;

  return ...;
}

修改

好的,我理解你的问题。并且认为您可以创建各种会话范围的过滤器。

@Service
class SomeService {
    @Autowired(required = false)
    private List<Filter> filters;

    public List<Product> getProducts() {
        List<Product> products = //...code to get some products

        if (filters != null) {
          for (Filter filter : filters)
            products = filter.doFilter(products);
        }

        return products; 
    }
}

然后使用设置字段创建过滤器:

public PriceFilter implements Filter {
  private Integer minPrice;
  private Integer maxPrice;

  // getters and setters

  public List<Product> doFilter(List<Product> products) {
     // implementation here
  }
}

public ContentFilter implements Filter {
  private String regexp;

  // getters and setters

  public List<Product> doFilter(List<Product> products) {
     // implementation here
  }
}

然后,用户可以为会话配置此过滤器,并使用服务功能getProducts来获取结果。

答案 2 :(得分:0)

<强>旧

  

我建议您在施工时或在时设置过滤器状态   至少在你之前getProducts()

     

在你的两个过滤器的例子中,其中一个是(可能)   检查数据库是否有可用的产品和另一个   将产品的价格与某个预设值进行比较。这个值   (minPrice)在应用过滤器之前已知。它可以   也可以说过滤器取决于它,或它是它的一部分   过滤器的状态。所以我建议你把   在施工时(或通过一个。)过滤器内部minPrice   setter)然后只传递你想要过滤的产品列表。   对其他过滤器使用相同的模式。

新建议(评论后提出来):

您可以创建一个包含所有过滤器所有值的单个对象(AllFiltersState)。在您的控制器中设置此对象中需要的任何条件(minPrice,颜色等)并将其传递给产品中的每个过滤器 - doFilter(allFiltersState,products)。

答案 3 :(得分:0)

获得自动装配的过滤器列表并不是解决问题的好方法。 每个过滤器都依赖于需要传递给doFilter方法的不同类型的参数。需要这样做使得该方法非常不灵活。是的,你可以使用varargs但它只会造成混乱。这就是为什么实现构建器以构建一系列过滤器以应用于产品集合可能更容易的原因。向构建器添加新过滤器变得非常简单。当许多不同的参数在起作用时,Builder Pattern非常有用。

考虑使用此界面:

public interface CollectionFilter<T> {
    public Collection<T> doFilter(Collection<T> collection);
}

过滤器链接类,它将所有过滤器应用于集合:

public class CollectionFilterChain<T> {
    private final List<CollectionFilter<T>> filters;

    public CollectionFilterChain(List<CollectionFilter<T>> filters) {
        this.filters = filters;
    }

    public Collection<T> doFilter(Collection<T> collection) {
        for (CollectionFilter<T> filter : filters) {
            collection = filter.doFilter(collection);
        }

        return collection;
    }
}

两个CollectionFilter<T>实现:

public class InStockFilter<T> implements CollectionFilter<T> {

    public Collection<T> doFilter(Collection<T> collection) {
        // filter
    }
}


public class MinPriceFilter<T> implements CollectionFilter<T> {

    private final float minPrice;

    public MinPriceFilter(float minPrice) {
        this.minPrice = minPrice;
    }

    public Collection<T> doFilter(Collection<T> collection) {
        // filter
    }
}

还有一个构建器,可以让您轻松构建过滤器链:

public class CollectionFilterChainBuilder<T> {
    List<CollectionFilter<T>> filters;

    public CollectionFilterChainBuilder() {
        filters = new ArrayList<CollectionFilter<T>>();
    }

    public CollectionFilterChainBuilder<T> inStock() {
        filters.add(new InStockFilter<T>());
        return this;
    }

    public CollectionFilterChainBuilder<T> minPrice(float price) {
        filters.add(new MinPriceFilter<T>(price));
        return this;
    }

    public CollectionFilterChain<T> build() {
        return new CollectionFilterChain<T>(filters);
    }
}

使用构建器可以轻松创建过滤器链,如下所示:

CollectionFilterChainBuilder<Product> builder = 
    new CollectionFilterChainBuilder();

CollectionFilterChain<Product> filterChain = 
    builder.inStock().minPrice(2.0f).build();

Collection<Product> filteredProducts = 
    filterChain.doFilter(products);

在更动态的设置中,您可以使用以下构建器:

CollectionFilterChainBuilder<Product> builder = new CollectionFilterChainBuilder();

if (filterInStock) {
    builder.inStock();
}

if (filterMinPrice) {
    builder.minPrice(minPrice);
}

// build some more