Abstraction: Optional Methods? [java] (Modeling Filters)

124 Views Asked by At

Background

For my assignment I am required to model filters such as those in signal processing at a basic level. Filters can take inputs of any type and output a different type if that's how the filter is implemented. The most simple filter outputs the input. Other example filters are arithmetic mean, max, or min filters which returns the maximum input. Similar filters can only return the mean/max/min of the last N inputs. Some filters are reset-able and has a method "reset" which takes an input of the same type. So for example a max3 filter returns the maximum number of the three last inputs or since the last reset including the input that the reset method takes. The assignment goes in further detail describing other more complicated filters but I'm having trouble with abstraction at the most basic level.

Attempt

So my first attempt was to create an interface "Filter" which had one method "filter". This would be implemented by filters to suite their own needs. I created an abstract class "StorageFilter" which stored a list of inputs accessible with protected set/get methods. Then I extended that class to implement the reset function in another abstract class "ResetableFilter". So filters that can't reset would extend the first abstract filter and filters that can would reset the second. But my implementation didn't really work out since filters are a little more complicated than that. There are a few main types of filters that I can pin down. Filters that:

  • store one input such as max/min filters: just compare stored value with input and if it's the new max/min then set the stored value to the input. We'll call this type 1.
  • store a list of inputs such as max/min filters of last N: only stores the last N inputs so the filter method can iterate through the list and find the max/min. We'll call this type 2. (This could also implemented in another way storing two values, one representing the current max/min and its "age")
  • store a list of inputs and a list of outputs such as complicated scalar linear filters which uses equations uses both to calculate the new output. We'll call this type 3.
  • store none at all such simple filters like the first example or a filter that just returns double the input. We'll call this type 4

So there are many types of things that a filter can store but not all filters are reset-able.

Problem

My general question is how can I implement optional methods while maintaining abstraction? This type (filter) can have an optional method (reset) that its subtypes can have. I can't just have an empty method "reset" that does nothing but the filter is still able to call. What is the best way to implement an optional method such as in this case while maintaining abstraction?

Potential Solutions

  • Use @Optional: Using this annotation means that filters that don't use this method will throw an UnsupportedOperationException. This is an acceptable way of maintaining abstraction since Java's Collections uses it but it's not desirable since exceptions are involved.
  • Create a "Reset" interface and have each Filter that can reset implement it: This is also bad because it will almost double the types of Filters I have to think about. (i.e Type 1 filters, reset-able Type 1 filters, ..., and Type 4 filters. Since type 4 filters don't store anything they don't reset ever)
  • The book "Code Complete 2" describes a scenario modeling a Cat. Cats can scratch but some cats are declawed and therefore can't scratch. Creating different classes for things that a cat can or cannot do complicates it so that you'll end up with classes like a ScratchlessTailess...Cat. The solution the book offers is to create an inner class "Claws" that is contained within the Cat class or build a constructor that includes whether the cat scratches. From this I think an optimal solution would be to create an inner interface "ResetableContainer" which has the one method reset which can be implemented to fit the different types. It could hold whatever the filters need to store and the reset will be implemented depending on what was stored. The problem is still how can I implement it to avoid all this complication with the different possibilities of storage (a single input or a list of inputs)?
2

There are 2 best solutions below

0
On

It looks like you are running into a conceptual design problem, in that you are expecting the user of the Filter to always know exactly what it can and can't do. But at the same time, you want filters to be able to do lots of different things... these two ideas can't entirely mesh.

What you can do is create these 'optional' methods to return a value on execution:

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

A much better method: Include include an additional method that must be overridden, a more common design pattern: see this question for an example. As stated there, it's also probably good to just have more than one interface.

0
On

This sounds like a school assignment, so you may be constrained in a way that you can't do this, but what I would do is keep it simple: a single interface:

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

And then probably an abstract base class to provide good default implementations for those methods that have them:

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

I wouldn't have even included canReset except for the possibility of filters which are sometimes resetable and sometimes not. If that's not a possibility you want to support then you can remove the canReset and just always call reset() whenever you would reset it if it were a resetable filter.