Неизменяемые коллекции Actionscript 3
В последнее время я пытаюсь внедрить некоторые чистые методы кодирования в AS3. Одна из них заключалась в том, чтобы не отсылать ссылки на массивы из содержащего объекта. Дело в том, что я контролирую добавление и удаление из одного класса, а все остальные пользователи из массива получают только версию для чтения.
В настоящий момент версия только для чтения представляет собой класс ArrayIterator, который я написал, который реализует типичный интерфейс Iterator (hasNext, getNext). Он также расширяет прокси-сервер, поэтому его можно использовать для каждой петли, как только может быть массив.
Итак, мой вопрос заключается в том, что это не является фундаментальной особенностью многих языков? Возможность передавать ссылки на чтение только видов коллекций?
Также теперь, когда улучшена безопасность типов для коллекций в AS3, в виде класса Vector, когда я обертываю вектор в VectorIterator, я теряю типизацию ради неизменности. Есть ли способ реализовать два желания, неизменность и типизацию в AS3?
Ответы
Ответ 1
Кажется, что использование шаблона Iterator - лучший способ в настоящее время в AS3 для передачи коллекции вокруг системы, гарантируя, что он не будет изменен.
Используемый мной интерфейс IIterator моделируется на Java Iterator, но я не реализую метод remove(), так как это считается ошибкой дизайна многими в сообществе Java, благодаря чему пользователь может удалить элементы массива. Ниже приведена моя реализация IIterator:
public interface IIterator
{
function get hasNext():Boolean
function next():*
}
Затем это реализуется такими классами, как ArrayIterator, VectorIterator и т.д.
Для удобства я также расширяю Proxy на своих конкретных классах Iterator и поддерживаю for-each петли в AS3, переопределяя методы nextNameIndex() и nextValue(). Это означает, что код, который обычно использует Массивы, не нуждается в изменении при использовании моего IIterator.
var array:Array = ["one", "two", "three"]
for each (var eachNumber:String in array)
{
trace(eachNumber)
}
var iterator:IIterator = new ArrayIterator(array)
for each (var eachNumber:String in iterator)
{
trace(eachNumber)
}
Проблема только в том, что пользователю не нужно смотреть на интерфейс IIterator и знать, что они могут использовать цикл for для каждого цикла для итерации по коллекции. Им нужно будет посмотреть на реализацию ArrayIterator, чтобы увидеть это.
Ответ 2
Некоторые утверждают, что тот факт, что вы можете реализовать такие шаблоны, как библиотеки, является аргументом против добавления функций к самому языку (например, разработчики языка С++ обычно говорят об этом).
Ответ 3
У вас есть неизменяемость, которую вы хотите с помощью прокси-объекта или нет? Обратите внимание, что конструктор VectorIterator может иметь обязательный параметр класса. По общему признанию, на данный момент это не дизайнерский подход, но позволяет надеяться, что в будущем все будет улучшаться.
Ответ 4
Я создал небольшую библиотеку неизменяемых классов коллекции для AS3, включая типизированный упорядоченный список, который звучит так, как будто он будет отвечать вашим потребностям. Подробнее см. этот пост в блоге.
Ответ 5
Что-то, что я делаю для достижения этого, состоит в том, чтобы класс, который поддерживает список, возвращает только копию этого списка в getter через slice()
. В качестве примера у моего игрового движка есть класс Scene
, который поддерживает список всех Beings
, которые были добавлены к нему. Затем этот список открывается как копия:
public function get beings():Vector.<Being>
{
return _beings.slice();
}
(Извините, что возродил старый поток, я наткнулся на это, ища способы реализовать именно то, что отвечает Брайан, и подумал, что я брошу свои 2 цента в этом вопросе).