AS3: Collection, ValueObject, & Iterator

View Collection Documentation
View Iterator Documentation
View Value Object Documentation
Download Classes & Example Files

A while ago I blogged about converting Collection and Iterator classes to AS3 since storing data in ValueObjects has become a regular practice in my coding. I really like how VOs are strongly typed and how you use a Collection to hold all the data together nicely. I am working on a project right now that allowed me to see even better uses for these things so I added a couple of simple (but helpful) methods to my Collection class (most notably the ability to add an item at a specified index as well as output the data currently existing in the collection easily) and created a base ValueObject class that allows you to easily output the data in that VO.

Important to also note is the package move. I've moved everything into a com.reintroducing.data package as I believe this fits better with what these classes are actually doing. There is also interfaces for ValueObject and Collection as well.

Just so you don't have to flip back and forth between posts, I'll post the classes and data here with a little explanation of each.

Here is Collection.as:

Actionscript:
  1. package com.reintroducing.data
  2. {
  3.     import flash.utils.getQualifiedClassName;
  4.  
  5.     /**
  6.      * A base class for storing strongly typed Value Objects.
  7.      *
  8.      * @author Adobe [http://www.adobe.com]
  9.      * @author Ported to AS3 by Matt Przybylski [http://www.reintroducing.com]
  10.      * @version 1.1
  11.      */
  12.     public class Collection implements ICollection
  13.     {
  14. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  15.  
  16.         private var _name:String;
  17.         private var _items:Array;
  18.        
  19. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  20.        
  21.        
  22.        
  23. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  24.    
  25.         /**
  26.          * Helper class used to manage a collection of objects. This class is similar to the Java
  27.          * Collection interface.  Developers can extend this class to create new Collection types
  28.          * that provide additional functionality such as ordering and sorting.
  29.          *
  30.          * @param $name the name of the Collection.
  31.          *
  32.          * @return Nothing
  33.          */
  34.         public function Collection($name:String):void
  35.         {
  36.             super();
  37.            
  38.             this._name = $name;
  39.             this._items = new Array();
  40.         }
  41.        
  42. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  43.        
  44.         // Finds an item within the Collection and returns it's index.
  45.         private function internalGetItem($item:Object):int
  46.         {
  47.             var result:int = -1;
  48.            
  49.             for (var i:int = 0; i <this._items.length; i++)
  50.             {
  51.                 if (this._items[i] == $item)
  52.                 {
  53.                     result = i;
  54.                     break;
  55.                 }
  56.             }
  57.            
  58.             return result;
  59.         }
  60.        
  61. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  62.    
  63.         /**
  64.          * Gets the name of the Collection.
  65.          *
  66.          * @return String the name of the Collection.
  67.          */
  68.         public function getName():String
  69.         {
  70.             return this._name;
  71.         }
  72.        
  73.         /**
  74.          * Adds a new item to the end of the Collection.
  75.          *
  76.          * @param $item * to be added to the Collection. If item is null it will not be added to the Collection.
  77.          *
  78.          * @return Boolean true if the Collection was changed as a result of the operation.
  79.          */
  80.         public function addItem($item:*):Boolean
  81.         {
  82.             var result:Boolean = false;
  83.            
  84.             if ($item != null)
  85.             {
  86.                 this._items.push($item);
  87.                
  88.                 result = true;
  89.             }
  90.            
  91.             return result;
  92.         }
  93.        
  94.         /**
  95.          * Adds a new item at the specified index in the Collection.
  96.          *
  97.          * @param $index position to add the specified item in
  98.          * @param $item * to be added to the Collection.
  99.          *
  100.          * @return Nothing
  101.          */
  102.         public function addItemAt($index:int, $item:*):void
  103.         {
  104.             this._items.splice($index, 0, $item);
  105.         }
  106.        
  107.         /**
  108.          * Removes a single item from the Collection.  Returns false if item is not found.
  109.          *
  110.          * @param $item reference to Collection item to be removed from Collection.
  111.          *
  112.          * @return Boolean true if item is found and successfully removed.  False if item is not found.
  113.          */
  114.         public function removeItem($item:*):Boolean
  115.         {
  116.             var result:Boolean = false;
  117.             var itemIndex:int = this.internalGetItem($item);
  118.            
  119.             if (itemIndex> -1)
  120.             {
  121.                 this._items.splice(itemIndex, 1);
  122.                
  123.                 result = true;
  124.             }
  125.            
  126.             return result;
  127.         }
  128.        
  129.         /**
  130.          * Removes all items from the Collection.
  131.          *
  132.          * @return Nothing
  133.          */
  134.         public function clear():void
  135.         {
  136.             this._items = new Array();
  137.         }
  138.        
  139.         /**
  140.          * Returns true if this Collection contains the specified item.
  141.          *
  142.          * @param $item * whose presence in this collection is to be tested.
  143.          *
  144.          * @return Boolean true if this collection contains the specified item.
  145.          */
  146.         public function contains($item:*):Boolean
  147.         {
  148.             return (this.internalGetItem($item)> -1);
  149.         }
  150.        
  151.         /**
  152.          * Returns an item within the Collection using it's index.
  153.          *
  154.          * @param $index location of item within the Collection.
  155.          *
  156.          * @return * reference to item.
  157.          */
  158.         public function getItemAt($index:int):*
  159.         {
  160.             return this._items[$index];
  161.         }
  162.        
  163.         /**
  164.          * Returns an iterator over the elements in this collection. There are no guarantees concerning
  165.          * the order in which the elements are returned (unless this collection is an instance of some
  166.          * class that provides a guarantee).
  167.          *
  168.          * @return Iterator object that is used to iterate through the collection.
  169.          */
  170.         public function getIterator():Iterator
  171.         {
  172.             return (new Iterator(this));
  173.         }
  174.        
  175.         /**
  176.          * Returns the current length
  177.          *
  178.          * @return int value reflecting the number of items in this Collection.
  179.          */
  180.         public function getLength():int
  181.         {
  182.             return this._items.length;
  183.         }
  184.        
  185.         /**
  186.          * Returns true if the Collection is empty.
  187.          *
  188.          * @return Boolean true if Collection is empty.
  189.          */
  190.         public function isEmpty():Boolean
  191.         {
  192.             return (this._items.length == 0);
  193.         }
  194.        
  195.         /**
  196.          * Traces the Value Objects of the Collection to the Output panel.
  197.          *
  198.          * @return Nothing
  199.          */
  200.         public function output():void
  201.         {
  202.             trace("Start " + this.getName() + " Contents:");
  203.             trace("---------------------------------------------\n");
  204.            
  205.             for (var i:int = 0; i <this.getLength(); i++)
  206.             {
  207.                 var vo:IValueObject = this.getItemAt(i);
  208.                
  209.                 vo.output();
  210.             }
  211.            
  212.             trace("End " + this.getName() + " Contents");
  213.             trace("---------------------------------------------\n");
  214.         }
  215.    
  216. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  217.    
  218.        
  219.    
  220. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  221.    
  222.        
  223.    
  224. //- HELPERS -----------------------------------------------------------------------------------------------
  225.    
  226.         public function toString():String
  227.         {
  228.             return getQualifiedClassName(this);
  229.         }
  230.    
  231. //- END CLASS ---------------------------------------------------------------------------------------------
  232.     }
  233. }

