[英]What is the best way to use visitor pattern in a hierarchy of generic classes?
我有矩陣類的層次結構。 我不想更改類,所以我決定使用訪客模式來包括諸如加法,乘法等矩陣操作。我的層次結構如下所示:
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> {}
所有這些類都實現Accept方法:
public override Matrix<T> Accept(MatrixVisitor<T> visitor, Matrix<T> matrix)
{
return visitor.Operation(this, matrix);
}
但是我被困在添加了兩個類型為T的元素上。我不知道類型T是否會重載運算符'+'。 我決定使用具體訪客參數之類的委托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]);
}
}
我真的很討厭我的方式,因為如果我想添加或乘以方矩陣和對角矩陣,則必須創建一個visitor實例並再次定義操作。 有沒有更優雅的方式? 謝謝。
通常,要執行的操作由訪問者的類型確定,而操作數與操作數類型的區分由重載的訪問者方法定義。 這稱為雙重調度 。 在您的情況下,實現一些通用二進制矩陣操作的訪問者必須看起來像這樣:
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類的基礎施加的約束:只要兩個矩陣具有兼容的元素類型和匹配的維度,就不必關心它們是對角線還是其他。 因此,您可以使用一種方法為所有類型的矩陣實現通用的總和訪問者:
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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.