我有矩阵类的层次结构。我不想改变我的类,所以我决定使用访问者模式来包括诸如加法,乘法等矩阵运算。我的层次结构看起来像这样:
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是否会重载运算符&#39; +&#39;。我决定使用具体访问者的参数这样的委托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 :(得分:1)
通常,正在执行的操作由访问者的类型决定,操作数类型的操作区别由重载的访问者方法定义。这称为双重调度。在您的情况下,实现某些通用二进制矩阵操作的访问者必须如下所示:
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);