This class has a lot of methods which you can go through with descriptions in the documentation. The only thing to point out here is the new output() and addItemAt() methods as described above.

Here is ValueObject.as:

Actionscript:
  1. package com.reintroducing.data
  2. {
  3.     import flash.utils.describeType;
  4.     import flash.utils.getQualifiedClassName;
  5.  
  6.     /**
  7.      * A base class for storing strongly typed data.
  8.      *
  9.      * @author Matt Przybylski [http://www.reintroducing.com]
  10.     * @version 1.0
  11.     */
  12.     public class ValueObject implements IValueObject
  13.     {
  14. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  15.  
  16.        
  17.        
  18. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  19.        
  20.        
  21.        
  22. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  23.    
  24.         public function ValueObject():void
  25.         {
  26.            
  27.         }
  28.        
  29. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  30.        
  31.        
  32.        
  33. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  34.    
  35.         /**
  36.          * Outputs the data in the value object.
  37.          *
  38.          * @return Nothing
  39.          */
  40.         public function output():void
  41.         {
  42.             trace(this.toString());
  43.             trace("\t-----------------------------------------");
  44.            
  45.             var props:XMLList = describeType(this).variable;
  46.            
  47.             for (var i:int = 0; i <props.length(); i++)
  48.             {
  49.                 trace("\t" + props[i].@name + ":" + props[i].@type + " = " + this[props[i].@name]);
  50.             }
  51.            
  52.             trace("\t-----------------------------------------\n");
  53.         }
  54.    
  55. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  56.    
  57.        
  58.    
  59. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  60.    
  61.        
  62.    
  63. //- HELPERS -----------------------------------------------------------------------------------------------
  64.    
  65.         public function toString():String
  66.         {
  67.             return getQualifiedClassName(this);
  68.         }
  69.    
  70. //- END CLASS ---------------------------------------------------------------------------------------------
  71.     }
  72. }

