2

私は潜在的に不可能な欲求を持っています。私はいくつかのサブクラスを構築したいクラスを持っています。各サブクラスは同じインターフェイスを実装しますが、BASE クラスがそのインターフェイスのメソッドを呼び出すようにしたいと考えています。

これが私が欲しいもののコンパイラエラーyバージョンです:

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のバージョン(問題のメソッドをオーバーライドする)がREQUIREになるかです。サブクラスによってオーバーライドされる initialize() ?

4

4 に答える 4

3

私があなたの質問を正しく解釈した場合、直接でClass1はなく、のサブクラスに実装されたインターフェイスが必要です。また、サブクラス化したときに自動的に呼び出されるように、Class1から Interface 内のメソッドを呼び出せるようにする必要があります。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!');
    }

}

のインスタンスを作成してテストすると、期待どおりに出力パネルに表示されますSubSuccess!

于 2013-01-23T22:22:37.350 に答える
0

基本クラスでインターフェイスを拡張します。そして、サブクラスは基本メソッドをオーバーライドします。これにより、ベースからメソッドを呼び出すことができます。

于 2013-01-23T21:43:19.670 に答える
0

古いトピックですが、私の考えを投稿します。super() を呼び出してから init() へのコールバックを行うのは意味がありません。不要な電話は... ピンポンのようなものです。

固有の SubClass-Code であり、クラスの外部からアクセスできないため、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 を直接インスタンス化することはできません。抽象クラスのように。ところで: [abstract] 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() にアクセスすることはできません。これは、二重の init を防ぐのに適しています。しかし、誰もが外部から setSize() を呼び出すことができ、すべてのサブクラスはインターフェイスのためにこれを実装する必要がありました-それはあなたが望むものです。BaseClass 内の同じ名前の保護関数は無関係です - それらは他の名前を持つこともできます - 統一のためだけです。

個々のプライベート init() 関数を定義しない場合、保護された動作により Base.init() が自動的に呼び出されます。

そして、コンストラクターの目的を知っていますか? はい、初期化!SubClass-Constructor に個々の init-code を記述して、追加の init-Function を削除しないのはなぜですか? ;)

于 2016-03-10T10:43:01.357 に答える
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 に答える