Как разделить массив между всеми классами в приложении? - PullRequest
2 голосов
/ 27 августа 2011

Я хочу поделиться массивом, который все классы могут «получать» и «изменять» данные внутри этого массива. Что-то вроде глобального массива или массива множественного доступа. Как это возможно с ActionScript 3.0?

Ответы [ 3 ]

6 голосов
/ 27 августа 2011

Есть несколько способов решить эту проблему.Одним из них является использование глобальной переменной (как предложено в ответе unkiwii), но это не очень распространенный подход в ActionScript.Более распространенные подходы:

Переменная класса (статическая переменная)

Создайте класс с именем DataModel или аналогичный и определите переменную массива для этого класса как статическую:

public class DataModel {
    public static var myArray : Array = [];
}

Затем вы можете получить к нему доступ из любой части вашего приложения, используя DataModel.myArray.Это редко является отличным решением, поскольку (как и глобальные переменные) одна часть вашего приложения не может узнать, когда содержимое массива изменено другой частью приложения.Это означает, что даже если ваш GUI ввода данных добавляет объект в массив, ваш GUI списка данных не будет знать, как отобразить новые данные, если вы не реализуете другой способ заставить их перерисовать.

Синглтонный оберточный массив

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

public class ArraySingleton {
    private var _array : Array;

    private static var _instance : ArraySingleton;


    public static function get INSTANCE() : ArraySingleton {
        if (!_instance)
            _instance = new ArraySingleton();

        return _instance;
    }


    public function ArraySingleton() {
        _array = [];
    }


    public function get length() : uint {
        return _array.length;
    }

    public function push(object : *) : void {
        _array.push(object);
    }

    public function itemAt(idx : uint) : * {
        return _array[idx];
    }
}

Этот класс оборачивает массив, и один экземпляр может быть доступен через ArraySingleton.INSTANCE.Это означает, что вы можете сделать:

var arr : ArraySingleton = ArraySingleton.INSTANCE;
arr.push('a');
arr.push('b');
trace(arr.length); // traces '2'
trace(arr.itemAt(0)); // trace 'a'

Большим преимуществом этого является то, что вы можете отправлять события, когда элементы добавляются или когда массив модифицируется любым другим способом, так что все части вашего приложения могутполучать уведомления о таких изменениях.Вы, вероятно, захотите расширить приведенный выше пример, реализовав больше интерфейсов, подобных массивам, таких как pop (), shift (), unshift () и т. Д.

Внедрение зависимостей

Общий шаблонв крупномасштабной разработке приложений это называется внедрением зависимостей, и в основном это означает, что, пометив ваш класс каким-либо образом (часто используются метаданные AS3), вы можете сигнализировать, что платформа должна «внедрить» ссылку в этот класс.Таким образом, классу не нужно заботиться о том, откуда поступает ссылка, но фреймворк позаботится о том, чтобы он там был.

Очень популярный DI-каркас для AS3 - Robotlegs .

2 голосов
/ 27 августа 2011

ПРИМЕЧАНИЕ. Я не рекомендую использовать глобальные переменные!

Но вот ваш ответ

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

//File: GlobalArray.as

package {
    public var GlobalArray:Array = [];
}

И это все!У вас есть глобальная переменная.Вы можете получить доступ из своего кода (из любого места) следующим образом:

function DoSomething() {
    GlobalArray.push(new Object());
    GlobalArray.pop();
    for each (var object:* in GlobalArray) {
        //...
    }
}
1 голос
/ 21 марта 2017

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

Aternative

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

Что касается альтернативы синглтону, вы могли бы иметь:

public class Global {
    public static const myArray:Alternative = new Alternative();
}

и используйте его почти как синглтон:

var ga:Alternative = Global.myArray;
ga.e.addEventListener(GDataEvent.NEW_DATA, onNewData);
ga.e.addEventListener(GDataEvent.DATA_CHANGE, onDataChange);
ga.push(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "ten");
trace(ga[5]); // 5

И ваш Alternative.as будет выглядеть аналогично синглтону:

