2017-05-15 5 views
0

Je crée une classe Matrix en Java pour l'utiliser dans un programme d'algèbre linéaire. En ce moment, il détient des doubles, mais je veux l'abstraire.Quelle est la bonne façon de remplacer une méthode d'interface pour s'assurer qu'elle ne peut être utilisée que sur des objets de types identiques?

J'ai créé une interface appelée MatrixElement, qui contiendra add, multiply, divide, et toute autre méthode arithmétique nécessaires pour effectuer ces opérations de la matrice.

Voici un extrait de la Matrix classe:

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); 
    } 

} 

Voici comment les méthodes sont déclarées dans MatrixElement

public interface MatrixElement { 
    public MatrixElement add(MatrixElement e); 
} 

Enfin, voici une classe d'exemple que j'ai créé qui implémente cette 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; 

    } 
} 

L'idée principale ici est la suivante:

  • objets Matrix peuvent contenir des instances de toute une classe qui implémente l'interface MatrixElement
  • MatrixElement contient des méthodes arithmétiques nécessaires pour la manipulation de la matrice, comme add
  • Le botteur: Les classes qui implémentent MatrixElement ne peut utiliser ses méthodes sur d'autres instances de la même classe. Par exemple, Fraction peut uniquement être ajouté à d'autres instances Fraction. Deux classes peuvent implémenter MatrixElement, mais elles ne devraient pas nécessairement pouvoir s'ajouter les unes aux autres.

J'ai exécuté cette conception par un autre programmeur et on m'a dit que le lancer comme ceci est une mauvaise pratique. Si oui, quelle est la bonne façon de le faire? Comment puis-je utiliser une interface pour regrouper des classes ayant des fonctionnalités similaires à celles du paramétrage, mais restreindre les enfants de cette interface qui peuvent être utilisés dans les méthodes des enfants?

+0

'nouveau T()' ne compilera pas –

+2

'public static Matrix somme (matrice a, matrice b)' –

+0

@Lashane @ElliotFrisch vous remercie d'avoir ceux sur. Je n'ai pas encore écrit la version générique de 'Matrix', donc j'attends quelques erreurs de syntaxe. Cette pièce a été principalement fournie pour donner un contexte. Ma question est dans l'implémentation de l'interface 'MatrixElement' – user3043902

Répondre

0

Il y a deux exigences pour les génériques dans le message ci-dessus.

Exigence 1: Les éléments qui peuvent être ajoutés à d'autres éléments du même type

Vous souhaitez imposer un contrat sur certains types de données afin que les instances de ces types peuvent être ajoutés à d'autres instances du même type et du même type uniquement. L'intention est de soutenir les types d'opérations suivantes:

int + int = int 
long + long = long 
real fraction + real fraction = real fraction 
complex number + complex number = complex number 

Ce contrat peut être exprimé comme suit:

public interface MatrixElement<T> { 
    T add(T e); 
} 

Dans un langage simple, ce contrat dit qu'un MatrixElement est un type dont les instances peuvent être ajouté à d'autres instances du même type pour donner encore une autre instance du même type, ce qui était nécessaire.

Exigence 2: matrices à deux dimensions d'éléments, tous du même type peut être ajouté à d'autres matrices à deux dimensions d'éléments du même type et mêmes dimensions

Ce contrat peut être exprimée:

public class Matrix<T extends MatrixElement<T>> { 
    public Matrix<T> add (Matrix<T> another) { ... } 
} 

Ce contrat dit qu'un Matrix se compose d'éléments de type MatrixElement, de sorte que tous les éléments sont de même type. Le Matrix permet également d'ajouter un autre Matrix, à condition que les deux aient des éléments du même type. Le résultat est renvoyé en tant que troisième Matrix avec des éléments du même type. Un échantillon est disponible on Github.

+0

Merci pour votre explication détaillée et votre code exemples. J'apprécie vraiment cela. Question répondue. – user3043902