Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Перечисляемый тип на AS3 (http://www.flasher.ru/forum/showthread.php?t=206336)

Фенёк 28.01.2014 19:48

Перечисляемый тип на AS3
 
Вечер добрый, господа соратники.

Давеча загадали мне загадку: необходимо написать на AS3 перечисляемый тип. Реализовать используя классы Enumeration, IntEnumeration, UintEnumeration, StringEnumeration, которые так же полагается реализовать самостоятельно. Ну и приведены примеры использования

Код AS3:

        public class UnitType extends UintEnumeration
        {
                public static const HERO:UnitType      = new UnitType(1);
                public static const WARRIOR:UnitType = new UnitType(2);
                public static const MAGE:UnitType      = new UnitType(3);
 
                public static const ENEMY:UnitType    = new UnitType(4);
 
 
 
                public function UnitType(val:uint)
                {
                        value = val;
                }
        }

Код AS3:

        public class UnitUpgradeType extends StringEnumeration
        {
                public static const U1:UnitUpgradeType = new UnitUpgradeType("U1");
                public static const U2:UnitUpgradeType = new UnitUpgradeType("U2");
                public static const U3:UnitUpgradeType = new UnitUpgradeType("U3");
                public static const U3:UnitUpgradeType = new UnitUpgradeType("U4");
 
 
 
                public function UnitUpgradeType(val:String)
                {
                        value = val;
                }
        }

Модифицировать приведенные в использовании классы запрещается.

Я прочел некоторое количество статей по реализации этого паттерна, но в условия задачи он не уложился. А не уложился он потому, что при невозможности модифицировать класс, необходимо было реализовать метод etElementsList(enumerationClass:Class):Vector.<Enumeration> который должен был отдавать все значения перечисления.

Насчет задачи вывода значений перечисления меня посетила только одна мысль: ведь любой класс, это на самом деле объект класса Class и по идее должна быть возможность просмотреть его свойства, ведь задавая статические константы мы задаем константы для объекта-класса.

то есть например
Код AS3:

                for (var property:String in SomeClass)
                {
                    trace(property)
                }

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

Так же я не вижу возможности закрыть эти классы так, чтобы из-вне невозможно было бы создавать их экземпляры, поскольку статические инициализаторы не наследуются, равно как и вложенные классы.

Вобщем у меня два вопроса, в связи с моим провалом:

1) Есть ли возможность при таких условиях добраться-таки до всех значений статических констант?
2) Есть ли возможность при таких условиях закрыть классы для создания экземпляров извне?

expl 28.01.2014 20:34

Цитата:

1) Есть ли возможность при таких условиях добраться-таки до всех значений статических констант?
Узнать тип объекта: getQualifiedClassName(this) (http://www.flasher.ru/forum/showthread.php?t=132772;
Получить список полей можно при помощи методов: getDefinitionByName, describeType

Только зачем вам этот список полей? Ведь в приведённом вами коде нет примеров где он нужен,
а чтобы эти примеры компилировались достаточно просто написать:

Код AS3:

public class UintEnumeration
{
    public uint value;
}
 
public class StringEnumeration
{
    public string value;
}

Т.е. чего-то не договариваете вы - примеров использования UnitType нет.
Как тогда понять какой функционал надо запихнуть в UintEnumeration?

Цитата:

2) Есть ли возможность при таких условиях закрыть классы для создания экземпляров извне?
Отличить создание и присвоение статическому полю от всех остальных созданий? Только каким-нибудь злым колдунством.

Akopalipsis 28.01.2014 21:00

Вот только если Вы хотите узнать о статических свойствах класса, то describeType не поможет, он их не видит.

silin 28.01.2014 21:27

describeType нормально видит статические константы
насчет закрыть классы для создания экземпляров извне при таких условиях - действительно непонятно о каких условиях речь, "Модифицировать приведенные в использовании классы запрещается" или что?

СлаваRa 28.01.2014 21:29

@Akopalipsis, вы не правы, describeType работает и показывает статику если в качестве аргумента методу будет передан класс, если же необходимо работать с объектом, то можно сделать так:
Код AS3:

describeType(this["constructor"])

Добавлено через 7 минут
А еще можно вот тут почитать http://www.flasher.ru/forum/blog.php?b=131

Akopalipsis 28.01.2014 22:11

Да, ошибся, я вот как пробовал -
Код AS3:

package 
{
        public class StorageClass
        {
                public static const STATIC_PROP:TestClass = new TestClass();
        }
}

Код AS3:

package 
{
        import flash.display.Sprite;
        import flash.utils.describeType;
 
        public class Main extends Sprite
        {
                public function Main()
                {
                        var storageClass:StorageClass = new StorageClass();
                        trace(describeType(StorageClass));//так видит, а вот если ссылку передать, то нет
                }
 
        }
}


