我正在尝试比较 compareCriteria。简单的,例如“between”和“inArray”或“greaterThan”。我对这些类使用多态性。他们从 compareCriteria 接口(interface)共享的一种方法是“matchCompareCriteria”。
我试图避免的是让每个类检查它们应该匹配的 compareCriteria 类型。例如,inArray 对象将检查 matchCompareCriteria 是否传递了一个 inArray 对象,如果没有,它将返回 false,如果是,它知道如何比较。
也许 instanceof 在这种情况下是完全合法的(对象知道自己),但我仍在寻找避免它的可能方法。有什么想法吗?
伪代码示例:
betweenXandY = create new between class(x, y)
greaterThanZ = create new greaterThan class(z)
greaterThanZ.matchCompareCriteria(betweenXandY)
如果 X 和 Y 大于 Z,它将返回 true。
编辑:
1) instanceof 是我现在看到的,根据 matchCompareCriteria 方法的需要。我想摆脱它
2) matchCompareCritera 检查一个 compareCriteria 是否被另一个包含。如果一个的所有可能值都被另一个包含,则返回 true。对于 compareCriteria 的许多组合,比较它们甚至没有意义,因此它们返回 false(例如 betweenAlfa 和 betweenNum 是不兼容的)。
最佳答案
您描述的问题称为 double dispatch .这个名字来源于这样一个事实,即您需要根据两个对象的类型(因此:double)来决定执行(分派(dispatch))代码。
通常在 OO 中有单个分派(dispatch) - 在对象上调用方法会导致该对象执行该方法的实现。
在您的例子中,您有两个对象,要执行的实现取决于两个对象的类型。从根本上说,当您以前只处理标准的 OO 情况时,这暗示了一种“感觉不对”的耦合。但这并不是真正的错误 - 它只是略微超出了 OO 的基本特征直接适合解决的问题范围。
如果您使用的是动态语言(或具有反射的静态类型语言,对于此目的来说它是动态的),您可以在基类中使用调度程序方法来实现它。在伪代码中:
class OperatorBase
{
bool matchCompareCriteria(var other)
{
var comparisonMethod = this.GetMethod("matchCompareCriteria" + other.TypeName);
if (comparisonMethod == null)
return false;
return comparisonMethod(other);
}
}
在这里,我假设该语言在每个名为 GetMethod
的类中都有一个内置方法,它允许我按名称查找方法,并在每个获取的对象上都有一个 TypeName 属性me 对象类型的名称。因此,如果另一个类是 GreaterThan
,并且派生类有一个名为 matchCompareCriteriaGreaterThan 的方法,我们将调用该方法:
class SomeOperator : Base
{
bool matchCompareCriteriaGreaterThan(var other)
{
// 'other' is definitely a GreaterThan, no need to check
}
}
因此您只需编写一个具有正确名称的方法,然后分派(dispatch)就会发生。
在支持按参数类型重载方法的静态类型语言中,我们可以避免必须发明串联命名约定 - 例如,在 C# 中:
class OperatorBase
{
public bool CompareWith(object other)
{
var compare = GetType().GetMethod("CompareWithType", new[] { other.GetType() });
if (compare == null)
return false;
return (bool)compare.Invoke(this, new[] { other });
}
}
class GreaterThan : OperatorBase { }
class LessThan : OperatorBase { }
class WithinRange : OperatorBase
{
// Just write whatever versions of CompareWithType you need.
public bool CompareWithType(GreaterThan gt)
{
return true;
}
public bool CompareWithType(LessThan gt)
{
return true;
}
}
class Program
{
static void Main(string[] args)
{
GreaterThan gt = new GreaterThan();
WithinRange wr = new WithinRange();
Console.WriteLine(wr.CompareWith(gt));
}
}
如果您要向模型中添加新类型,则需要查看之前的每个类型并问问自己它们是否需要以某种方式与新类型交互。因此,每个 类型都必须定义一种与所有其他 类型交互的方式——即使交互是一些非常简单的默认值(例如“除了返回 true 之外什么都不做
”)。即使是那个简单的默认值也代表您必须做出的深思熟虑的选择。不必为最常见的情况显式编写任何代码的便利性掩盖了这一点。
因此,捕获外部表中所有类型之间的关系可能更有意义,而不是将其分散在所有对象周围。将其集中化的值(value)在于,您可以立即查看是否遗漏了类型之间的任何重要交互。
所以你可以有一个字典/ map /哈希表(不管它在你的语言中叫什么)将一个类型映射到另一个字典。第二个字典将第二种类型映射到这两种类型的正确比较函数。一般的 CompareWith 函数会使用该数据结构来查找要调用的正确比较函数。
哪种方法是正确的取决于您最终可能在模型中使用多少种类型。
关于oop - 在这种情况下如何替换 instanceof ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1406860/