I am creating a Matrix
class in Java to use in a linear algebra program. Right now it holds doubles, but I want to abstract it.
I've created an interface called MatrixElement
, which will contain add
, multiply
, divide
, and any other arithmetic methods needed to perform these matrix operations.
Here is a snippet of the Matrix
class:
public class Matrix<T extends MatrixElement> {
private ArrayList<ArrayList<T>> rows;
public Matrix(int numRows, int numCols) {
if (numRows <= 0) {
throw new IllegalArgumentException("Matrix must have at least one row.");
}
if (numCols <= 0) {
throw new IllegalArgumentException("Matrix must have at least one column.");
}
this.rows = new ArrayList<ArrayList<T>>();
for (int r = 0; r < numRows; r++) {
ArrayList<T> row = new ArrayList<T>();
for (int c = 0; c < numCols; c++) {
row.add(new T());
}
this.rows.add(row);
}
}
/* lots of methods omitted */
public static Matrix sum(Matrix a, Matrix b) {
if (a.numRows() != b.numRows() || a.numCols() != b.numCols()) {
throw new IllegalArgumentException("Matrices must be the same size.");
}
Matrix sum = new Matrix(a.numRows(), b.numCols());
for (int r = 1; r <= b.numRows(); r++) {
for (int c = 1; c <= b.numCols(); c++) {
sum.setEntry(r, c, a.getEntry(r, c).add(b.getEntry(r, c)));
}
}
return sum;
}
public Matrix add(Matrix matrix) {
return Matrix.sum(this, matrix);
}
}
Here is how methods are declared in MatrixElement
public interface MatrixElement {
public MatrixElement add(MatrixElement e);
}
Finally, here's a sample class I've created that implements this interface:
public class Fraction implements MatrixElement {
private BigInteger numerator;
private BigInteger denominator;
public Fraction(int num, int denom) {
numerator = BigInteger.valueOf(num);
denominator = BigInteger.valueOf(denom);
}
@Override
public Fraction add(MatrixElement e) {
Fraction f;
try {
f = (Fraction) e;
} catch (ClassCastException cce) {
throw new IllegalMatrixOperationException("Cannot add " + this.getClass().toString() + " and " + e.getClass().toString());
}
/* addition code omitted */
return this;
}
}
The main idea here is this:
Matrix
objects can hold instances of any one class that implements the interfaceMatrixElement
MatrixElement
contains arithmetic methods necessary for matrix manipulation, such asadd
- The kicker: Classes that implement
MatrixElement
can only use its methods on other instances of the same class. For example,Fraction
can only be added to otherFraction
instances. Two classes may implementMatrixElement
, but they shouldn't necessarily be able to add to one another.
I ran this design by another programmer and was told that casting like this is bad practice. If so, what is the correct way to do this? How can I use an interface to 'group' classes that have similar functionality to be used in parameterization, but then restrict which children of said interface can be used in the children's methods?