2011-10-21 39 views
0

単純なジェネリックマトリックスクラスを作成していたので、私のソリューションが気に入らない問題に遭遇しましたので、より良いものに助けを求めると思いました。インタフェースタイプを返す拡張メソッド

ここで説明するインターフェース考えてみましょう:拡張

public static class MatrixExtensions 
{ 
    /// <summary> 
    /// Performs a standard matrix addition 
    /// </summary> 
    public static IMatrix<T> Add<T>(this IMatrix<T> matrix, IMatrix<T> other, IScalarOperators<T> operators) 
    { 
     JoinCells<T> joiner = new JoinCells<T>(); 
     return joiner.Join(matrix, other, null, operators.OperatorAdd); 
    } 

    /// <summary> 
    /// Adds a row to the end of the matrix 
    /// </summary> 
    public static void AddRow<T>(this IMatrix<T> matrix); 

    /// <summary> 
    /// Adds a number of rows to the end of the matrix 
    /// </summary> 
    public static void AddRows<T>(this IMatrix<T> matrix, int rows); 

    /// <summary> 
    /// Adds a column to the end of the matrix 
    /// </summary> 
    public static void AddColumn<T>(this IMatrix<T> matrix); 

    /// <summary> 
    /// Adds a number of columns to the end of the matrix 
    /// </summary> 
    public static void AddColumns<T>(this IMatrix<T> matrix, int columns); 

    /// <summary> 
    /// Gets the column at the specified position 
    /// </summary> 
    public static IList<T> ColumnAt<T>(this IMatrix<T> matrix, int position); 

    /// <summary> 
    /// Gets the number of columns in the matrix 
    /// </summary> 
    public static int ColumnCount<T>(this IMatrix<T> matrix); 

    /// <summary> 
    /// Sets the number of columns in the matrix 
    /// </summary> 
    public static void ColumnCount<T>(this IMatrix<T> matrix, int columns); 

    /// <summary> 
    /// Deletes the last column from the matrix 
    /// </summary> 
    public static void DeleteLastColumn<T>(this IMatrix<T> matrix); 

    /// <summary> 
    /// Deletes the last row from the matrix 
    /// </summary> 
    public static void DeleteLastRow<T>(this IMatrix<T> matrix); 

    /// <summary> 
    /// Gets the value at the specified position in the matrix 
    /// </summary> 
    public static T GetValueAt<T>(this IMatrix<T> matrix, int row, int column); 

    /// <summary> 
    /// Multiplies this matrix with the other matrix and returns the result 
    /// </summary> 
    public static IMatrix<T> Multiply<T>(this IMatrix<T> matrix, IMatrix<T> other, IVectorOperators<T> vectorOperators, IScalarOperators<T> scalarOperators) 
    { 
     JoinRowColumn<T> joiner = new JoinRowColumn<T>(); 
     return joiner.Join(matrix, other, vectorOperators.OperatorAdd, scalarOperators.OperatorMultiply); 
    } 

    /// <summary> 
    /// Gets the row at the specified position 
    /// </summary> 
    public static IList<T> RowAt<T>(this IMatrix<T> matrix, int position); 

    /// <summary> 
    /// Gets the number of rows in the matrix 
    /// </summary> 
    public static int RowCount<T>(this IMatrix<T> matrix); 

    /// <summary> 
    /// Sets the number of rows in the matrix 
    /// </summary> 
    public static void RowCount<T>(this IMatrix<T> matrix, int rows); 
} 

public interface IMatrix<T> 
{ 
    void DeleteColumn(int position); 
    void DeleteRow(int position); 
    // Returns a NEW IMatrix<T> 
    IMatrix<T> FromRows(IList<IList<T>> rows);  // would like to remove 
    // Returns a NEW IMatrix<T> 
    IMatrix<T> FromColumns(IList<IList<T>> columns);// would like to remove 
    IList<IList<T>> GetColumns(); 
    IList<IList<T>> GetRows(); 
    void InsertColumn(int position); 
    void InsertRow(int position); 
    void SetValueAt(int row, int column, T value); 
} 

