2016-07-28 1 views
0

私はマトリックスクラスの階層を持っています。私の階層はそのように見えるなど、私は私のクラスを変更したいdid'tので、私はさらに、乗算のような行列演算を含めるようにビジターパターンを使用することにしました:ジェネリッククラスの階層でビジターパターンを使用する最も良い方法は何ですか?

public abstract class Matrix<T> { 
    public abstract T GetValue(int i, int j); 
    public abstract void SetValue(int i, int j, T value); 
    public abstract Matrix<T> Accept(MatrixVisitor<T> visitor, Matrix<T> matrix); 
} 

public class SquareMatrix<T> : Matrix<T> {} 
public class DiagonalMatrix<T> : Matrix<T> {} 
public class SymmetricMatrix<T> : Matrix<T> {} 

これらのクラスのすべてのメソッドを受け入れる実装します。

public override Matrix<T> Accept(MatrixVisitor<T> visitor, Matrix<T> matrix) 
     { 
      return visitor.Operation(this, matrix); 
     } 

しかし、私は、私はTを入力します知らない型Tを持つ2つの要素を追加してstuckedたが「+」演算子をオーバーロードしています。私は具体的な訪問者のパラメータなどの代理人Funcを使用することに決めました。そして今、私の具体的な訪問者のクラスは次のようになります。私は正方行列と対角行列を追加したり、乗算したい場合、私は訪問者のインスタンスを作成し、操作を再定義する必要があるため

public class SumOfSquareMatricesVisitor<T> : MatrixVisitor<T> 
    { 
     public SumOfSquareMatricesVisitor(Func<T, T, T> sumOfTwoTypesOperation) 
     { 
      this.sumOfTwoTypesOperation = sumOfTwoTypesOperation; 
     } 

     public override Matrix<T> Operation(Matrix<T> A, Matrix<T> B) 
     { 
      // example 
      // into a loop 
      // result = sumOfTwoTypesOperation(A[i,j], B[i,j]); 
     } 
} 

私は本当に、私の方法を憎みます。よりエレガントな方法がありますか?ありがとう。

答えて

0

通常、実行されるオペレーションはビジターのタイプによって決定され、オペランドタイプによるオペレーションの区別は、オーバーロードされたビジターメソッドによって定義されます。これはダブルディスパッチと呼ばれます。あなたのケースでは、いくつかの一般的なバイナリ行列演算は次のようになりしなければならないを実装訪問者:あなたは、オペランドのすべての組み合わせのためのオーバーロードメソッドを実装する必要があるとして

public class SomeOperationVisitor<T> : BinaryOperationMatrixVisitor<T> 
{ 
    public SomeOperationVisitor(Func<T, T, T> someItemOp) 
    { 
    this.someItemOp = someItemOp; 
    } 

    public override Matrix<T> Operation(SquareMatrix<T> a, SquareMatrix<T> b) 
    { ... } 

    public override Matrix<T> Operation(SquareMatrix<T> a, DiagonalMatrix<T> b) 
    { ... } 

    // other methods for all combination of element types 
} 

バイナリ動作を実現するために訪問者を使用しては非常に珍しいですタイプ。

しかし、あなたの特別なケースでは、加算と乗算だけに限定されている場合は、そうする必要はありません。これらの演算は、継承されたクラスが基本Matrixクラスに追加する制約に依存しません.2つの行列が互換性のある要素型と一致する次元を持つ限り、それらが対角線であるかどうかは気にしません。だから、あなただけの1つの方法で行列のすべてのタイプのための一般的な和の訪問者を実装することができます

public class MatrixSumVisitor<T> : BinaryOperationMatrixVisitor<T> 
{ 
    public MatrixSumVisitor(Func<T, T, T> addOp) 
    { 
    this.addOp = addOp; 
    } 

    public override Matrix<T> Operation(Matrix<T> a, Matrix<T> b) 
    { 
    // 1. Check that dimensions of a and b match. 
    // 2. Add a and b. 
    } 
} 

しかし、これが事実であるならば、あなたは今単一の発送を行うように、すべての訪問者を必要としない - ビジタータイプのみ。この場合、Acceptメソッドを完全に削除することができます。単純にコールを転送するだけでは何も役に立ちません。代わりにこれを行う:

Matrix<int> a, b; 
// ... 
MatrixBinaryOp op = new MatrixSum(...); 
var sum = op.Operation(a, b); 
関連する問題