Actionscript 3 如何创建一个子类,为同一函数名接受不同的参数?

Actionscript 3 如何创建一个子类,为同一函数名接受不同的参数?,actionscript-3,class,interface,subclass,Actionscript 3,Class,Interface,Subclass,所以我制作了这个简单的界面: package{ public interface GraphADT{ function addNode(newNode:Node):Boolean; } } 我还创建了一个简单的类图: package{ public class Graph implements GraphADT{ protected var nodes:LinkedList; public function

所以我制作了这个简单的界面:

package{
    public interface GraphADT{
        function addNode(newNode:Node):Boolean;     
    }
}
我还创建了一个简单的类图:

package{

    public class Graph implements GraphADT{

        protected var nodes:LinkedList;

        public function Graph(){
            nodes = new LinkedList();
        }

        public function addNode (newNode:Node):Boolean{
            return nodes.add(newNode);
        }
}
最后但并非最不重要的一点是,我创建了另一个简单的类AdjacancyListGraph:

package{
    public class AdjacancyListGraph extends Graph{

        public function AdjacancyListGraph(){
            super();
        }

        override public function addNode(newNode:AwareNode):Boolean{
            return nodes.add(newNode);
        }
}
在这里进行此设置会给我带来错误,即:

1144: Interface method addNode in namespace GraphADT is implemented with an incompatible signature in class AdjacancyListGraph.
仔细检查后,很明显AS3不喜欢Graph中不同图形类的不同参数类型
newNode:Node
,以及AdjacancyListGraph中的
newNode:awaronede

然而,我不明白为什么这会是一个问题,因为
AwareNode
Node
的一个子类


在保持代码完整性的同时,有什么方法可以让我的代码正常工作吗?

我想问题是:你想实现什么

关于为什么会出错,考虑一下:

public class AnotherNode extends Node { }
class... {

    protected function check (node:Node) : Boolean {
        return node is Node;
    }    

    public function addNode (node:Node) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}
然后:

var alGraph:AdjacancyListGraph = new AdjacancyListGraph();

alGraph.addNode(new AnotherNode());  
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)

// but what about the contract? 

var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?
根据界面,这应该是好的。但是,您的实现则相反,您的实现表示它只接受
AwareNode
。存在明显的不匹配。如果您要有一个接口,一个对象应该遵循的契约,那么您最好遵循它。否则,接口的意义首先是什么


如果你想这么做的话,我认为架构在某个地方被搞砸了。即使语言支持它,我也会说这是一个“坏主意”™"

我想问题真的是这样的:你想完成什么

关于为什么会出错,考虑一下:

public class AnotherNode extends Node { }
class... {

    protected function check (node:Node) : Boolean {
        return node is Node;
    }    

    public function addNode (node:Node) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}
然后:

var alGraph:AdjacancyListGraph = new AdjacancyListGraph();

alGraph.addNode(new AnotherNode());  
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)

// but what about the contract? 

var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?
根据接口,这应该是好的。但是你的实现说不是这样,你的实现说它只接受一个
AwareNode
。有一个明显的不匹配。如果你要有一个接口,一个你的对象应该遵循的契约,那么你最好遵循它。否则,接口的意义是什么首先是rface


我认为,如果你试图这样做,架构会在某个地方出错。即使语言支持它,我也会说这是一个“坏主意”™“

简单回答

如果您真的不需要“addNode()”函数只接受一个AwareNode,您可以将参数类型更改为Node。由于AwareNode扩展了Node,您可以毫无问题地传入一个AwareNode。您可以检查函数体中的类型正确性:

subclass... {
    override public function addNode (node:Node ) : Boolean {
        if (node is AwareNode) return nodes.add(node);
        return false;
    }
}
更长的答案

我同意@32bitkid的说法,您得到了一个错误,因为接口中为addNode()定义的参数类型与子类中的类型不同

但是,目前的主要问题是ActionScript通常不允许函数重载(具有多个同名方法,但具有不同的参数或返回值),因为每个函数都被视为泛型类成员—与变量的处理方式相同。您可以这样调用函数:

myClass.addNode (node);
但你也可以这样称呼它:

myClass["addNode"](node);
每个成员都是按名称存储的,您可以始终使用该名称访问它。不幸的是,这意味着您在一个类中只允许使用每个函数名一次,而不管它需要多少类型的参数。任何事情都是有代价的:您在一方面获得了灵活性,在另一方面则失去了一些舒适感

因此,您只允许重写具有完全相同签名的方法-这是一种让您坚持在编写基类时决定的方法。虽然您可能会认为这是一个坏主意,并且使用重载或允许在子类中使用不同签名更有意义,但使用他解释了AS处理函数的方式,这将最终帮助您解决问题:您可以使用类型检查函数,甚至可以将其作为参数传递

考虑这一点:

public class AnotherNode extends Node { }
class... {

    protected function check (node:Node) : Boolean {
        return node is Node;
    }    

    public function addNode (node:Node) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}
在本例中,您可以覆盖检查(节点:node):

并在不破坏接口约定的情况下实现完全相同的效果-在您的示例中,如果传入错误的类型,编译器将抛出错误,而在本例中,错误仅在运行时可见(a
false
返回值)

您还可以使其更加动态:

class... {
    public function addNode (node:Node, check : Function ) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}
请注意,此addNode函数接受函数作为参数,我们调用该函数而不是类方法:

var f:Function = function (node:Node) : Boolean {
    return node is AwareNode;
}

addNode (node, f);
这将使您的实现变得非常灵活-您甚至可以在匿名函数中进行合理性检查,例如验证节点的内容。并且您甚至不必扩展类,除非您打算添加除类型正确性之外的其他功能


拥有一个接口还将允许您创建不从原始基类继承的实现-您可以编写一个完全不同的类层次结构,它只需实现接口,并且您以前的所有代码都将保持有效。

简单回答

如果您真的不需要“addNode()”函数只接受一个AwareNode,您可以将参数类型更改为Node。由于AwareNode扩展了Node,您可以毫无问题地传入一个AwareNode。您可以检查函数体中的类型正确性:

subclass... {
    override public function addNode (node:Node ) : Boolean {
        if (node is AwareNode) return nodes.add(node);
        return false;
    }
}
更长的答案

我同意@32bitkid的说法,您得到了一个错误,因为接口中为addNode()定义的参数类型与子类中的类型不同

但是,目前的主要问题是ActionScript通常不允许函数重载(具有多个同名方法,但具有不同的参数或返回值),因为每个函数都被视为泛型类成员—与变量的处理方式相同。您可以这样调用函数:

myClass.addNode (node);
但你也可以这样称呼它:

myClass["addNode"](node);
每个成员都按名称存储