The reason I made this class was so that I could easily output the data in the VO without having to rewrite that method in every VO moving forward. It was very useful on this project I am working on and I definitely wished I had something like that previously rather than trying to loop through the class when necessary.

The following is Iterator.as:

Actionscript:
  1. package com.reintroducing.data
  2. {
  3.     import flash.utils.getQualifiedClassName;
  4.  
  5.     /**
  6.      * Works in conjunction with a Collection to iterate through its contents.
  7.      *
  8.      * @author Adobe [http://www.adobe.com]
  9.      * @author Ported to AS3 by Matt Przybylski [http://www.reintroducing.com]
  10.      * @version 1.0
  11.      */
  12.     public class Iterator
  13.     {
  14. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  15.  
  16.         private var _collection:Collection;
  17.         private var _cursor:int;
  18.        
  19. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  20.        
  21.        
  22.        
  23. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  24.    
  25.         /**
  26.          * Initialize the Iterator and maintain a link to it's Collection.
  27.          *
  28.          * @param $coll Collection to which this Iterator belongs.
  29.          */
  30.         public function Iterator($coll:Collection):void
  31.         {
  32.             this._collection = $coll;
  33.             this._cursor = 0;
  34.         }
  35.  
  36. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  37.        
  38.        
  39.        
  40. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  41.    
  42.         /**
  43.          * Returns true if the iteration has more items.
  44.          *
  45.          * @return Boolean true if iteration has more items.
  46.          */
  47.         public function hasNext():Boolean
  48.         {
  49.             return (this._cursor <this._collection.getLength());
  50.         }
  51.        
  52.         /**
  53.          * Return the next item in the iteration and increment the cursor. Returns null if the
  54.          * iteration has no more items.
  55.          *
  56.          * @return * the next item in the Iteration.
  57.          */
  58.         public function next():*
  59.         {
  60.             return (this._collection.getItemAt(this._cursor++));
  61.         }   
  62.    
  63. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  64.    
  65.        
  66.    
  67. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  68.    
  69.        
  70.    
  71. //- HELPERS -----------------------------------------------------------------------------------------------
  72.    
  73.         public function toString():String
  74.         {
  75.             return getQualifiedClassName(this);
  76.         }
  77.    
  78. //- END CLASS ---------------------------------------------------------------------------------------------
  79.     }
  80. }

There have been no changes to this class.

Here is a sample XML file that I am going to use in a project:

XML:
  1. <info>
  2.     <entry name="Portfolio" id="0" src="http://www.reintroducing.com" />
  3.     <entry name="Flash Dev Blog" id="1" src="http://evolve.reintroducing.com" />
  4.     <entry name="Company" id="2" src="http://www.b-r-e-e-d.com" />
  5.     <entry name="Girlfriend" id="3" src="http://www.jessicanovales.com" />
  6.     <entry name="Sport" id="4" src="http://www.nba.com" />
  7. </info>

