This article continues to introduce23 Design Mode SeriesThe Observer pattern.
definitionIn the process of software building, the internal structure of collection objects often varies, but for these collection objects, we want to allow external client code to transparently access the elements contained therein while not exposing its internal structure, and this "transparent traversal" also provides the possibility for the same algorithm to operate on a variety of collection objects. Using object-oriented techniques to abstract this traversal mechanism into an "iterator object" provides an elegant way of coping with changing collection objects. The iteration (Iterator) pattern, also called the cursor pattern, is the behavior pattern of the object. Iterative sub-patterns can sequentially access an element in a cluster without having to burst the internal representation of the aggregation.
Why aggregation requires iterative sub-generationMultiple objects are collectively called aggregates (Aggregate), and clustered objects are container objects that can contain a set of objects. Aggregation relies on the abstraction of aggregation structures, complexity and diversity, arrays are the most basic aggregation, but also the design basis of other Java aggregation objects. Java Aggregation (Collection) objects are objects that implement a common Java.util.Collection interface and are the direct support of the Java language to the concept of aggregation. The aggregation object must provide the appropriate method to allow the client to traverse all the element objects in a linear order, extracting or deleting the element objects, etc. A system using aggregation will inevitably use these methods to manipulate the aggregation objects, so there are two types of situations in the process of using the poly system. The iterative logic does not change, but a clustered object needs to be replaced by another aggregation, because different aggregates have different traversal interfaces, so you need to modify the client code to replace the existing iteration calls with the interfaces required by the new clustered object. The aggregation does not change, but the iteration needs to change, such as the original only need to read elements and delete elements, but now need to add new, or the original iteration just traverse all the elements, and now need to filter the elements and so on. At this point, you have to modify the aggregation object, modify the existing traversal method, or add a new method. Obviously, this occurs because the aggregation design involved does not conform to the "open-closed" principle, that is, because the invariant structure is not abstracted from the system, separated from the variable components, and the various implementations of the variable parts are encapsulated. A clever way to do this is to use a more abstract approach, so that when iterating, the client does not need to know which type of aggregation to use, and when the client needs to use the new iterative logic, it is only necessary to introduce a new iteration sub-object, without modifying the clustered object itself at all. The iterative sub-pattern pattern is such an abstraction that the pattern is able to do this because it encapsulates the iterative logic into a separate iteration of the iterative sub-object, separating it from the aggregation itself. Iterative sub-objects are abstractions of traversal, and different clustered objects can provide the same iteration sub-objects, so that the client does not need to know the clustered low-level structure, and a aggregation can provide several different iterations of the sub-objects, so that the traversal logic changes do not affect the clustered object itself.
There are two implementations of the iterative sub-pattern, namely, the white box aggregation and the outer iteration and the black box aggregation in the intrinsic iteration.
white box aggregation and external iterative sub-generationIf a clustered interface provides a method that can be used to modify a clustered element, this interface is called a wide interface. If a clustered object provides the same interface for all objects, that is, a wide interface, it will of course satisfy the iterative sub-pattern requirements for the iteration sub-object. However, this destroys the encapsulation of the clustered object. This aggregation, which provides a wide interface, is called a white box aggregation.
By aggregating itself to implement iterative logic and providing an appropriate interface externally, the iteration can control the iterative process of aggregating elements from the outside. As a result, the iteration control is just a cursor, which is called the cursor iteration (cursor Iterator). Since the iteration is outside the aggregation structure, such an iteration is called an external iteration (extrinsic Iterator).
ImplementA white box gathers to provide an interface to the outside world to access its own elements (called traversal methods or traversing method), so that the external iteration can iterate through the aggregated traversal method. Because the logic of the iteration is provided by the aggregation object itself, such an external iterative child role tends to keep only the cursor position of the iteration.
roleAbstract Iteration Child (Iterator) role: This abstract role defines the interfaces required to traverse an element. Specific iteration child (concreteiterator) Role: This role implements the iterator interface and maintains the cursor position during iteration. Aggregation (Aggregate) role: This abstract role gives an interface to create an iterative child (Iterator) object. Specific aggregation (concreteaggregate) role: Implements an interface that creates an iterative child (Iterator) object, and returns an appropriate iteration child instance. Client role: holds a reference to the aggregation and its iteration sub-objects, calls the iteration interface of the iteration sub-object, and may also accumulate and delete the elements by iterating through the child operations.
abstract Clustered Role ClassesThis role specifies the interfaces that all concrete aggregates must implement. Iterative sub-patterns require that a clustered object must have a factory method, the Createiterator () method, to provide an instance of an iterative child object to the outside world.
Public abstract class Aggregate { /** * Factory method, creating an interface for the corresponding iteration sub-object * /public abstract Iterator Createiterator () ;}
specific clustered Role classesimplements the interface required by the abstract clustered role class, which is the Createiterator () method. In addition, there are methods for getelement () to provide aggregation elements to the outside world, and the method size () provides the aggregation to the outside world.
public class Concreteaggregate extends Aggregate { private object[] Objarray = null; /** * Construction method, the specific contents of the incoming Aggregation object * /Public concreteaggregate (object[] objarray) { this.objarray = Objarray; } @Override public Iterator createiterator () { return to new Concreteiterator (this); } /** * Value method: Provide aggregation elements to the outside world */public Object getelement (int index) { if (Index < objarray.length) { return objarray[index]; } else{ return null; } } /** * Value method: Provides the size of the aggregation to the outside world * /public int size () { return objarray.length;} }
Abstract Iteration Child role classes
Public interface Iterator { /** * Iteration method: Moves to the first element * /public void firstly (); /** * Iteration method: Move to next element */public void Next (); /** * Iteration method: Is the last element * /Public Boolean isDone (); /** * Iteration method: Returns the current element * /Public Object CurrentItem ();}
specific Iteration child role classes
public class Concreteiterator implements Iterator {//holds the specific aggregation object of the iteration private concreteaggregate agg; Internal index, which records the current iteration to the index location private int index = 0; Records the size of the current clustered object private int size = 0; Public Concreteiterator (Concreteaggregate agg) {This.agg = agg; This.size = Agg.size (); index = 0; }/** * Iteration method: Returns the current element */@Override public Object CurrentItem () {return agg.getelement (index); }/** * Iterative method: Move to the first element */@Override public void () {index = 0; }/** * Iteration method: Is the last element */@Override public boolean IsDone () {return (index >= size); }/** * Iteration method: Move to next element */@Override public void Next () {if (Index < size) {in Dex + +; } }}
Client Class
public class Client {public void operation () { object[] Objarray = {"One", "I", "three", "four", "Five", "Six"};< c6/>//Create aggregation object Aggregate agg = new Concreteaggregate (objarray); The value in the Loop output aggregation object Iterator it = Agg.createiterator (); while (!it.isdone ()) { System.out.println (It.currentitem ()); It.next (); } } public static void Main (string[] args) { Client client = new client (); Client.operation (); }}
The example above first creates an instance of a clustered class and then calls the Factory method Createiterator () of the clustered object to get an iterative sub-object. After the instance of the iteration is obtained, the client begins the iterative process and prints out all the aggregation elements.
meaninga frequently asked question is: Since the white box aggregation has provided the outside world with the traversal method, the client can already iterate on its own, why should the iterative sub-pattern be applied and create an iterative sub-object to iterate? The client can of course iterate on its own, not necessarily requiring an iterative sub-object. However, iterative sub-objects and iterative patterns abstract the iterative process, separating the client as the iterative consumer from the iteration responsibility of the iteration owner, allowing the two to evolve independently. When the kind of aggregation object changes, or the iterative method changes, the iteration as a mediation layer can absorb the change factor, and avoid modifying the client or aggregation itself. In addition, if the system needs to iterate over several different clustered objects at the same time, and the traversal methods provided by these clustered objects are different, it makes sense to use iterative sub-patterns and an external iterative sub-object. Different iterative sub-objects with the same iterative interface handle aggregate objects with different traversal interfaces, allowing the system to use a single, iterative interface for all iterations.
black box aggregation and intrinsic iterative sub-generationIf a clustered interface does not provide a way to modify a clustered element, such an interface is called a
Narrow Interface。 A clustered object provides a wide interface for an iterative sub-object, and a narrow interface for other objects. In other words, the internal structure of a clustered object should be exposed appropriately to the iteration sub-object so that the iterative sub-object can have sufficient knowledge of the clustered object, allowing for iterative operations. However, a clustered object should avoid providing these methods to other objects, because other objects should do this through iterative sub-objects rather than manipulating the clustered objects directly.
In the Java language, the way to implement a dual interface is to design an iterative subclass as an internal member class of a clustered class. Such an iterative child object will be able to access the internal structure of the clustered object as if it were an internal member of the clustered object. A schematic implementation is given below, showing how the structure of this dual interface arises, and the implementation of the iterative sub-pattern after the dual interface structure is used. This scheme, which guarantees the encapsulation of clustered objects and the implementation of iterative sub-functions, is called
black box Implementation scheme。 Since the iteration is a clustered inner class, the iteration child has free access to the clustered elements, so the iteration can implement its own iterative function and control the iterative logic of the aggregation element. Because iterations are defined within a clustered structure, such iterations are also called
The intrinsic iteration (intrinsic Iterator).
ApplicationTo illustrate the details of the black box scheme, a schematic black box implementation is given here. In this implementation, the aggregation class concreteaggregate contains an internal member class Concreteiterator, which is a concrete iterative subclass that implements an abstract iterative sub-interface, while aggregation does not provide a way for the outside world to access its own internal elements.
abstract Clustered Role ClassesThis role specifies the interfaces that all concrete aggregates must implement. Iterative sub-patterns require that a clustered object must have a factory method, the Createiterator () method, to provide an instance of an iterative child object to the outside world.
Public abstract class Aggregate { /** * Factory method, creating an interface for the corresponding iteration sub-object * /public abstract Iterator Createiterator () ;}
Abstract Iteration Child role classes
Public interface Iterator { /** * Iteration method: Moves to the first element * /public void firstly (); /** * Iteration method: Move to next element */public void Next (); /** * Iteration method: Is the last element * /Public Boolean isDone (); /** * Iteration method: Returns the current element * /Public Object CurrentItem ();}
specific clustered Role classesImplements the interface required by the abstract aggregation role, which is the Createiterator () method. In addition, the aggregation class has an internal member class Concreteiterator, which implements the interface specified by the abstract iteration child role, and the Factory method Createiterator () returns an instance of the internal member class.
public class Concreteaggregate extends Aggregate {private object[] Objarray = null; /** * Construction method, the specific contents of the incoming Aggregation object */Public concreteaggregate (object[] objarray) {this.objarray = Objarray; } @Override Public Iterator createiterator () {return new concreteiterator (); }/** * Internal member class, specific iteration subclass */Private class Concreteiterator implements Iterator {//Internal index, record the current iteration to the index location private int index = 0; Records the size of the current clustered object private int size = 0; /** * constructor */public Concreteiterator () {this.size = Objarray.length; index = 0; }/** * Iteration method: Returns the current element */@Override public Object CurrentItem () {return obja Rray[index]; }/** * Iterative method: Move to first element */@Override public void () {index = 0; }/** * Iteration method: Is the last element */@OvErride public boolean IsDone () {return (index >= size); }/** * Iteration method: Move to next element */@Override public void Next () {if (Index < size ) {index + +; } } }}
Client Class
public class Client {public void operation () { object[] Objarray = {"One", "I", "three", "four", "Five", "Six"};< c4/>//Create aggregation object Aggregate agg = new Concreteaggregate (objarray); The value in the Loop output aggregation object Iterator it = Agg.createiterator (); while (!it.isdone ()) { System.out.println (It.currentitem ()); It.next (); } } public static void Main (string[] args) { Client client = new client (); Client.operation (); }}
The example above first creates an instance of a clustered class and then calls the Factory method Createiterator () of the clustered object to get an iterative sub-object. After the instance of the iteration is obtained, the client begins the iterative process and prints out all the aggregation elements.
Iterative sub-pattern benefits
- Iterative sub-patterns simplify the aggregation of interfaces. The iteration has a traversal interface so that the clustered interface does not have to traverse the interface.
- Each clustered object can have one or more iteration sub-objects, and the iteration state of each iteration can be independent of each other. Therefore, a clustered object can have several iterations in progress at the same time.
- Because the traversal algorithm is encapsulated within the iteration child role, the iterative algorithm can be independent of the aggregation role change.
More Design Patterns: 23 design Mode Series
jason0539
Blog: http://blog.csdn.net/jason0539 (reprint please indicate the source)
Recommended sweep code pay attention to the public number, to add color to life
Iterative sub-patterns of Java design patterns