2

我有一个潜在的不可能的愿望。我有一个类,我想从中构建几个子类。每个子类都将实现相同的接口,但我有点希望 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()方法要求,而且我不知道我可以强制每个子类覆盖该方法。当然,我可以省略基类中的调用并将其插入到每个子类中,但我也不能强制要求拥有它。

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

4

4 回答 4

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!在输出面板中注意到预期的结果。

于 2013-01-23T22:22:37.350 回答
0

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

于 2013-01-23T21:43:19.670 回答
0

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

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

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

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

于 2013-01-23T22:19:42.250 回答
0

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

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

接口应该只保证 PUBLIC 函数可用于其他编码器。没有人需要知道私有函数。在类中编写干净统一的代码是您自己的责任。私有方法始终在每个单独的类中是可选的。

假设您想使用(公共方法的)接口初始化您的各个子类 - 例如 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”(子类)是否实现了 IBase 接口。所以没有人可以直接实例化 BaseClass。就像一个抽象类。顺便说一句:[抽象] MetaTag 什么都不做。只是为了更好地理解课程。;)

所有其他功能都受到保护。它们只能从子类访问——它们不能从外部访问。接口无法识别 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
    }
}

现在您必须在您的接口中定义的子类中设置公共函数。没有覆盖!我们只是调用 Base 函数。你可以在这个公共函数中做任何你想做的事情,并且可以通过 super.setSize(x,y) 调用 BaseClass 中的受保护函数。

没有人可以从外部访问私有 init() - 这对防止双重初始化很有好处。但是每个人都可以从外部调用 setSize() 并且每个子类都必须通过接口来实现这一点——这就是你想要的。BaseClass 中同名的受保护函数是无关紧要的——它们也可以有其他名称——它只是为了统一。

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

你知道构造函数是干什么用的吗?是的,初始化!为什么你不只是在你的子类构造器中编写你自己的初始化代码并摆脱额外的初始化函数?;)

于 2016-03-10T10:43:01.357 回答