package adnss.projects.tchqs 
{

    import flash.utils.Proxy;
    import flash.utils.flash_proxy;

    public class Alternative extends Proxy
    {
        private var _data:Array = [];
        private var _events:AltEventDisp = new AltEventDisp();
        private var _dispatching:Boolean = false;
        public var blockCircularChange:Boolean = true;

        public function Alternative() {}

        override flash_proxy function getProperty(id:*):* {var i:int = id;
            return _data[i += (i < 0) ? _data.length : 0];
            //return _data[id]; //version without anal item access - var i:int could be removed. 
        }

        override flash_proxy function setProperty(id:*, value:*):void { var i:int = id;
            if (_dispatching) { throw new Error("You cannot set data while DATA_CHANGE event is dipatching"); return; }
            i += (i < 0) ? _data.length : 0;
            if (i > 9 ) { throw new Error ("You can override only first 10 items without using push."); return;}
            _data[i] = value;
            if (blockCircularChange) _dispatching = true;
            _events.dispatchEvent(new GDataEvent(GDataEvent.DATA_CHANGE, i));
            _dispatching = false;
        }

        public function push(...rest) {
            var c:uint = -_data.length + _data.push.apply(null, rest);
            _events.dispatchEvent(new GDataEvent(GDataEvent.NEW_DATA, _data.length - c, c));
        }

        public function get length():uint { return _data.length; }

        public function get e():AltEventDisp { return _events; }

        public function toString():String { return String(_data); }
    }

}

import flash.events.EventDispatcher;
/**
 * Dispatched after data at existing index is replaced. 
 * @eventType   adnss.projects.tchqs.GDataEvent
 */
[Event(name = "dataChange", type = "adnss.projects.tchqs.GDataEvent")]
/**
 * Dispatched after new data is pushed intwo array.
 * @eventType   adnss.projects.tchqs.GDataEvent
 */
[Event(name = "newData", type = "adnss.projects.tchqs.GDataEvent")]
class AltEventDisp extends EventDispatcher { }

Единственное отличие формы Singleton заключается в том, что у вас может быть несколько экземпляров этого класса, поэтому вы можете использовать его следующим образом:

public class Global {
    public static const myArray:Alternative = new Alternative();
    public static const myArray2:Alternative = new Alternative();
}

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

Примечание

Обтекание массива подобным образом с использованием таких методов, как myArray.get(x) или myArray[x], явно медленнее, чем доступ к необработанному массиву (см. Все дополнительные шаги, которые мы предпринимаем в setProperty).

public static const staticArray:Array = [1,2,3];

С другой стороны, вы не можете это контролировать. И содержимое массива может быть изменено в любом месте.

Предупреждение о событиях

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

private function onDataChange(e:GDataEvent):void {
    trace("dataChanged at:", e.id, "to", Global.myArray[e.id]);
    Global.myArray[e.id]++;
    trace("new onDataChange is called before function exits"); 
}

Функция вызывается после изменения данных в массиве, и внутри этой функции вы меняете данные снова. В основном это похоже на что-то вроде этого:

function f(x:Number) {
    f(++x);
}

Вы можете увидеть, что происходит в таком случае, если вы переключите myArray.blockCircularChange. Иногда вы намеренно хотели бы иметь такую ​​рекурсию, но вполне вероятно, что вы сделаете это «случайно». К сожалению, Flash внезапно остановит отправку таких событий, даже не объяснив, почему, и это может сбить с толку.

Скачать полный пример здесь

Почему использование глобальных переменных плохо в большинстве сценариев?

Я полагаю, что в интернете много информации об этом, но для полноты добавлю простой пример.

Представьте, что в вашем приложении есть какой-то вид, где вы отображаете текст, графику или, скорее всего, игровой контент. Скажем, у вас есть игра в шахматы. Возможно, вы разделили логику и графику на два класса, но вы хотите, чтобы оба работали на одних и тех же пешках. Таким образом, вы создаете переменную Global.pawns и используете ее в классах Grahpics и Logic.

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

Что ж, вы обречены на этом этапе, потому что каждый экземпляр вашего класса будет использовать один и тот же массив Global.pawns. Вы не только имеете эту глобальную переменную, но также ограничиваете себя в использовании только одного экземпляра каждого класса, который использует эту переменную: /

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

...