【问题标题】:Abstraction: Optional Methods? [java] (Modeling Filters)抽象:可选方法? [java](建模过滤器)
【发布时间】:2013-12-28 19:06:19
【问题描述】:

背景

在我的任务中,我需要对滤波器进行建模,例如基本级别的信号处理中的滤波器。如果过滤器是这样实现的,过滤器可以接受任何类型的输入并输出不同的类型。最简单的过滤器输出输入。其他示例过滤器是返回最大输入的算术平均值、最大值或最小值过滤器。类似的过滤器只能返回最后 N 个输入的平均值/最大值/最小值。一些过滤器是可重置的,并且有一个“重置”方法,它接受相同类型的输入。因此,例如 max3 过滤器返回最后三个输入的最大数量或自上次重置以来的最大数量,包括重置方法采用的输入。该作业更详细地描述了其他更复杂的过滤器,但我在最基本的抽象层次上遇到了麻烦。

尝试

所以我的第一次尝试是创建一个接口“Filter”,它有一个方法“filter”。这将由过滤器实现以满足他们自己的需求。我创建了一个抽象类“StorageFilter”,它存储了一个可通过受保护的 set/get 方法访问的输入列表。然后我扩展了该类以在另一个抽象类“ResetableFilter”中实现重置功能。因此,无法重置的过滤器将扩展第一个抽象过滤器,而可以重置第二个的过滤器。但是我的实现并没有真正奏效,因为过滤器比这更复杂一些。我可以确定几种主要类型的过滤器。过滤器:

  • 存储一个输入,例如最大/最小过滤器:只需将存储的值与输入进行比较,如果是新的最大/最小值,则将存储的值设置为输入。我们将这种类型称为 1。
  • 存储输入列表,例如最后 N 个的最大/最小过滤器:仅存储最后 N 个输入,因此过滤器方法可以遍历列表并找到最大/最小。我们将此类型称为 2。(这也可以以另一种方式实现,存储两个值,一个代表当前的最大/最小值及其“年龄”)
  • 存储输入列表和输出列表,例如复杂的标量线性滤波器,它使用方程来计算新的输出。我们将这种类型称为 3。
  • 根本不存储任何像第一个示例这样简单的过滤器或只返回双倍输入的过滤器。我们将这种类型称为 4

因此,过滤器可以存储多种类型的内容,但并非所有过滤器都可以重置。

问题

我的一般问题是如何在保持抽象的同时实现可选方法?此类型(过滤器)可以具有其子类型可以具有的可选方法(重置)。我不能只有一个空方法“重置”,它什么都不做,但过滤器仍然可以调用。在保持抽象的同时实现可选方法的最佳方法是什么?

可能的解决方案

  • 使用@Optional:使用这个注解意味着不使用这个方法的过滤器会抛出一个UnsupportedOperationException。这是一种可以接受的维护抽象的方式,因为 Java 的 Collections 使用它,但由于涉及异常,因此不受欢迎。
  • 创建一个“重置”接口并让每个可以重置的过滤器实现它:这也很糟糕,因为它几乎会使我必须考虑的过滤器类型增加一倍。 (即类型 1 过滤器、可重置的类型 1 过滤器、...和类型 4 过滤器。由于类型 4 过滤器不存储任何它们永远不会重置的内容)
  • “代码完成 2”一书描述了一个模拟猫的场景。猫可以抓挠,但有些猫是去爪的,因此不能抓挠。为猫可以或不能做的事情创建不同的类会使它复杂化,因此您最终会得到像 ScratchlessTailess...Cat 这样的类。本书提供的解决方案是创建一个包含在 Cat 类中的内部类“Claws”,或者构建一个包含猫是否抓挠的构造函数。据此,我认为最佳解决方案是创建一个内部接口“ResetableContainer”,该接口具有一种重置方法,可以实现以适应不同类型。它可以保存过滤器需要存储的任何内容,并且将根据存储的内容执行重置。问题仍然是如何实现它以避免所有这些与存储的不同可能性(单个输入或输入列表)有关的所有这些复杂性?

【问题讨论】:

  • 我不清楚为什么你不能有一个 reset() 方法,它对过滤器没有任何意义。你总是在通用界面中得到那种东西。例如,并非所有 InputStream 的实现都实现了 mark() 或 reset()。
  • 另一种看待它的方式是所有过滤器都支持reset(),但在大多数情况下它是无操作的。良好的抽象可以通过多种方式实现。

标签: java abstraction


【解决方案1】:

这听起来像是一项学校作业,所以您可能会受到某种方式的限制,您无法做到这一点,但我要做的就是保持简单:单一界面:

public interface Filter<In, Out> {
    public Out filter(In toFilter);
    public void reset();
    public boolean canReset();
}

然后可能是一个抽象基类,为那些拥有它们的方法提供良好的默认实现:

public abstract class BaseFilter<In, Out> implements Filter<In, Out> {
    public void reset() {}
    public boolean canReset() { return false; }
}

我什至不会包含 canReset ,除非过滤器有时可重置,有时不可重置。如果这不是您想要支持的可能性,那么您可以删除 canReset 并在重置它时始终调用 reset()(如果它是可重置过滤器)。

【讨论】:

    【解决方案2】:

    您似乎遇到了概念设计问题,因为您希望Filter 的用户始终确切知道它可以做什么和不能做什么。但与此同时,您希望过滤器能够做很多不同的事情......这两个想法不能完全融合。

    可以做的是创建这些“可选”方法以在执行时返回一个值:

    /**
     * Resets the filter.
     *
     * @returns
     *          false if this operation is not supported by the filter
     */
    public boolean reset() {
        return false;
    }
    

    更好的方法: 包含一个必须被覆盖的附加方法,这是一种更常见的设计模式:请参阅this question 示例。如那里所述,拥有多个界面也可能很好。

    【讨论】:

      猜你喜欢
      • 2014-10-27
      • 1970-01-01
      • 2012-09-19
      • 2016-07-22
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-05
      相关资源
      最近更新 更多