2

Let's assume that I have lots of implementations of matrices (Which don't extend from one to another) and I want the user to be able to see all the different classes, to gather them in some kind of enum or something, How can I do that? It doesn't have to be a menu or something, just so I will be able to see all the classes, just like enum.

For example:

MainMatrix matrix= new (ALL THE POSSIBILITIES)();

While the MainMatrix is the common interface of all matrices.

Can I use enum that will create instance of new class matching the option I'll choose? for example:

public enum Matrices{
DIAGONAL_MATRIX(new DiagonalMatrix());
..
..
}

Can I do that?

Numerator
  • 1,389
  • 3
  • 21
  • 40

7 Answers7

4

You can do this programmatically with the Reflections library.

For example:

Reflections reflections = new Reflections(...); //see in other use cases
Set<Class<? extends MainMatrix>> subTypes =
    reflections.getSubTypesOf(MainMatrix.class);
luketorjussen
  • 3,156
  • 1
  • 21
  • 38
johnstok
  • 96,212
  • 12
  • 54
  • 76
4

Here a solution using an enum with an abstract method:

public enum MatrixFactory {

    /**
     * Creates a diagonal matrix
     * 
     * args[0] : a double[] with the diagonal values
     */
    DIAGONAL_MATRIX {
        @Override
        public MainMatrix create(Object[] args) {
            double[] diagonal = (double[]) args[0];
            return new DiagonalMatrix(diagonal);
        }
    },

    /**
     * Creates a full matrix
     * 
     * args[0] : the number of rows
     * 
     * args[1] : the number of columns
     */
    FULL_MATRIX() {
        @Override
        public MainMatrix create(Object[] args) {
            int rows = (Integer) args[0];
            int cols = (Integer) args[1];
            return new FullMatrix(rows, cols);
        }
    };

    public abstract MainMatrix create(Object[] args);
}

Usage:

MatrixFactory.DIAGONAL_MATRIX.create(new Object[] {new double[] {1.0, 2.0, 3.0}});
MatrixFactory.FULL_MATRIX.create(new Object[] {4, 4});

See also the classic enum tutorial which illustrates this with an arithmetic enum:

public enum Operation {
  PLUS   { double eval(double x, double y) { return x + y; } },
  MINUS  { double eval(double x, double y) { return x - y; } },
  TIMES  { double eval(double x, double y) { return x * y; } },
  DIVIDE { double eval(double x, double y) { return x / y; } };

  // Do arithmetic op represented by this constant
  abstract double eval(double x, double y);
}

I advocate a regular factory though, because the usage is much clearer. Using an enum does not add any benefits I can think of in this context.

public class MatrixFactory {

    /**
     * Creates a diagonal matrix
     * 
     * @param diagonal the diagonal values
     * @return
     */
    public static MainMatrix diagonalMatrix(double[] diagonal) {
        return new DiagonalMatrix(diagonal);
    }

    /**
     * Creates a full matrix
     * 
     * @param rows the number of rows
     * @param cols the number of columns
     * @return
     */
    public static MainMatrix fullMatrix(int rows, int cols) {
        return new FullMatrix(rows, cols);
    }
}

Usage:

MatrixFactory.diagonalMatrix(new double[] {1.0, 2.0, 3.0});
MatrixFactory.fullMatrix(4, 4);
Adriaan Koster
  • 15,870
  • 5
  • 45
  • 60
1

One way is to have a method in your enum to create the matrix (mostly based on what you already wrote):

public enum Matrices{
    DIAGONAL_MATRIX {
        @Override
        public MainMatrix createMatrix() {
            return new DiagonalMatrix();
        }
    },
    OTHER_MATRIX {
        @Override
        public MainMatrix createMatrix() {
            return new OtherMatrix();
        }
    },
    ...
    ;

    public abstract MainMatrix createMatrix();
}

EDIT:
just call the createMatrix method to create a matrix for a given enum:

Matrices type = ...
MainMatrix matrix = type.createMatrix();

or directly

