AS3: две функции с одинаковым именем, но несовместимыми сигнатурами из двух интерфейсов - PullRequest
3 голосов
/ 03 февраля 2012

У меня есть два интерфейса, которые объявляют функции с тем же именем, но несовместимыми сигнатурами:

interface IDog 
{
    function bark() : void;
}

interface IAdvancedDog
{
    function bark(volume : Number) : void;
}

Мне нужно реализовать оба в одном классе, что-то вроде следующего:

class AlphaDog implements IDog, IAdvancedDog
{
     public function bark() : void
     {
     }

     public function bark(volume : Number) : void
     {
     }
}

Это, конечно, не работает. Есть ли способ устранить неоднозначность функций bark () в этом случае? C #, например, допускает явный маркер интерфейса:

   class AlphaDog : IDog, IAdvancedDog
   {
       // ...
       void IDog.bark() { } 
   }

Хотя это не требуется в C # из-за правил перегрузки функций. В AS3 нет перегрузки, есть ли другой способ решить эту проблему?

UPDATE.

1) Отсутствие общедоступных классификаторов в определении класса было опечаткой. Я починил это.

2) Я пропустил дополнительное требование, чтобы интерфейсы НЕ могли быть изменены (для целей этого вопроса). В реальном проекте они определены в двух разных библиотеках, которые являются частью большого проекта. Несколько классов реализуют оба интерфейса (отдельно). Таким образом, любые изменения интерфейсов потребуют каскадного обновления всех этих классов, перекомпиляции, тестирования и т. Д. Итак, я сначала хотел выяснить, было ли решение без таких навязчивых модификаций. Кажется, что нет.

Ответы [ 2 ]

5 голосов
/ 03 февраля 2012

ActionScript 3 не поддерживает перегрузку функций, как это. Плюс тот факт, что вы не определили, если функции как общедоступные, вы получите ошибки компиляции.

В вашем случае вы можете добавить значение по умолчанию NaN и иметь только один интерфейс.

package{
  public class AlphaDog implements IDog
    {
         public function bark(volume : Number = NaN) : void
         {
         }
    }
}


package{
    interface IDog
    {
        function bark(volume : Number = NaN) : void;
    }
}
0 голосов
/ 03 февраля 2012

Ответ The_asMan, я думаю, является более или менее лучшим ответом, а также правильным ответом на этот вопрос. Мой ответ - это скорее альтернативный подход, который может быть тщательно изучен, но я думаю, что его стоит опубликовать (не обижайте меня слишком плохо :().

Вы можете определить объем не как параметр для метода bark(), а как свойство в вашем интерфейсе. Здесь вы говорите «но вы не можете определить свойство в интерфейсе -_-», что верно, так что вы можете использовать следующие лучшие определения, методы получения и установки метода. Вот пример, который я сделал:

    package 
    {
        import flash.display.Sprite;
        import flash.events.Event;

        public class Main extends Sprite 
        {

            public function Main():void 
            {
                if (stage) init();
                else addEventListener(Event.ADDED_TO_STAGE, init);
            }

            private function init(e:Event = null):void 
            {
                removeEventListener(Event.ADDED_TO_STAGE, init);

                var strayDog:IDog = new StrayDog();
                var alphaDog:IDog = new AlphaDog();

                strayDog.bark(); // output: Bark!
                alphaDog.bark(); // output: Bark!

                (alphaDog as IAdvancedDog).volume = 1; // output: set volume to 1

                alphaDog.bark(); // output: Bark!!!

            }// end function

        }// end class

    }// end package

    internal interface IDog
    {
        function bark():void

    }// end interface

    internal interface IAdvancedDog extends IDog
    {
        function get volume():Number
        function set volume(value:Number):void

    }// end interface

    internal class StrayDog implements IDog
    {
        public function StrayDog() {}

        public function bark():void
        {
            trace("Bark!");

        }// end function

    }// end class

    internal class AlphaDog implements IAdvancedDog
    {
        private var _volume:Number = 0.5;

        public function AlphaDog() {}

        public function get volume():Number
        {
            return _volume;

        }// end function

        public function set volume(value:Number):void
        {
            if (value <0 || value > 1) 
            throw new Error("Error: Volume must be between 0 and 1.");

            trace("setting volume to " + value);

            _volume = value;

        }// end function

        public function bark():void
        {
            if (volume <= 0) trace("...")
            else if (volume > 0 && volume <= 0.5) trace("Bark!")
            else if (volume > 0.5) trace("BARK!!!");

        }// end function

    }// end class

Это просто идея, но я бы согласился с ответом The_asMan, этот может быть неправильным.

[UPDATE]

Другой подход:

package 
{
    import flash.display.GraphicsGradientFill;
    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite 
    {
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);

        }// end function

        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            var strayDog:IDog = new StrayDog();
            var alphaDog:IDog = new AlphaDog();
            var supremeDog:IDog = new SupremeDog();

            strayDog.bark(); // output: Bark!
            alphaDog.bark(); // output: Bark!
            alphaDog.bark( { volume : 1 } ); // output: BARK!!!
            supremeDog.bark(); // output: Bark!
            supremeDog.bark( { volume : 1 } ); // output: BARK!!!
            supremeDog.bark( { length : 3 } ); // output: Baaark!

        }// end function

    }// end class

}// end package

internal interface IDog
{
    function bark(args:Object = null):Boolean

}// end interface

internal class StrayDog implements IDog
{
    public function StrayDog() {}

    public function bark(args:Object = null):Boolean
    {
        var barked:Boolean = true;

        if (!args) trace("Bark!");
        else  barked = false;

        return barked;

    }// end function

}// end class

internal class AlphaDog extends StrayDog
{
    public function AlphaDog() {}

    override public function bark(args:Object = null):Boolean
    {
        var barked:Boolean = true;

        if (!super.bark(args))
        {
            if (args.volume)
            {
                if (args.volume <= 0) trace("...")
                else if (args.volume > 0 && args.volume <= 0.5) trace("Bark!")
                else if (args.volume > 0.5) trace("BARK!!!");
                else throw new ArgumentError("volume must be between 0 and 1");

            }
            else 
            {
                barked = false;

            }// end if

        }// end if

        return barked;

    }// end function

}// end class

internal class SupremeDog extends AlphaDog
{
    public function SupremeDog() {}

    override public function bark(args:Object = null):Boolean
    {
        var barked:Boolean = true;

        if (!super.bark(args))
        {
            if (args.length)
            {
                if (args.length == 1) trace("Bark!")
                else if (args.length == 2) trace("Baark!")
                else if (args.length == 3) trace("Baaark!");
                else throw new ArgumentError("length must be either 1, 2 or 3");
            }
            else 
            {
                barked = false;

            }// end if

        }// end if

        return barked;

    }// end function

}// end class
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...