代码之家  ›  专栏  ›  技术社区  ›  fenomas

键入在接口中指定的克隆方法

  •  0
  • fenomas  · 技术社区  · 15 年前

    我正在编写一个接口,它需要类来实现clone()方法。我对这件事的天真态度是这样的:

    public interface ISolvableGame {
        function clone():ISolvableGame;
        //...
    }
    

    其他地方:

    public class MyGame implements ISolvableGame {
        public function clone():MyGame {
            // ...
        }
    }
    

    我本以为这种签名是合法的,因为 MyGame.clone() 返回实现isolavablegame的类的实例,在我看来,该类满足接口中的约定。但是,像上面这样的代码会生成一个编译错误,这涉及到 MyPo.C克隆() 具有与接口中指定的签名不同的签名。

    因此,我的问题是,如果实现的方法必须与接口中的签名完全匹配,如何才能使需要克隆方法的接口?显然,让接口更具体一点没有任何意义。但是,如果我使实现的方法不那么具体(例如,如果我键入 MyPo.C克隆() 作为回报 ISolvableGame ,克隆方法的其他用户将不再知道他们得到了什么。

    我需要克隆方法的两个版本吗,一个类型为 隔离域名 满足接口和另一个类型为 MyGame 在课堂上使用?还是有更好的方法?


    注: 我在ActuScript 3中工作(实现ECMA4规范的Java语言)。我将此标记为语言不可知论,因为假设AS3在处理接口方面不是唯一的。但是如果我上面的示例代码可以用其他语言工作,那么我的问题可能是特定于我的语言的。


    更新: 我突然想到,我的语言核心库是如何处理这一问题的。例如,有一个 IEventDispatcher 接口,它定义了一个方法 dispatch():Event -所以任何一个班 子类 属于 Event 无法实现 IEventDispatcher(事件调度员) 这最终类似于我的问题。

    核心库通过使用此类类来处理这一问题。 继承 来自一个班 EventDispatcher 为实现 IEventDispatcher(事件调度员) . 因此获得了编译时类型的安全性,但代价是首先要减少使用接口的时间点,因为人们通常喜欢使用接口来避免继承带来的问题。

    我认为我的选择是:

    • 最终依赖于继承,就像核心库一样
    • 实现Frederik描述的两种方法,使用不同的名称
    • 牺牲编译时类型的安全性,如James所描述的

    答: 最后,我选择让接口指定 cloneToSolvable 方法-即,接口指定要克隆到接口类型的方法,并且实现类除了可能具有的任何更具体类型的克隆方法之外,还必须具有该方法。在我看来,这是最不令人不快的选择。

    3 回复  |  直到 15 年前
        1
  •  1
  •   James Fassett    15 年前

    AS3不允许您进行重载(多个具有相同名称的函数,由返回类型或参数类型区分)只重写(子类可以替换基类实现)。

    例如

    function foo():int {}
    function foo():String {}
    function foo(a:String):void {}
    

    是名为foo的函数的重载-不能在actionscript中执行此操作。在某种意义上,接口比重载更接近于重写,因为您“继承”了接口。

    // in your specific case you couldn't have these two functions
    // defined within the same scope
    public function clone():MyGame {}
    public function clone():ISolvableGame {}
    

    你要做的是把这两个概念混合起来。您想重载一个试图重写的接口。正如Fredrik的文章所显示的那样,即使在支持重载的语言中(其中as3不是一种语言),您也常常不能同时执行这两种操作。接口强制您具有具有精确签名的函数: clone():ISolvableGame 你不能用额外的 clone():MyGame

    如果您正在寻找类型安全性,则在编译时无法获得它,但如果您在调用方检查返回类型,则可以在运行时获得它。

    例如

    // this will throw if clone does not return an
    // object that is cast-able to MyGame
    var game:MyGame = MyGame(someObj.clone());
    

    我也希望能在 MyGame 但我不知道怎么做。

        2
  •  1
  •   Fredrik Mörk    15 年前

    我对actionscript没有经验,因此这可能是一个可行的解决方案,也可能不是,但在C中,我通常这样做:

    public class MyGame : ISolvableGame {
        public MyGame clone(){
            // ...
        }
    
        ISolvableGame ISolvableGame.clone() {
            return this.clone();
        }
    }
    

    换句话说,我创建了一个“类型化”克隆方法(它不实现inteface,因为它在返回类型上有所不同)。然后我显式地实现接口方法,它将调用类型化克隆方法并返回结果。这是合法的行动,因为 MyGame 可以铸造成 ISolvableGame .

        3
  •  0
  •   Amarghosh    15 年前

    继承的克隆方法总是以超级类作为返回类型。例如,所有事件类都重写 flash.events.Event 类返回 Event 对象并实现它以返回各自的派生类对象。