koe*_*oen 2 oop polymorphism criteria instanceof
我想比较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)
Run Code Online (Sandbox Code Playgroud)
如果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);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我想象语言在每个被调用的类中都有一个内置方法,GetMethod
它允许我按名称查找方法,并且每个对象上都有一个TypeName属性,它获取对象类型的名称.因此,如果另一个类是a GreaterThan
,并且派生类有一个名为matchCompareCriteriaGreaterThan的方法,我们将调用该方法:
class SomeOperator : Base
{
bool matchCompareCriteriaGreaterThan(var other)
{
// 'other' is definitely a GreaterThan, no need to check
}
}
Run Code Online (Sandbox Code Playgroud)
所以你只需要编写一个具有正确名称的方法并发生调度.
在通过参数类型支持方法重载的静态类型语言中,我们可以避免必须发明连接的命名约定 - 例如,它在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));
}
}
Run Code Online (Sandbox Code Playgroud)
如果要在模型中添加新类型,则需要查看以前的每个类型,并询问自己是否需要以某种方式与新类型进行交互.因此,每种类型都必须定义一种与其他类型交互的方式- 即使交互是一些非常简单的默认(例如"除了返回之外什么也不做true
").即使是那个简单的默认也代表了你必须做出的慎重选择.这是为了不必为最常见的情况显式编写任何代码的便利性而伪装.
因此,捕获外部表中所有类型之间的关系而不是将其散布在所有对象周围可能更有意义.集中它的价值在于您可以立即查看是否错过了类型之间的任何重要交互.
所以你可以有一个字典/ map/hashtable(用你的语言调用它)将一个类型映射到另一个字典.第二个字典将第二种类型映射到这两种类型的右对比函数.一般的CompareWith函数将使用该数据结构来查找要调用的正确比较函数.
哪种方法是正确的取决于您可能在模型中最终使用的类型数量.
既然你引用了instanceof
,我假设我们在这里工作.这可能会让您使用重载.考虑一个名为的接口SomeInterface
,它有一个方法:
public interface SomeInterface {
public boolean test (SomeInterface s);
}
Run Code Online (Sandbox Code Playgroud)
现在,我们定义两个(巧妙命名)实现的类SomeInterface
:Some1
和Some2
. Some2
很无聊:test
总是返回false.但是test
当给出一个时,Some1会覆盖该函数Some2
:
public class Some1 implements SomeInterface {
public boolean test (SomeInterface s) {
return false;
}
public boolean test (Some2 s) {
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
这使我们可以避免使用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
Run Code Online (Sandbox Code Playgroud)
看到第三次测试?即使inter
是类型Some2
,它也被视为一种类型SomeInterface
.在Java编译时确定重载分辨率,这可能使它对您完全无用.
这让你回到正方形:使用instanceof
(在运行时评估).即使你这样做,它仍然是一个糟糕的设计.您的每个课程都必须了解所有其他课程.如果您决定添加另一个,则必须返回所有现有的添加功能来处理新类.这很难得到匆忙,这是设计糟糕的好兆头.
重新设计是有序的,但没有更多的信息,我不能给你一个特别好的推动正确的方向.