A Container is an object created to hold other objects that are accessed, placed, and maintained with the class methods of the container - queues, sets, lists, vectors, and caches all fit this description. These objects - the elements of the container - are usually allowed to be of any class and may be of the container class itself. Every Container should also have an associated Iterator type that can be used to iterate through the elements of the container.
The term container in modern computer programming can actually refer to many things:
Use a Container Pattern when:
This class diagram shows a simple Container which implements only the add(E o) and iterator() methods. To be really useful you would of course also implement methods like remove(E o), contains(E o), isEmpty(), size(), etc...
A Container Pattern should really make use of the Interface Pattern, in our short example here we won't implement an interface because we want to concentrate on how a container works. Please note that if you need to create your own container, which is very rare anyway since the Java Collections Framework is quite good, you should implement the Collection interface (public class MyContainer<E> implements Collection<E>) in order to make your container compatible with the Java Collections Framework.
public class MyContainer<E> { protected class Node { private E element; Node next = null; Node previous = null; public Node(E element) { this.element = element; } } protected Node head = null; protected Node tail = null; public class NodeIterator implements Iterator<E> { protected Node p = head; public boolean hasNext() { return p != null; } // returns the next element public E next() { if (p == null) return null; E element = p.element; p = p.next; return element; } // removes the last element returned by the iterator public void remove() { Node n = p.previous; p.previous.next = p.next; p.next.previous = p.previous; } } public void add(E o) { if (head == null) tail = head = new Node(o); else Node newnode = new Node(o); newnode.previous = tail; tail = tail.next = newnode; } public Iterator<E> iterator() { return new NodeIterator(); } }
Now lets take a look at how this container is used:
public static void main(String[] args) { // Integer Container MyContainer<Integer> int_cont = new MyContainer<Integer>(); int_cont.add(1); int_cont.add(2); int_cont.add(3); Iterator<Integer> int_it = int_cont.iterator(); while (int_it.hasNext()) { System.out.println("Integer Container: " + int_it.next()); } // String Container MyContainer<String> string_cont = new MyContainer<String>(); string_cont.add("one"); string_cont.add("two"); string_cont.add("three"); Iterator<String> string_it = string_cont.iterator(); while (string_it.hasNext()) { System.out.println("String Container: " + string_it.next()); } // Container Container MyContainer<MyContainer<Integer>> cont_cont = new MyContainer<MyContainer<Integer>>(); cont_cont.add(int_cont); // cont_cont.add(string_cont); This does not work -> MyContainer<Integer> ! Iterator<MyContainer<Integer>> cont_it = cont_cont.iterator(); while (cont_it.hasNext()) { MyContainer<Integer> it = cont_it.next(); Iterator<Integer> it_it = it.iterator(); while (it_it.hasNext()) { System.out .println("Integer Container inside Container Container: " + it_it.next()); } } }