Приведение подкласса к родительской переменной as3

Я вызываю классы разных типов из цикла. Объекты могут быть разных типов, поэтому я использую метод getDefinitionByName. вот кусок моего кода:

for(var y = 0; y < mapH; y++)
            {
                brickHolder[y] = new Array();
                for(var x = 0; x < mapW; x++)
                {
                    var classRef = getDefinitionByName('com.objects.Brick2') as Class;
                    var brick:Brick2 = Brick2(new classRef());
                    brick.name = x+""+y;
                    brick.getBall(ball);
                    brick.getEngine(this);
                    brick.x = x * brick.bWidth + brick.bWidth;
                    brick.y = y * brick.bHeight + 100;
                    numberOfBricks += 1;
                    addChild(brick);

                }
            }

Единственная проблема в том, что я должен привести этот объект к определенной переменной:

var brick:Brick2 = Brick2(new classRef());

Я думал об использовании интерфейса и его приведении следующим образом:

var brick:IBrick = IBrick(new classRef());

Но я получил ошибку, когда попытался вызвать методы. Интерфейс пустой; не имеет в нем никаких методов. Я не уверен, что это имеет значение. Но родительский класс наследует его, а подклассы наследуют родительский класс. Могу ли я вместо этого использовать родительский класс?

var brick:ParentBrick2 = ParentBrick2(new classRef());

В двух словах, что я могу сделать, чтобы свободно преобразовать эти объекты, чтобы я мог использовать любые вызываемые методы подкласса?


person numerical25    schedule 07.01.2010    source источник


Ответы (4)


Лучший способ — использовать интерфейс и определить все общие методы, которые вы будете использовать в интерфейсе. Это гарантирует, что все реализации имеют правильные методы с правильными сигнатурами и обеспечивают безопасность типов везде, кроме отражения, где вы получаете класс по имени.

Очень плохой способ, который сработает, - это ввести кирпич как «Объект» или «*», что позволит вам вызывать любой метод, который вы хотите, и выдаст вам ошибку только во время выполнения, а не во время компиляции, если метод не работает. существует. Это плохой хак, которого вам следует избегать, если это возможно.

Вы также можете использовать методологию утиного ввода, когда вы вводите кирпич как «Объект», но вызываете методы только в том случае, если подтверждаете, что они действительно существуют.

var brick:Object = new classRef();
if ("getBall" in brick)
    brick.getBall();

Не дает вам никакой безопасности типа во время компиляции, но позволит избежать ошибок во время выполнения (при условии, что допустимо просто пропустить отсутствующие методы).

person Samuel Neff    schedule 07.01.2010
comment
хорошо, я попробовал объект, я получил ошибку. Но, как вы сказали, я не хочу использовать это. Я бы предпочел остаться объектно-ориентированным. что касается второго предложения. это отличная идея, но это не совсем то, что я ищу. родительский класс выполняет основную часть работы. Во всяком случае, я переопределяю методы родительского класса, чтобы делать что-то немного другое. - person numerical25; 07.01.2010

