Understanding the Element Interface


All elements within the Composite pattern, whether leaves or composites, should be essentially interchangeable. This means that they must all implement a common interface. It's impossible to determine what the exact interface ought to look like for every use of the Composite pattern. However, at a minimum, it will likely look much like a collection. The following is an example of what a basic element interface might look like:

package {    public interface IElement {       function iterator():IIterator;       function addItem(item: IElement):void;       function removeItem(item: IElement):void;       function getParent():IElement;       function setParent(parent: IElement):void;    } }


Note

The preceding interface uses the IIterator interface as discussed in Chapter 7, "Iterator Pattern." This chapter makes use of the Iterator pattern; if you have not yet read Chapter 7, you might want to consider reading that chapter before continuing with this one.


Note that this basic element interface example specifies IElement as the type for the addItem(), removeItem(), and setParent() methods. In theory, this means that any class that implements the IElement interface can be added to any other object that implements the same interface. This is what enables all elements in the Composite pattern to look identical. Of course, the implementation will be different for leaf and composite elements. A leaf element cannot actually contain other elements, but it must implement the same interface for the pattern to work.

In a practical example, the element interface will probably have more methods than are included in the IElement example. Throughout this chapter, we'll be looking at a file system example. The following IFileSystemItem interface is the element interface we will use for the file system example:

package com.peachpit.aas3wdp.compositeexample.data {    // You'll need to ensure that IIterator from Chapter 7 is in your    // classpath.    import com.peachpit.aas3wdp.iterators.IIterator;        public interface IFileSystemItem {    function iterator():IIterator;    function addItem(item:IFileSystemItem):void;    function removeItem(item:IFileSystemItem):void;    function getName():String;    function setName(name:String):void;    function getParent():IFileSystemItem;    function setParent(parent:IFileSystemItem):void; } }


For this example, it's also useful to create a simple implementation in the form of an abstract class we'll call FileSystemItem. Although an abstract class is not a requirement in this case, we're using one because that way each of the concrete classes can inherit a common implementation rather than having redundant code in each of the classes. All our code still references the interface rather than the abstract class to maintain maximum adaptability. The abstract class looks like the following:

package com.peachpit.aas3wdp.compositeexample.data {    import com.peachpit.aas3wdp.iterators.IIterator;           public class FileSystemItem implements IFileSystemItem {       protected var _parent:IFileSystemItem;       protected var _name:String;         public function FileSystemItem() {       }       public function iterator():IIterator {          return null;       }                public function addItem(item:IFileSystemItem):void {                 }       public function removeItem(item:IFileSystemItem):void {            }       public function getName():String {          return _name;       }       public function setName(name:String):void {          _name = name;       }       public function getParent():IFileSystemItem {          return _parent;       }       public function setParent(parent:IFileSystemItem):void {          _parent = parent;       }    } }


In this case, we're using an abstract class (FileSystemItem) because it provides some basic implementation that concrete leaf and composite subclasses can inherit. This way the, File and Directory subclasses don't have to each implement getName(),setName(), getParent(), and setParent().

Note

The preceding interface and abstract class might seem strange because they require all concrete classes to implement methods that may or may not appear directly related to all types. For example, leaf elements might not appear to need addItem(), removeItem(), and iterator() methods. Although it's true that, in most cases, it is inadvisable for an interface to require a concrete type to implement methods that don't apply to all types, in the case of the Composite pattern it is essential to the pattern that composite and leaf elements appear to be identical. Therefore the leaf elements must implement addItem(), removeItem(), and iterator().





Advanced ActionScript 3 with Design Patterns
Advanced ActionScript 3 with Design Patterns
ISBN: 0321426568
EAN: 2147483647
Year: 2004
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net