Then, here is the corresponding TestVO class that extends ValueObject:

Actionscript:
  1. package
  2. {
  3.     import com.reintroducing.data.ValueObject;
  4.     import flash.utils.getQualifiedClassName;
  5.    
  6.     /**
  7.     * @author Matt Przybylski [http://www.reintroducing.com]
  8.     * @version 1.0
  9.     */
  10.     public class TestVO extends ValueObject
  11.     {
  12. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  13.  
  14.        
  15.        
  16. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  17.        
  18.         public var name:String;
  19.         public var id:int;
  20.         public var src:String;
  21.        
  22. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  23.    
  24.         public function TestVO():void
  25.         {
  26.             super();
  27.         }
  28.        
  29. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  30.        
  31.        
  32.        
  33. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  34.    
  35.        
  36.    
  37. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  38.    
  39.        
  40.    
  41. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  42.    
  43.        
  44.    
  45. //- HELPERS -----------------------------------------------------------------------------------------------
  46.    
  47.         override public function toString():String
  48.         {
  49.             return getQualifiedClassName(this);
  50.         }
  51.    
  52. //- END CLASS ---------------------------------------------------------------------------------------------
  53.     }
  54. }

Nothing fancy here, just extending ValueObject and defining some properties for later use.

Here is the corresponding TestVOCollection which will store all of our VOs:

Actionscript:
  1. package
  2. {
  3.     import com.reintroducing.data.Collection;
  4.     import com.reintroducing.data.Iterator;
  5.     import flash.utils.getQualifiedClassName;
  6.    
  7.     /**
  8.     * @author Matt Przybylski [http://www.reintroducing.com]
  9.     * @version 1.0
  10.     */
  11.     public class TestVOCollection extends Collection
  12.     {
  13. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  14.  
  15.        
  16.        
  17. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  18.        
  19.        
  20.        
  21. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  22.    
  23.         public function TestVOCollection($name:String):void
  24.         {
  25.             super($name);
  26.         }
  27.        
  28. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  29.        
  30.        
  31.        
  32. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  33.    
  34.         /**
  35.          *
  36.          */
  37.         public function getItemByID($id:int):TestVO
  38.         {
  39.             var itr:Iterator = this.getIterator();
  40.             var testVO:TestVO;
  41.             var rVO:TestVO;
  42.            
  43.             while (itr.hasNext())
  44.             {   
  45.                 testVO = TestVO(itr.next());
  46.                
  47.                 if (testVO.id == $id)
  48.                 {
  49.                     rVO = testVO;
  50.                     break;
  51.                 }
  52.             }
  53.            
  54.             return rVO;
  55.         }
  56.        
  57.         /**
  58.          *
  59.          */
  60.         public function getItemByName($name:String):TestVO
  61.         {
  62.             var itr:Iterator = this.getIterator();
  63.             var testVO:TestVO;
  64.             var rVO:TestVO;
  65.            
  66.             while (itr.hasNext())
  67.             {   
  68.                 testVO = TestVO(itr.next());
  69.                
  70.                 if (testVO.name == $name)
  71.                 {
  72.                     rVO = testVO;
  73.                     break;
  74.                 }
  75.             }
  76.            
  77.             return rVO;
  78.         }
  79.    
  80. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  81.    
  82.        
  83.    
  84. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  85.    
  86.        
  87.    
  88. //- HELPERS -----------------------------------------------------------------------------------------------
  89.    
  90.         override public function toString():String
  91.         {
  92.             return getQualifiedClassName(this);
  93.         }
  94.    
  95. //- END CLASS ---------------------------------------------------------------------------------------------
  96.     }
  97. }

Basically I've extended Collection and also given it some specific methods for this particular collection to access data a little easier.

Lastly, here is the code I wrote in the Document class of my FLA to pull everything together:

Actionscript:
  1. package
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.events.Event;
  5.     import flash.net.URLLoader;
  6.     import flash.net.URLRequest;
  7.     import flash.utils.getQualifiedClassName;
  8.    
  9.     import com.reintroducing.debug.Environment;
  10.  
  11.     /**
  12.     * @author Matt Przybylski [http://www.reintroducing.com]
  13.     * @version 1.0
  14.     */
  15.     public class Main extends Sprite
  16.     {
  17. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  18.  
  19.         private var _env:Environment;
  20.         private var _testVOCollection:TestVOCollection;
  21.        
  22. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  23.        
  24.        
  25.        
  26. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  27.    
  28.         public function Main():void
  29.         {
  30.             this._env = Environment.getInstance();
  31.             this._env.setPaths("../", "");
  32.            
  33.             this.loadXML();
  34.         }
  35.        
  36. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  37.        
  38.         private function loadXML():void
  39.         {
  40.             var xmlURL:String = this._env.basePath + "xml/info.xml";
  41.             var xmlLoader:URLLoader = new URLLoader();
  42.            
  43.             xmlLoader.addEventListener(Event.COMPLETE, parseXML, false, 0, true);
  44.             xmlLoader.load(new URLRequest(xmlURL));
  45.         }
  46.        
  47.         /**
  48.          *
  49.          */
  50.         private function parseXML($evt:Event):void
  51.         {
  52.             var info:XML = new XML($evt.target.data);
  53.             var numItems:int = info.children().length();
  54.             var testVO:TestVO;
  55.            
  56.             this._testVOCollection = new TestVOCollection("TestVOCollection");
  57.            
  58.             for (var i:int = 0; i <numItems; i++)
  59.             {
  60.                 testVO   = new TestVO();
  61.                 testVO.name = info.entry[i].@name;
  62.                 testVO.id   = int(info.entry[i].@id);
  63.                 testVO.src  = info.entry[i].@src;
  64.                
  65.                 this._testVOCollection.addItem(testVO);
  66.             }
  67.            
  68.             this.traceBlogInfo();
  69.         }
  70.        
  71.         /**
  72.          *
  73.          */
  74.         private function traceBlogInfo():void
  75.         {
  76.             trace("Entry Name: " + this._testVOCollection.getItemAt(1).name);
  77.             trace("Entry ID: " + this._testVOCollection.getItemByID(1).id);
  78.             trace("Entry Source: " + this._testVOCollection.getItemByName("Flash Dev Blog").src);
  79.             trace("\nAlternate Output Method\n");
  80.             this._testVOCollection.output();
  81.         }
  82.        
  83. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  84.    
  85.        
  86.    
  87. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  88.    
  89.        
  90.    
  91. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  92.    
  93.        
  94.    
  95. //- HELPERS -----------------------------------------------------------------------------------------------
  96.    
  97.         override public function toString():String
  98.         {
  99.             return getQualifiedClassName(this);
  100.         }
  101.    
  102. //- END CLASS ---------------------------------------------------------------------------------------------
  103.     }
  104. }

Not much has changed in this version except I've specified the name of the Collection when defining it and showed how to output the data in two different approaches (the latter using the new output() method of the Collection class.

As you can see, the new methods for outputting data can really be a big time saver so you don't have to loop through your VOs/Collections and output stuff manually.

If you found this post useful, please consider leaving a comment, subscribing to the feed, or making a small donation.

6 Comments

Good post Matt, I feel that's the highest time for me to become friends with VOs 🙂

Good tutorial, thank you for sharing.

[...] used ValueObjects in my project, here’s an interesting link: AS3: Collection, ValueObject,& Iterator I think ValueObjects these can be parsed to JSON [...]

Good !
But why don't use Vector. ?

@Oleg: Great question, and the simple answer is that this was something I used in FP9 so Vector wasn't an option at that point. Now that most of my work is done in FP10 I'll probably convert it over to use Vector instead.

@Oleg also, just realized after looking at the class, you don't know what item is going to be typed to so what kind of vector are you making?

Leave a comment

(required)

(required)