dimarik 28.01.2014 23:38

Код AS3:

public class Enumeration {
    public function Enumeration(id:*) {
        this.id = id;
    }
 
    public var id:*;
 
    public function etElementsList(/*enumerationClass:Class этот параметр, к.м.к., не имеет смысла */):Vector.<Enumeration> {
        return null;
    }
 
    public function toString():String {
        return this.id.toString();
    }
}
 
public class UintEnumeration extends Enumeration {
    public function UintEnumeration(id:uint) {
        super(id);
    }
}
 
public class UnitType extends UintEnumeration {
    public static const HERO:      UnitType = new UnitType(1);
    public static const WARRIOR:  UnitType = new UnitType(2);
    public static const MAGE:      UnitType = new UnitType(3);
    public static const ENEMY:    UnitType = new UnitType(4);
 
    private static const _elementsList:Vector.<Enumeration> = new <Enumeration>[HERO, WARRIOR, MAGE, ENEMY];
 
    public function UnitType(id:uint) {
        super(id);
    }
 
    public override function etElementsList(/*enumerationClass:Class*/):Vector.<Enumeration> {
        return _elementsList.slice();
    }
 
}


Фенёк 29.01.2014 01:17

Ого, оперативно вы )

Насчет describeType большое спасибо, это очень помогло. Я уж было думал, что все это можно сделать если только каким-нибудь безумно грязным хаком, а тут оказывается есть готовая утилитка.

Сегодня-завтра накидаю демку того, что хотелось бы получить в результате, чтобы исключить неоднозначности в вопросах, а то пост писал несколько второпях, уходя с работы. Больше так не буду )

djyamato 29.01.2014 10:06

интересная тема, спасибо всем

Фенёк 29.01.2014 11:50

Итак, поехали.

Для начала приведу исходый текст задания, может быть я чего-то не допонял:

Цитата:

Написать на ActionScript перечисляемый тип и объяснить, почему это хорошо.
Реализуется классами Enumeration, IntEnumeration, UintEnumeration, StringEnumeration.

Использование.

public class UnitType extends UintEnumeration
{
public static const HERO:UnitType = new UnitType(1);
public static const WARRIOR:UnitType = new UnitType(2);
public static const MAGE:UnitType = new UnitType(3);

public static const ENEMY:UnitType = new UnitType(4);



public function UnitType(val:uint)
{
value = val;
}
}

public class UnitUpgradeType extends StringEnumeration
{
public static const U1:UnitUpgradeType = new UnitUpgradeType("U1");
public static const U2:UnitUpgradeType = new UnitUpgradeType("U2");
public static const U3:UnitUpgradeType = new UnitUpgradeType("U3");
public static const U3:UnitUpgradeType = new UnitUpgradeType("U4");



public function UnitUpgradeType(val:String)
{
value = val;
}
}

Ничего больше в классах UnitType и UnitUpgradeType быть не должно (иначе задание теряет смысл).
Все значения перечисляемого типа могут быть объявлены его статическими константами и только ими. Если это не так - проект падает сразу после компиляции или содержит варнинги.
Есть метод function getElementsList(enumerationClass:Class):Vector.<Enumeration> - отдает все значения перечисления.
Есть метод getElementByValue(value:*, enumClass:Class):Enumeration - отдает элемент перечисления по значению.

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

Для чего такая длинная цепочка наследования классов(Enumeration, UintEnumeration, StringEnumeration), я так и не понял, поскольку условиями задачи запрещается даже вызывать конструктор суперкласса в UnitType и UnitUpgradeType. Из-за чего иерархия классов в моем представлении сложлась следующим, весьма нелепым, образом:

класс Enumeration:
Код AS3:

 
    public class Enumeration
    {
        protected var _value:*;
 
        public function Enumeration()
        {
 
        }
 
        public function get value():*
        {
            return _value;
        }
 
    }

класс UintEnumeration:
Код AS3:

    public class UintEnumeration extends Enumeration
    {
 
        public function UintEnumeration()
        {
 
        }
 
    }

Класс StringEnumeration
Код AS3:

    public class StringEnumeration extends Enumeration
    {
 
        public function StringEnumeration()
        {
 
        }
 
    }

То есть по факту, классы наследники мне пришлось оставить пустыми, потому как больше ничего поделать я с ними не могу.

Кстати, попутно еще один вопрос: могу ли я в классах наследниках переписать так метод get value() чтобы он возвращал значения другого типа? Так как в данной ситуации, это могла быть единственная польза принесенная таким наследованием.