MainMatrix matrix = DIAGONAL_MATRIX.createMatrix();
user85421
  • 28,957
  • 10
  • 64
  • 87
  • Thank you for the answer, how can we make an instance of DIAGONAL_MATRIX after using this enum? MainMatrix matrix= Matrices.DIAGONAL_MATRIX; ? Will it be o.k? I think that I'll have a compilation error, no? – Numerator Sep 06 '11 at 09:53
  • @Nir - added it to my answer above – user85421 Sep 06 '11 at 10:49
1

We can create some kind of Matrix Factory:

public class MatrixImplFactory {
     IMatrixImpl createMatrix(double[] diagonal) {
          return new DiagonalMatrix(diagonal);
           }
     IMatrixImpl createMatrix(int rows, int cols) {
          return new FullMatrix(rows, cols);
           }
    }

I just need to make sure that each matrix will have different type of constructor.

Making instance of a matrix in this way:

public class Matrix implements IMatrix {
       protected IMatrixImpl impl;
       MatrixFacotry factory;
   public Matrix(int rows, int cols) {
          impl = factory.createMatrix(rows, cols);
          }
         ....

         }  
Numerator
  • 1,389
  • 3
  • 21
  • 40
  • 1
    +1 You just beat me to it! (-: I suggest making all the factory methods static and removing the field 'MatrixFacotry factory'. Then you can simply create a matrix by MatrixImplFactory.createMatrix(...). A reason to make a factory non static and implementing an interface would be if you want to allow for multiple different factory implementations (classes of factories) which is called the 'Abstract factory' pattern (http://en.wikipedia.org/wiki/Abstract_factory_pattern). – Adriaan Koster Sep 06 '11 at 10:01
  • Thanks! :-) Still I don't choose the name of the matrix, like I wanted. I wonder if this enum idea can be executed. Thanks for the idea, it's much better than create an instance of the MatrixImplFactory. – Numerator Sep 06 '11 at 10:04
  • Sure you could make an enum version of this. I will post an answer in a couple of minutes to demonstrate. However, you will need to standardize the arguments of the factory methods (like an Object[] args) which doesn't improve the usability of the API. A normal factory is the way to go I think. If you want you can represent the name of the matrix in the method name. – Adriaan Koster Sep 06 '11 at 10:07
1

I think this might be what you want to try:

public enum Matricies {

    DIAGONAL_MATRIX(new DiagonalMatrix()),
    OTHER_MATRIX(new OtherMatrix(4, 4));

    private MainMatrix value; // each value of the enum has a value which is an instance of a matrix

    Matricies(MainMatrix val) { // enum constructor to set instance of matrix
        value = val;
    }

    public MainMatrix getValue() {
        return value;
    }
}

To get instance of diagonal matrix:

MainMatrix diagMatrix = Matricies.DIAGONAL_MATRIX.getValue();
luketorjussen
  • 3,156
  • 1
  • 21
  • 38
0
  1. Write the above code in Eclipse
  2. Put the cursor within the text MainMatrix
  3. Press F4.

F4 is the Eclipse shortcut to open the 'Type Hierarchy' view. This will show you all sub-types of the currently selected type.

johnstok
  • 96,212
  • 12
  • 54
  • 76
  • Thank you but I want to write a code for that, a common class or something, I don't mind the technical side. – Numerator Sep 06 '11 at 09:20
0

If all the classes are implementations of matrices, then it probably makes sense to have them implement a common interface, or extend a common abstract class. With this simple 2 level hierarchy, you can also build an array of the common super-class/interface. Here's an example of what I mean:

public class AA {

    public interface MainMatrix {

    }

    public class MatrixA implements MainMatrix {

    }

    public class MatrixB implements MainMatrix {

    }

    public void go() {
        MainMatrix[] mainMatrices = new MainMatrix[2];
        mainMatrices[0] = new MatrixA();
        mainMatrices[1] = new MatrixB();
    }

}
MarcoS
  • 13,386
  • 7
  • 42
  • 63
  • In the question Nir states that all Matrix classes implement MainMatrix. "with this simple 2 level hierarchy you can also build an array of the common super-class" - this is the question, how do you do this? – luketorjussen Sep 06 '11 at 09:32
  • I added a code snippet showing what I meant. I think the question was slightly modified after I posted my answer, and I probably misunderstood the original question. – MarcoS Sep 06 '11 at 10:03