は、乗算方法を考えてみましょう。 IMatrixオブジェクトに乗算した結果はよく知られています。簡単にするために、行列の整数実装のみを考慮してください。結果を計算するために、Multiply(int、int)とAdd(int、int)がどのように動作するか以外は、行列について何も知る必要はありません。それらの両方がわかっているので、その結果で新しい行列を返すために他のものは必要ありません。しかし、私はこれを行う最善の方法が不明です。

私のアプローチは、FromRowsとFromColumnsの2つのメソッドをインターフェイスに追加することでした。この特定の方法で行列を強制的に構築してはいけないので、これは間違っています(または私は感じます)。しかし、それがこのインタフェースのインスタンスを返す方法を理解できる唯一の方法です。 IListを使ってジョイナクラスで行列を構築し、コレクションが行または列の定義であることを確認してから、FromRowsメソッドを使用します。おそらく、これは一例でより多くの意味を行います:ありますが、

/// <summary> 
/// Class used for joining by combining rows and columns 
/// </summary> 
/// <typeparam name="T"> 
/// Type of the values contained in the matrix 
/// </typeparam> 
class JoinRowColumn<T> : IJoinMatrix<T> 
{ 
    public IMatrix<T> Join(IMatrix<T> a, IMatrix<T> b, IOperateVector<T> vectorOperation, IOperateScalar<T> cellOperation) 
    { 
     // ensure that the matricies can be joined 
     if (a.ColumnCount() != b.RowCount()) 
     { 
      throw new ArgumentException("Cannot join matricies. Invalid dimensions"); 
     } 

     IList<IList<T>> rowDefinition = IMatrixHelpers.GetRowDefinition<T>(a.RowCount(), b.ColumnCount()); 
     for (int row = 0; row < a.RowCount(); row++) 
     { 
      IList<T> aRow = a.RowAt(row); 
      for (int col = 0; col < b.ColumnCount(); col++) 
      { 
       IList<T> bCol = b.ColumnAt(col); 
       rowDefinition[row][col] = vectorOperation.Operate(aRow, bCol, cellOperation); 
      } 
     } 
     // I do not like this because it is unclear that the 
     // method is returning a NEW instance of IMatrix<T> 
     // based on the row definition. It does not update 
     // a to contain the matrix defined by rowDefinition 
     return a.FromRows(rowDefinition); // UGLY! 
    } 
} 

だからメソッドの最後に、私は(おそらく)同じタイプ(の新しい行列を生むために私に与えられた行列のいずれかを使用します具体的な実装の限り、マトリックスが返すものに制限はありません)。問題の一部があります。 FromRowsはNEWインスタンスを返します。しかし、明らかではなく、メソッドが呼び出されている行列を更新していると思うかもしれません。

インターフェイスの具体的な実装を構築する方法で追加するためのパターンはありますか?または、この方法はOKと思われますか?

私はジェネリックに精通していますので、何か明白ではない場合は私にご負担ください。

答えて

1
  • デザインに
  • あなたはこのような場合に使用し、デフォルトの実装を、それの新しいインスタンスを返す、あなたのインターフェイス上Construct(int xDimension, int yDimension)という名前のメソッドを含めます。インターフェイスに対してコーディングするので、誰も特定の実装を想定する必要はありません。

個人的には、私は2番目のオプションを使用します。とにかくインターフェイスに対してコーディングしていますが、実装は重要ではありません。あなたは簡単に行列の既定の実装を返すことができ、呼び出し元はそれを扱うことができます。加えて、渡された行列を操作するのではなく、新しい行列を作成してそれを操作するのではなく、他の方法にもこれを採用することを考えなければなりません。

これはLINQの動作と似ていて、途中でバグが侵入するのを防ぎます。現在のオブジェクトを操作する場合は、拡張メソッドは必要ありません。

+0

私はデフォルトの実装を返すことを考えました。「私が選択したデフォルトが最適ではない場合はどうすればいいのですか...」と思っていました。それは時期尚早で少し恥ずかしいですね。( – MPavlak

+0

Nah、そうではありません。私の手の中で次善最適解の数を数えることはできません。最適最適解は、それらが改善していると分かっていれば、問題ではありません。コーディング中に私たちはすべて学習しています、それが私たちの職業の仕組みです。 – Femaref