Далее. Я так понял что методы getElementsList(enumerationClass:Class):Vector.<Enumeration> и getElementByValue(value:*, enumClass:Class):Enumeration это методы, напрмер, объекта Main. В этом случае передаваемй параметр все таки имеет существенное значение.

expl 29.01.2014 14:21

Цитата:

То есть по факту, классы наследники мне пришлось оставить пустыми, потому как больше ничего поделать я с ними не могу.
Может они хотят что-то типа такого (хотя не факт):

Код AS3:

public class Enumeration
    {
        public function Enumeration()
        {
 
        }
 
        private var _commonValue:*;
        public function get commonValue():*// Это для обобщенных алгоритмов над всеми перечислениями
        {
            return _commonValue;
        }
 
    }
 
 public class UintEnumeration extends Enumeration
    {
 
        public function UintEnumeration()
        {
 
        }
 
        private var _value:uint;
        public function set value(value:uint):uint
        {
            _value = value;
            _commonValue = value;
        }
        public function get value():uint
        {
            return _value;
        }
    }

Цитата:

могу ли я в классах наследниках переписать так метод get value() чтобы он возвращал значения другого типа? Так как в данной ситуации, это могла быть единственная польза принесенная таким наследованием.
Пользу тут вообще искать сложно, они это, видимо, чисто ради примера сделали
На практике такой стиль не подводил(без всяких базовых классов - они практически бесполезны и с забиванием большого гвоздя на проверки создания не в том месте - они не от чего не защищают):
Код AS3:

public class UnitType
{
    // Список всех значений (не всегда нужен, кстати)
    public static const allUnits:Vector.<Unit> = new Vector.<Unit>();
 
    public static const Unit1:UnitType = new UnitType(1);
    public static const Unit1:UnitType = new UnitType(2);
    public static const Unit1:UnitType = new UnitType(3);
 
    private var _code:uint;
    public function get code():uint
    {
        return _code;
    }
 
    public function UnitType(code:uint)
    {
        _code = code;
        allUnits.Add(this);// заполнение списка
    }
}

А громоздить сюда рефлексию - это лишние проблемы при дебаге и никакой пользы

Akopalipsis 29.01.2014 14:47

Вчера не спрашивал, потому что думал, пойму. Но нет, я и статью прочёл и код смотрел сто раз.
Объясните на простом языке, для чего это.

silin 29.01.2014 15:13

если честно, не совсем понял в чем проблема
вот такой вариант, например
Код AS3:

package
{
        import flash.display.Sprite;
 
        public class Main extends Sprite
        {
 
                public function Main():void
                {
 
                        var list:Vector.<Enumeration> = Enumeration.getElementsList(UnitType);
                        trace("list : " + list);
                        var element:Enumeration = Enumeration.getElementByValue(1, UnitType);
                        trace("element : " + element);
                        var isHero:Boolean = (element === UnitType.HERO);
                        trace("isHero : " + isHero);
                }
 
        }
 
}
 
//=================================//
import flash.utils.describeType;
 
class Enumeration
{
        public var value:*;
 
        public function Enumeration(value:*)
        {
                this.value = value;
        }
 
        public static function getElementsList(enumClass:Class):Vector.<Enumeration>
        {
                var list:Vector.<Enumeration> = new Vector.<Enumeration>();
                var constList:XMLList = describeType(enumClass).constant;
 
                for each (var item:XML in constList)
                {
                        list.push(enumClass[item.@name])
                }
 
                return list;
 
        }
 
        public static function getElementByValue(value:*, enumClass:Class):Enumeration
        {
                var constList:XMLList = describeType(enumClass).constant;
 
                for each (var item:XML in constList)
                {
                        if (enumClass[item.@name].value == value)
                                return enumClass[item.@name];
                }
 
                return null;
        }
}
 
//=================================//
class UintEnumeration extends Enumeration
{
 
        public function UintEnumeration(value:uint)
        {
                super(value);
 
        }
 
}
 
//=================================//
class UnitType extends UintEnumeration
{
 
        public static const HERO:UnitType = new UnitType(1);
        public static const WARRIOR:UnitType = new UnitType(2);
 
        public function UnitType(value:uint)
        {
                super(value);
 
        }
 
}


Фенёк 29.01.2014 15:56

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

Akopalipsis, Для чего что именно? Реализация перечислений? Об этом я писал несколько выше:
Цитата:

