AS3 - 接口是否需要覆盖,或者类可以从仅由子类使用的接口调用方法吗?

时间:2013-01-23 21:38:17

标签: actionscript-3 methods interface subclass

我有一种可能不可能的愿望。我有一个类,我想从中创建几个子类。每个子类都将实现相同的接口,但我希望BASE类调用该接口的方法。

这是我想要的编译器错误版本:

public class Class1
{
    public function Class1()
    {
        initialize();
    }
}

public interface Int
{
    function initialize():void;
}

public class Class2 extends Class1 implements Int
{
    public function Class2()
    {
        super();
    }

    public function initialize():void
    {
        // Code unique to the class goes here.
    }
}

显然,即使我无意创建Class1实例,此代码也会中断。在这个简化版本中它看起来也很愚蠢,但它有点显示我想要这个的原因:我希望每个类在其构造函数中自动调用initialize(),因此将它保留在超类中是有意义的。

现在,我可以这样做:

public class Class1
{
    public function Class1() implements Int
    {
        initialize();
    }

    public function initialize():void {}
}

public interface Int
{
    function initialize():void;
}

public class Class2 extends Class1 implements Int
{
    public function Class2()
    {
        super();
    }

    public override function initialize():void
    {
        // Code unique to the class goes here.
    }
}

这就是我现在所处的位置,但是将该方法放在超类中并将其覆盖在子类中会破坏具有接口的目的;简单地通过扩展原始类来满足initialize()方法要求,并且我无法知道我可以强制每个子类重写该方法。当然,我可以省略基类中的调用并将其插入到每个子类中,但我也不能强制要求使用THAT。

所以我的问题是,是否存在#1(在基类中调用未实现接口的接口方法)不会中断的版本,或#2版本(覆盖有问题的方法)那将REQUIRE initialize()被子类覆盖?

4 个答案:

答案 0 :(得分:3)

如果我正确解释了您的问题,您希望在Class1的子类上实现接口,而不是直接在Class1上实现。您还希望能够从Class1调用接口中的方法,以便在子类化时自动调用它们。

我现在要指出这个可能很糟糕的设计,但不管你在做什么都可以做到:

界面:

测试的基本界面:

public interface Interface
{

    function init():void;

}

您的基类:

如果任何子类实现init(),则此类将调用Interface

public class Base
{

    public function Base()
    {
        // Use 'is' to check if this implements Interface.
        if(this is Interface)
        {
            // Use 'as' to refer to .init() within Interface.
            (this as Interface).init();
        }
        else
        {
            // Interface was not implemented.
            // Throw an error or whatever you find necessary.
            //
        }
    }

}

这里的技巧是我们使用is来确定子类是否已实现Interface。如果有,我们可以通过as访问它定义的方法,然后继续调用它们。

子类:

这是您测试的直接子类:

public class Sub extends Base implements Interface
{

    public function init():void
    {
        trace('Success!');
    }

}

如果您继续通过构建Sub的实例进行测试,则会在输出面板中按预期注意到Success!

答案 1 :(得分:0)

让基类扩展接口。然后子类覆盖基本方法。这将允许您从基地调用方法。

答案 2 :(得分:0)

我感觉到你的痛苦,抽象课在这里会非常有用。不幸的是,AS3中不存在这些。在你的情况下我能做的最好的只是你的建议稍作改动。

public class Class1
{
    public function Class1() implements Int
    {
        initialize();
    }

    public function initialize():void {
        throw new Error("Subclass of Class1 must override initialize.");
    }
}

显然这会给你一个运行时错误,而不是编译时错误。我仍然只是谨慎地使用这种策略,因为声明方法和抛出错误不是很干净并且是让步。然而,有时候,优点是值得的。

答案 3 :(得分:0)

这是一个古老的话题,但我会发表自己的想法。 调用super()然后对init()进行回调是没有意义的。不必要的电话......就像乒乓球一样。

最好将init()定义为private,因为它的唯一SubClass-Code并且不应该从类外部访问。 您不需要接口来确保存在私有init()方法。 如果你在构造函数中调用它并且它不存在它就不会编译 - 与接口相同的行为。如果另一个单独的SubClass不需要init(),则不要调用/定义它或将其留空。简单,对吧? ^^

接口应该只保证PUBLIC功能可用于其他编码器。没有人需要了解私人职能。在类中编写干净统一的代码是您自己的责任。私人方法总是可选地在每个单独的类中。

假设您希望使用接口(公共方法)初始化您的各个SubClasses - 例如setSize(x,y)方法。

public interface IBase
{
    function setSize(x:int, y:int):void
}

[abstract] public class Base
{
    private var _x:int;
    private var _y:int;

    public function Base()
    {
        if(!(this is IBase))
        {
            throw new ArgumentError("Class " + flash.utils.getQualifiedClassName(this) + " can not be instantiated.");
        }
    }

    protected function init():void
    {
        // global init functions...
    }

    protected function setSize(x:int, y:int):void
    {
        this._x = x;
        this._y = y;
    }
}

在构造函数中,您可以检查" this" (SubClass)实现IBase接口。 所以没有人可以直接实例化BaseClass。就像一个抽象类。 顺便说一下:[摘要] MetaTag什么都不做。它只是为了更好地理解课程。 ;)

所有其他功能都受到保护。它们只能从SubClass访问 - 它们无法从外部访问。 接口无法识别setSize()函数,因为它受保护,而不是公共!

public class Sub extends Base implements IBase
{
    public function Sub()
    {
        // You don't need to define an empty super(). The compiler will do it for you automatically. 
        // It's only necassary, if you want to pass parameters to the BaseClass.
        // The Base-Constructor fires always before Sub() and init()
        init(); 
    }

    // Its private and save. Only this class can call this individual init().
    private function init():void
    {
        // init something
        super.init(); // optionally call the protected [Base].init()
    }

    // Its public and necessary, because its defined in the Interface
    public function setSize(x:int, y:int):void
    {
        // Do something before
        super.setSize(x, y);
        // Do something after
        // or do something special in the SubClass
    }
}

现在,您必须在接口中定义的SubClasses中设置公共函数。没有覆盖! 我们只是调用Base函数。您可以在此公共函数中执行任何操作,并可以通过super.setSize(x,y)调用BaseClass中的受保护函数。

没有人可以从外部访问私有init() - 这有利于防止双重入侵。但是每个人都可以从外部调用setSize(),并且每个SubClass都必须通过接口实现这一点 - 这就是你想要的。 BaseClass中同名的受保护函数是无关紧要的 - 它们也可以有其他名称 - 它只是用于统一。

如果您没有定义单独的私有init()函数,它会因受保护的行为而自动调用Base.init()。

你知道构造函数的用途吗?是的,初始化!为什么不在SubClass-Constructor中编写单独的init-code并删除额外的init-Function? ;)