我正在尝试比较compareCriteria。简单的比如'between'和'inArray'或'greaterThan'。我对这些类使用多态。他们从compareCriteria接口共享的一种方法是'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)。

通常在OO中有单个调度 - 调用对象上的方法会导致该对象的方法实现执行。

在您的情况下,您有两个对象,要执行的实现取决于两个对象的类型。从根本上说,存在一种隐含的耦合,即“感觉不对”。当你以前只处理标准的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属性我是对象类型的名称。因此,如果另一个类是 GreaterThan ,并且派生类有一个名为matchCompareCriteriaGreaterThan的方法,我们将调用该方法:

class SomeOperator : Base
{
    bool matchCompareCriteriaGreaterThan(var other)
    {
        // 'other' is definitely a GreaterThan, no need to check
    }
}

因此,您只需编写一个具有正确名称的方法,即可进行调度。

在一种支持按参数类型进行方法重载的静态类型语言中,我们可以避免必须发明一个连接的命名约定 - 例如,这里是在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));
    }
}

如果要向模型中添加新类型,则需要查看以前的每种类型,并询问自己是否需要以某种方式与新类型进行交互。因此,每个类型必须定义一种与每个其他类型交互的方式 - 即使交互是一些非常简单的默认(例如“除了返回之外什么也不做”)真&QUOT)。即使是那个简单的默认也代表了你必须做出的慎重选择。这是为了不必为最常见的情况明确地编写任何代码的便利性而伪装。

因此,捕获外部表中所有类型之间的关系而不是将其散布在所有对象周围可能更有意义。集中它的价值在于您可以立即查看是否错过了类型之间的任何重要交互。

所以你可以有一个字典/ map / hashtable(用你的语言调用它)将一个类型映射到另一个字典。第二个字典将第二种类型映射到这两种类型的右对比函数。一般的CompareWith函数将使用该数据结构来查找要调用的正确比较函数。

哪种方法是正确的取决于您在模型中最终可能会有多少种类型。

其他提示

由于您引用 instanceof ,我假设我们在这里使用Java。这可能会让您使用重载。考虑一个名为 SomeInterface 的接口,它有一个方法:

public interface SomeInterface {
    public boolean test (SomeInterface s);
}

现在,我们定义两个(巧妙命名的)类,它们实现 SomeInterface Some1 Some2 Some2 很无聊: test 总是返回false。但是当给出 Some2 时,Some1会覆盖 test 函数:

public class Some1 implements SomeInterface {
    public boolean test (SomeInterface s) {
        return false;
    }

    public boolean test (Some2 s) {
        return true;
    }
}

这使我们可以避免一行一行的if语句进行类型检查。但有一点需要注意。请考虑以下代码:

Some1 s1 = new Some1 ();
Some2 s2 = new Some2 ();
SomeInterface inter = new Some2 ();

System.out.println(s1.test(s2));     // true
System.out.println(s2.test(s1));     // false
System.out.println(s1.test(inter));  // false

看到第三次测试?即使 inter 的类型为 Some2 ,它也会被视为 SomeInterface 。过载分辨率是在Java编译时确定的,这可能会让你完全无用。

这会让你回到原点:使用 instanceof (在运行时进行评估)。即使你这样做,它仍然是一个糟糕的设计。您的每个课程都必须了解所有其他课程。如果您决定添加另一个,则必须返回所有现有的添加功能来处理新类。这很难得到匆忙,这是设计不好的好兆头。

重新设计是有序的,但没有更多的信息,我不能给你一个特别好的推动正确的方向。

您需要创建一个名为Criteria的超类或接口。然后每个具体子类将实现Criteria接口。之间,greaterthan等是标准。

Criteria类将指定matchCompareCriteria方法,该方法接受Criteria。实际逻辑将驻留在子类中。

您正在寻找策略设计模式或模板设计模式。

如果我理解得很好,你的方法依赖于类型检查。这很难避免,多态性无法解决问题。在您的示例中,inArray 需要来检查参数的类型,因为方法的行为取决于。你不能通过多态来做到这一点,这意味着你不能在你的类上放置多态方法来处理这种情况。这是因为你的matchCompareCriteria取决于参数的类型而不是行为

当您检查对象的类型以选择要具有的行为时,不使用 instanceof 的规则是有效的。显然,该行为属于您检查其类型的不同对象。但在这种情况下,你的对象的行为取决于你传入的对象的类型并且属于调用对象,而不是像之前那样在被调用对象上。这种情况类似于覆盖 equals()时的情况。您进行类型检查,以便传入的对象与 this 对象的类型相同,然后实现您的行为:如果测试失败,则返回false;否则,进行相等测试。

结论:在这种情况下,使用 instanceof 是可以的。

以下是来自Steve Yegge的更长的文章,其解释更好,我认为,使用一个简单明了的例子。我认为这可以很好地解决您的问题。

记住:多态性是好的,除非它不是。 :)

Smalltalk方法是在层次结构中引入更多层。因此 bigThan 之间的将是 rangedCompareCriteria (或其他)的子类,而 rangeCompareCriteria :: matchCompareCriteria 将返回<当被问及两个实例是否具有可比性时,强>真

说到这,你可能想要重命名“matchCompareCriteria”。表达意图更好的东西。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top