Проблема ООП: расширение класса, переопределение функций и jQuery-подобный синтаксис - PullRequest
3 голосов
/ 17 декабря 2010

У меня есть проблема, связанная с ООП, с Flash, actionscript 3. Это личный проект, и я ищу шаблон проектирования или обходной путь для этой проблемы, и моя цель - изучить новые вещи.

Iсоздали класс под названием Chain.Я создал этот класс утилит, чтобы упростить вызов отложенных функций.Вы можете создать цепочку функций, добавляя их с задержкой в ​​миллисекундах.Эта цепочка может быть выполнена несколько раз, даже в обратном порядке.Этот класс имеет функции, которые возвращают себя.Это позволяет использовать синтаксис в стиле jQuery, подобный следующему:

var chain:Chain = new Chain(); 
chain.wait(100).add(myFunction1,300).wait(300).add(myFunction2,100);
// etc..

Для примера я оставил множество функций просто для демонстрации проблемы.Класс Chain в основном предназначен для добавления функций и запуска / остановки цепочки.

public class Chain 
{  
 function wait(delay:int = 0):Chain
 {
   // do stuff
   return this;
 }

 public function add(func:Function, delay:Number = 0):Chain
 {
      list.push( new ChainItem(func, delay) );
      return this;
 }
}

Теперь у меня есть еще один класс, называемый ChainTween.Я пытаюсь разделить вещи, чтобы сохранить цепочку с некоторыми основными функциями и заставить ChainTween выполнять некоторые анимационные трюки.У меня была идея создать маленький двигатель на основе класса Chain.В настоящее время расширяется Цепь.Он использует множество защищенных переменных из класса Chain и переопределяет некоторые основные функции для Chain, чтобы добавить функции анимации в процесс Chain.

public class ChainTween extends Chain
{  
 function animate(properties:Object = null, duration:Number = 0, easing:Function = null):ChainTween
 {
   // do stuff
   return this;
 }
}

Теперь это проблема: я хочу сохранить цепочкусинтаксис, но wait () возвращает экземпляр Chain, а Chain не имеет анимационной функции.

var chain:ChainTween = new ChainTween();
chain.wait(100).animate({x:200}, 100).wait(250);

Я пытался переопределить функции wait () и add () в классе ChainTween, но это вызывает несовместимое переопределение.

Я мог бы разыграть chain.wait (100) как ChainTween, но это очень уродливо и бесполезно, когда я объединяю их в цепочку.Теперь я не хочу добавлять какие-либо функции ChainTween в Chain (также нет фиктивных функций), и я хочу сохранить завершение для всех функций, поэтому возвращать Object тоже нельзя.Я пытался использовать интерфейс, но это создает ту же проблему, поскольку функции интерфейса должны быть реализованы в классе, который его реализует.

Теперь я подумал о создании экземпляра Chain внутри ChainTween, ноэто не позволяет мне переопределять функции, и тогда я должен сделать множество свойств общедоступными вместо защищенных, что тоже не является предпочтительным.

Возможно ли это, и есть ли у кого-нибудь отличное решение для этого?

Ответы [ 6 ]

2 голосов
/ 17 декабря 2010

Эта проблема довольно распространена.Шаблон проектирования, который вы используете, называется Fluent Interface , и если вы используете Google «Fluent Interface Inheritance», вы найдете множество вопросов и очень мало ответов.

Распространенный способ решенияв C #, Java и C ++ должен использовать шаблоны .Однако я не могу сказать, как реализовать то же самое в AS3, я нашел эту тему , которая может вам помочь.

1 голос
/ 17 декабря 2010

Следуя структуре класса Chain, должна быть возможность (и как-то логично) использовать метод add для вызова метода animate ... Не зная больше о классе Chain, трудно быть более точным, но в Теория кажется возможной ... Это потребует добавления нового аргумента в метод add.

var chain:ChainTween = new ChainTween();
var params:Object = {x:200};
chain.wait(100).add(animate, 300 , params).wait(300);

У alxx есть смысл, может показаться, что что-то должно что-то давать, в отличие от Javascript, AS3 - это язык со строгой типизацией, это и есть причина ваших ограничений. Если вам нужно реализовать такие специфические методы, как rotate, fadeOut, у вас может быть не так много доступных решений. Эти методы либо возвращают ChainTween, Chain или Object, и вы отклоняете Object и * ...

Почему-то я все еще думаю, что добавление метода rotate, fadeOut или animate с помощью add () (или любого другого метода, который вы можете создать для этой цели) больше соответствует дизайну Chain.

1 голос
/ 17 декабря 2010

Если вы хотите, чтобы функция отображалась при завершении кода, она должна быть там. Это исключает любые методы обнаружения во время выполнения. Я бы добавил в цепочку что-то вроде этого:

public function animate(args:Object, time:int):Chain {
    throw new Error("Animate is supported only on ChainTween");
}

для переопределения в ChainTween. Не думайте, что это такой большой натяжение.

0 голосов
/ 17 декабря 2010

Я бы пошел за уже предложенную идею интерфейса. Wait возвращает что-то вроде IChainTween, которое содержит только методы для настройки ChainTween, а также функцию like, которая возвращает исходную цепочку.

package
{
    public interface IChainTween
    {
        function doSomething():IChainTween;
        ...
        function then():IChain;
    }
}

package
{
    public class ChainTween implements IChainTween
    {
        private originalChain:IChain;
        public function ChainTween(IChain chain)
        {
            originalChain = chain;
        }
        ...
        public function doSomething():IChainTween
        {
            return this;
        }
        public function then():IChain
        {
            return originalChain;
        }
    }
}
0 голосов
/ 17 декабря 2010

на вашем месте я создал бы интерфейс IChain, описывающий только основные функции (add, wait и т. Д.)

0 голосов
/ 17 декабря 2010

Вы можете попытаться вернуть * вместо Цепочки, но это удаляет подсказки кода.

...