[ОБНОВЛЕНИЕ] после копания кажется, что ключевое слово virtual игнорируется компилятором, поэтому это не сработает. Еще один недостаток AS3 :(

Я думаю, что полиморфизм — это концепция, которую вы ищете. Я думаю, вы можете сделать это в AS3 (существует виртуальное ключевое слово).

http://msdn.microsoft.com/en-us/library/ms173152%28VS.80%29.aspx ‹ — примеры C#, но хорошо объясняющие идею.

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

Поэтому, если вы сделаете свои функции базового класса виртуальными, вы все равно сможете вызывать новые переопределенные функции подклассов, даже если экземпляр относится к типу базового класса.

person Allan    schedule 07.01.2010
comment
это именно то, что я ищу. за исключением того, что я получаю ошибки даже без вызова каких-либо методов. На данный момент я еще не добавил ключевое слово virtual в свои функции. но нужно ли мне это, когда я просто пытаюсь преобразовать свой подкласс в переменную родительского класса... Базовым классом является Brick(). подкласс - Brick2. Я сделал это -- var classRef = getDefinitionByName('com.objects.Brick2') as Class; вар кирпич: кирпич = кирпич (новый classRef ()); и я получил ошибку. ReferenceError: Ошибка № 1065: переменная Brick2 не определена. - person numerical25; 07.01.2010
comment
к сожалению, после того, как я покопался в ключевом слове virtual в AS3, на данный момент это не более чем заполнитель. Компилятор игнорирует это :(. Если вы приведете Brick2 к переменной типа Brick и вызовете переопределенную функцию, то она вызовет функцию Brick, а не функцию Brick2. Если бы виртуальные функции существовали, тогда можно было бы вызвать Brick2. переопределенная функция экземпляра Brick. - person Allan; 07.01.2010
comment
Попался. Так что на данный момент это, вероятно, просто для чего-то в будущем. Таким образом, AS3 не обязательно имеет настоящий полиморфизм. Конечно, есть интерфейсы, но они нужны только для того, чтобы поддерживать контракт между классами. На самом деле нет правдоподобного способа сделать классы свободных типов. из того, что я получил до сих пор. Боюсь, мне придется создать некую фабрику, которая будет содержать ряд операторов case в зависимости от типа предоставленного класса. - person numerical25; 07.01.2010
comment
Думать об этом. Даже это не сработает. Если бы я создал фабрику, возвращающую запрошенный класс, мне пришлось бы указать возвращаемое значение. что ограничило бы меня возвратом только одного типа данных. - person numerical25; 07.01.2010
comment
да, нет настоящего полиморфизма :( Мне также нужно сделать что-то подобное. Я думаю, возможно, вы могли бы вернуться, используя нетипизированный класс, и просто «знать», что вы можете его разыграть.. это может сработать, но да, не лучший результат - person Allan; 07.01.2010
comment
Хорошо, я читаю эту книгу под названием «Шаблоны проектирования Advance AS3». В нем говорится, что все классы, реализующие интерфейс, больше не привязаны к его конкретному типу. В нем также говорится, что подклассы в as3 могут быть преобразованы в родительскую переменную. если это так. почему у меня ошибки?!? Он ссылается на переменную с именем item, имеющую тип данных IProduce. это он говорит... - person numerical25; 07.01.2010
comment
Теперь, когда элемент объявлен как тип IProduce, мы можем присвоить элементу любой экземпляр любого класса, реализующего IProduce. Мы больше не привязаны к одному конкретному классу. Если и Fruit, и Vegetable реализуют IProduce, тогда вы можете назначить экземпляр любого класса элементу теперь, когда он типизирован как IProduce.... Он говорит это, но не упоминает процесс окончательного приведения типа к его собственному конкретному типу данных. , правильный ? - person numerical25; 07.01.2010
comment
бла, так это работает!. Это просто не работает с getDefinitionByName(). что, я думаю, противоречит цели getDefinitionByName(). Нет необходимости в его использовании, если вы можете использовать только 1 тип данных - person numerical25; 07.01.2010
comment
Лучше поздно, чем никогда, я ошибался насчет отсутствия полиморфизма. Я не уверен, как я пришел к неправильному выводу, но мой комментарий о Brick2 и т. д. неверен, происходит желаемый результат вызова функции Brick2 для базового типа. И раздел книги с Интерфейсом тоже тому подтверждение. Извини за это. - person Allan; 16.02.2010

Да, вы определенно должны иметь возможность использовать родительский класс, например:

var c:Car = new Mercedes();

Что касается случая интерфейса, вы должны вызывать только функции, определенные интерфейсом. И иметь пустой интерфейс вообще не имеет смысла.

Если я правильно помню свои причуды AS3, проверка имени метода и члена выполняется во время выполнения, и вы должны иметь возможность вызывать любую функцию в Object. Таким образом, вы также можете привести все к Object:

var brick:Object = new classRef(); //or cast to Object
brick.name = x + "" + y;
brick.getBall(ball);

Но используйте родительский тип, как в примере с автомобилем. Это правильный полиморфизм.

person aib    schedule 07.01.2010
comment
Я пробовал это. Это не работает. Базовым классом является Brick(). подкласс - Brick2. Я сделал это -- var classRef = getDefinitionByName('com.objects.Brick2') as Class; вар кирпич: кирпич = кирпич (новый classRef ()); и я получил ошибку. ReferenceError: Ошибка № 1065: переменная Brick2 не определена. - person numerical25; 07.01.2010
comment
Да, я понимаю, что не имеет особого смысла не иметь никаких методов в интерфейсе. но на данный момент я пытаюсь сделать что-нибудь, чтобы сделать мой класс свободным. так что я могу добавить любые подклассы в цикле. - person numerical25; 07.01.2010
comment
Но где вы имеете в виду «Brick2»? Сообщение об ошибке не имеет смысла. Вы пытались передать Class вместо использования getDefByName()? Вы пытались сделать Brick2 общедоступным и/или сделать определение Brick2 видимым во время вызова getDef...()? (т.е. можете ли вы сказать var x = new Brick2(); внутри цикла for?) - person aib; 07.01.2010
comment
да, или еще лучше. если я разыграю Brick2(); в переменную типа Brick2(), это работает, но не в том случае, если получающая переменная имеет тип Brick() - person numerical25; 07.01.2010
comment
ха-ха, хорошо, так что если инициировать Brick2() непосредственно к переменной типа Brick, это работает. Просто если вы используете getDefinitionByName() для получения этого класса, а затем установите его, это не сработает. что я считаю глупым, потому что в некотором смысле это противоречит цели использования метода getDefinitionByName(). Любой, кто его использует, 8/10, вероятно, вызывает несколько типов классов. но если вы уже знаете этот тип, зачем его использовать, если вы можете вызвать его напрямую. не поймите меня неправильно getDefinitionByName() работает. но вы должны сначала ввести его в метод. В котором вам лучше просто делать это напрямую. - person numerical25; 07.01.2010
comment
Я все еще думаю, что вы должны дать Class шанс: livedocs.adobe.com/flash/ 9.0/ActionScriptLangRefV3/Class.html - person aib; 07.01.2010
comment
Да, это хорошая идея. но он не динамический, потому что я не могу использовать строку, чтобы выбрать, какой класс я хочу. Мне пришлось бы создать фабрику, чтобы выбрать, какой класс получить на основе строки или числа. в этом случае мне было бы лучше просто объявить сам фактический класс. - person numerical25; 07.01.2010

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

person numerical25    schedule 07.01.2010