делаем код более читаемым, избавляясь от магических чисел, плюс ко всему мы имеем возможность иметь дело с этими значениями как с типом, что позволяет внести дополнительную конкретизацию при, например, описании методов.
Если вопрос в том зачем такая реализация, то тут уже я сильно затрудняюсь вам как-то это прокомментировать. Люди составлявшие задание по всей видимости пытались сделать сделать из него загадку, мол «вот вам странные условия задачи, попробуйте используя их дать нам ответ, какой мы хотим увидеть. Попытайтесь использовать нашу логику». Признаться честно глядя на все это мне кажется что такой способ можно охарактеризовать только одним словом - ИЗВРАТ.

silin, Если честно, мне кажется, что проблема на деле в странно поставленной задаче. Сам запутался и вас запутал. В общем на деле пожалуй ваш вариант наиболее приближен к тому, что как я понял от меня хотели. Сформирую свой вариант и, если будет какой-то ответ по заданию, расскажу, что же там была за черная магия в описании.

Вобщем всем спасибо, вы мне очень помогли )

Akopalipsis 15.02.2014 15:51

Хочется полюбопытствовать, в конструкторах классов присутствует параметр id, так вот он для того, чтобы в каком-нибудь особом случаи сравнивать по нему? Типа -
Код AS3:

...
public static const HERO:UnitType = new UnitType(1);
...
public static const HERO:uint = 0x000000;
...
if(HERO.id == HERO){...}

Правильно я понял?

silin 15.02.2014 16:42

>>Правильно я понял?
все правильно, в особых случаях параметр id можно использовать для сравнения в операторе if

Akopalipsis 16.02.2014 07:25

Немного не по теме - а при помощи describeType можно только public свойства увидеть?
Почему-то мне кажется, что можно и к остальным обращаться-считать, но у меня не получается и мне уже кажется, что я что-то напутал.

silin 16.02.2014 12:03

да, при помощи describeType можно только public свойства увидеть

Akopalipsis 16.02.2014 13:58

silin Спасибо! Ужас.

taluks 20.09.2016 01:54

если кому еще интересно то выглядеть должно так так

caseyryan 20.09.2016 06:43

Цитата:

Сообщение от taluks (Сообщение 1196246)
если кому еще интересно то выглядеть должно так так

Это все равно не ENUM. Тут, по сути, просто замена примитивных типов ссылочными, и не более.

taluks 20.09.2016 15:18

Цитата:

Сообщение от caseyryan (Сообщение 1196248)
Это все равно не ENUM. Тут, по сути, просто замена примитивных типов ссылочными, и не более.

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

dimarik 21.09.2016 20:12

Код AS3:

var classConstructor:Class = this["constructor"];
...
/*
Вместо
var className:String = getQualifiedClassName(this);
if (className == getQualifiedClassName(Enumeration))
    throw new ArgumentError("Enumeration class cannot be instantiated.");
*/

 
// Можно прост:
if (classConstructor == Enumeration) {
    throw new ArgumentError("Enumeration class cannot be instantiated.");
}

Так, накатило прост.

caseyryan 21.09.2016 20:33

Цитата:

Сообщение от dimarik (Сообщение 1196287)
Код AS3:

var classConstructor:Class = this["constructor"];
...
/*
Вместо
var className:String = getQualifiedClassName(this);
if (className == getQualifiedClassName(Enumeration))
    throw new ArgumentError("Enumeration class cannot be instantiated.");
*/

 
// Можно прост:
if (classConstructor == Enumeration) {
    throw new ArgumentError("Enumeration class cannot be instantiated.");
}

Так, накатило прост.

А если еще проще
Код AS3:

if (this is Enumeration) {
    throw new ArgumentError("Enumeration class cannot be instantiated.");
}

?

dimarik 21.09.2016 20:35

не, так не катит. исправляйся )

И еще я стринги во флеше не люблю. Лучше так

Код AS3:

var ctor:Class = (this as Object).constructor;


taluks 22.09.2016 22:46

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

RAlfDog 27.08.2017 00:37

А что будет, если где-нибудь я сделаю так:
Код AS3:

UnitType.HERO.value = 4;

или
Код AS3:

UnitType.HERO.value = 5;

Добавлено через 27 минут
и вот здесь вот:
Код AS3:

if(vectorEnumeration[i].value == value)

мне кажется лучше делать так:
Код AS3:

if(vectorEnumeration[i].value === value)

Добавлено через 49 часов 31 минуту
В целом идея отличная, очень нужная :) Спасибо автору за тему!
Нужно только немного улучшить:
- не давать напрямую создавать экземпляры UnitType (все возможные значения должны быть объявлены только статически)
- сделать IntEnumeration, UintEnumeration, StringEnumeration абстрактными
- в Enumeration проверку на абстракцию вынести перед проверкой наличия в словаре списка экземпляров класса


Часовой пояс GMT +4, время: 12:23.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.