Shu S Shu S - 3 months ago 17
Java Question

Array value restriction by class inheritance

I'm writing signal processing library,

and I want to make this kind of hierarchy.

First, I defined

abstract class


that define only "this wrapper class has one
double[]
field"

i.e.

public abstract class DoubleArray{
private final double[] array;
DoubleArray(double[] array){
this.array = array;
}
}


(I made constructor
package private
rather than
protected
because

I want to restrict usage of constructor outside the package)

(
System.arraycopy
is not used here

because this constructor is used only by me.)

Next, my first restriction is,

"cannot contain exceptional values"

i.e.

//inside the same package
public class SignalWithoutExceptionalValues extends DoubleArray{
SignalWithoutExceptionalValues(double[] signal){
super(signal);
for(double d : signal)
if(Double.isNaN(d) || Double.isInfinite(d))
throw new IllegalArgumentException("cannot contain exceptional values");
}
}


Next restriction is

"signal is in range of -1.0 ~ 1.0"

i.e.

//inside the same package
public final class OneAmplitudeSignal extends SignalWithoutExceptionalValues{
OneAmplitudeSignal(double[] signal){
super(signal);
for(double d : signal)
if(d > 1.0 || d < -1.0)
throw new IllegalArgumentException("is not normalized");
}
}


However, I think,

first of all,

I have to do
for-each
argument checking,

and then, after that,

assign to field.

but in this example,

I am forced to assign unchecked array to field,

because
DoubleArray
constructor must initialize
array
field.

So, my question is,

is there any strategy to do "first checking then assign"

in this kind of hierarchy.

OR this design is not appropriate for this purpose,

and there is another good design ?

Thank you.

Answer

You could extract the checking logic to a separate check method which the base constructor can execute prior to the assignment :

public abstract class DoubleArray{
    private final double[] array;
    protected abstract void check (double[] array);
    DoubleArray(double[] array){
        check(array);
        this.array = array;
    }
}

The sub-classes will override check to supply the required validation logic :

public class SignalWithoutExceptionalValues extends DoubleArray{
    SignalWithoutExceptionalValues(double[] signal){
        super(signal);
    }

    @Override
    protected void check (double[] signal) {
        for(double d : signal)
            if(Double.isNaN(d) || Double.isInfinite(d))
                throw new IllegalArgumentException("cannot contain exceptional values");
    }
}

public final class OneAmplitudeSignal extends SignalWithoutExceptionalValues{
    OneAmplitudeSignal(double[] signal){
        super(signal);
    }

    @Override
    protected void check (double[] signal) {
        super.check ();
        for(double d : signal)
            if(d > 1.0 || d < -1.0)
                throw new IllegalArgumentException("is not normalized");
    }
}