View the design mode from the Java class library (4)

Source: Internet
Author: User

In the previous section, we introduced two structural models: bridge and decorator. The content of this part will be explained above to continue our design model journey.

In addition to a structured composite model, this section also introduces two behavior models. In fact, we have come into contact with the behavior patterns in the previous content: observer and command are two typical behavior patterns. The behavior pattern focuses more on the assignment of duties between algorithms and object creation. That is to say, it focuses more on the semantics of object collaboration, such as the pattern system, and control the communication between objects.

Composite Mode

Undoubtedly, the component-container system in AWT is an example of a good composite mode. The container inherits from component, while the container can contain multiple component. Because the container is actually a component, the container can also contain the container. In this way, the component-container structure is combined to form a tree hierarchy. This is what the composite mode needs to do.

The composite mode is proposed to simplify programming. In general programming, If you strictly distinguish component and container, it may cause a lot of inconvenience, and these are often unnecessary. For example, if I want to place a component in a iner, I don't need to know whether the component is a container or a general component. What I need to do in the parent container is, only record reference of a component, and call the component draw method to display this component as needed. When the component is indeed a container, it can display the container by using the iner reload method, and pass the draw message to its sub-object. That is to say, for a parent container, it does not care about whether its sub-object is a component or a iner. It must treat component and container in a unified manner.

Figure 11: class diagram in composite mode
 

The composite mode is relatively simple and not complicated to implement, but it has some limitations. For example, when processing a tree, we often need to process three types of objects: Subtrees, page nodes, and non-page nodes. In composite mode, the distinction between Subtrees and non-leaf nodes is not obvious. Instead, they are merged into a composite object. In the composite mode provided by gof, methods for adding and deleting sub-nodes that belong to the composite object are placed in the component object, although they can be distinguished during implementation, but it is easy to cause some conceptual misunderstandings.

As described above, we can propose an improved composite mode to introduce the subtree object to separate the subtree from the non-leaf node, as shown in:

Figure 12: a variation of the composite mode

Although composite is separated from the component class hierarchy, it does not compromise the connotation of the composite mode. This is not necessarily better than the one above, but it has different applications. However, sometimes it is easier to use this method to process Subtrees, and its concept is clearer.

The following code provides a simple JAVA Implementation of the composite mode:

Public abstract class component {
Public abstract void operation ();
Public void add (Component component ){};
Public void remove (Component component ){};
}
Import java. util .*;
Public class composite extends component {
String name;
Arraylist children = new arraylist ();
Public composite (string name ){
This. Name = Name;
}
Public void add (Component component ){
Children. Add (component );
}
Public void remove (Component component ){
Children. Remove (component );
}
Public void operation (){
System. Out. println (name );
Iterator = children. iterator ();
While (iterator. hasnext ()){
Component child = (Component) iterator. Next ();
Child. Operation ();
}
}
}
Public class leaf extends component {
String name;
Public leaf (string name ){
This. Name = Name;
}
Public void operation (){
System. Out. println (name );
}
}

Strategy Mode

The Strategy Mode is mainly used to separate algorithms from classes and encapsulate them in a separate class. To put it simply, the two closely related parts of the object and its behavior (behaviour) are decoupled and placed in two different classes respectively. This allows you to easily switch between different implementation algorithms at any time for the same behavior. By encapsulating policies, a unified interface is provided for them, and new policies can be easily introduced.

Layoutmanager of AWT is an example of the Strategy Mode. For the GUI, each component (Component) needs to follow certain algorithms for emissions from containers. The general method is to use absolute coordinates, as shown in tools such as VB and Delphi, to record the position of each component in the container. This will certainly cause some problems. For example, when scaling the form, you need to manually encode and change the size and position of the component to save the original proportion. In AWT, layoutmanager is introduced to greatly enrich layout methods and simplify the coding process.

A container, such as Applet and panel, only records the components it contains. The layout manager encapsulates the algorithm for layout components in the container. Specifically, indicates the position and size of components in the container. With the layout manager, you only need to determine the relative location between the components you want to place. This simplifies coding and helps achieve platform independence of the software.

Figure 13: Relationship between containers and layout manager in AWT

Each container has a layout manager. When the container needs to deploy its components, it calls the layout manager method to deploy the components in the container. Layoutmanager2 is inherited from layoutmanager and provides more detailed layout functions. It allows the layout manager to add constraints to the components and determines how the components are arranged. For example, borderlayout adds a direction indication to its component to determine the position of the component placed in the border.

In particular, you can easily implement custom Layout policies by implementing the layoutmanager or layoutmanager2 interface.

Back to the topic of pattern, if there are several very similar classes, the difference is only that the actions on individual behaviors are different, then you can consider using the strategy pattern. In this way, multiple classes are reduced to one class with multiple policies through policy combination. This is in line with the OO design principle: Find the changed part and encapsulate it! The Strategy Mode also provides a good alternative for subclass inheritance. When the inheritance mechanism is used, the behavior changes are static. You mean that the behavior can be changed once-and the policy is dynamic, you can change the number of times at any time. More importantly, policy objects can be shared by different objects in different environments. Taking the layout manager as an example, although each container has only one layout manager, one layout manager can work for multiple containers.

Figure 14: class diagram of the Strategy Mode

The Strategy Mode also has some disadvantages. For example, an application must know all the policy objects and select one from them. When a policy object is used, it is usually tightly coupled with the context object. The context object must provide the policy object with data related to specific algorithms or other things, however, the transmission of such data may not be able to load abstract policy classes, because not all algorithms need such data. In addition, because the policy object is usually created by the application, the context object cannot control the lifecycle of strategy. In terms of concept, this policy should belong to the context object, its life cycle should not be beyond the range of context objects.

Usually, strategy is easily confused with the bridge mode. Indeed, they have similar structures, but they are designed to solve different problems. The Strategy Mode focuses on algorithm encapsulation, while the Bridge Mode focuses on separating abstraction and implementation, providing different implementations for an abstract system.

Iterator Mode

The iterator mode is used to normalize the traversal interface of a data structure.

The iterator interface is introduced in the Collection framework in JDK to provide traversal of a collection. Each collection class defines the iterator () method inherited from the collection interface to obtain an iterator object, which is called a traversal device. The iterator interface is simple:

Hasnext (): used to determine whether there is another element in the traversal.

Next (): returns the next element in the traversal.

Remove (): Delete the last returned object in the retrieved collection class.

Let's take the most common vector as an example to see how the iterator mode is implemented in the Collection framework. Before that, we need to understand the structure of vector and collection framework.

As the basis of this framework, the collection interface is inherited or implemented by all other collection classes. A basic implementation of the collection interface is the abstract class abstractcollection, which implements most of the operations unrelated to the specific data structure. For example, to determine whether an object exists in the ins () method of this collection class:

Public Boolean contains (Object O ){
Iterator E = iterator ();
If (O = NULL ){
While (E. hasnext ())
If (E. Next () = NULL)
Return true;
} Else {
While (E. hasnext ())
If (O. Equals (E. Next ()))
Return true;
}
Return false;
}

The iterator () method called here is an abstract method, which depends on the implementation of the specific data structure. However, for this containers () method, you do not need to know the specific iterator implementation. Instead, you only need to know the interfaces It provides to complete certain types of tasks, this is the role of abstract methods in abstract classes. Most other non-abstract methods implemented in abstractcollection depend on the iterator interface provided by the abstract method iterator. This design method is the key to introducing abstract classes and deserves careful understanding.

The list interface inherits the collection interface and provides abstraction for the list collection class. The corresponding abstractlist class inherits abstractcollection and implements the list interface as an abstract base class of list. It implements non-abstract methods, which is similar to abstractcollection.

Corresponding to the iterator of collection, list has its own listiterator. listiterator inherits from iterator and adds some methods dedicated to list traversal:

Boolean hasprevious (): determines whether an element exists before the current element in the list.

Object previous (): returns the element before the current element in the list.

Int nextindex ():

Int previusindex ():

Void set (Object O ):

Void add (Object O ):

Listiterator provides more powerful functional interfaces for list. In abstractlist, The iterator () method and listiterator () method are implemented. Let's take a look at how these two methods are implemented:

Public iterator (){
Return new itr (); // itr is an internal class
}
Private class itr implements iterator {
Int cursor = 0; // The iterator counter, indicating the position of the element to be returned when the next () method is called.
Int lastret =-1; // indicates the position of the element returned by the next () or previous () method,-1
// Indicates that the remove () method is called to delete an element.
// Modcount is a field defined in abstractlist, indicating the number of times the list has been modified. Iterator uses the // value to check whether the encapsulated list is illegally modified by other methods.
Int expectedmodcount = modcount;
Public Boolean hasnext (){
Return cursor! = Size ();
}
Public object next (){
Try {
// The get method is still an abstract method, depending on the specific subclass implementation
Object next = get (cursor );
// Check whether the list is incorrectly modified
Checkforcomodification ();
Lastret = cursor ++;
Return next;
} Catch (indexoutofboundsexception e ){
Checkforcomodification ();
Throw new nosuchelementexception ();
}
}
Public void remove (){
If (lastret =-1)
Throw new illegalstateexception ();
Checkforcomodification ();
Try {
// Remove (INT) also depends on the specific subclass implementation.
Abstractlist. This. Remove (lastret );
If (lastret <cursor)
Cursor --;
Lastret =-1;
Expectedmodcount = modcount;
} Catch (indexoutofboundsexception e ){
Throw new concurrentmodificationexception ();
}
}
Final void checkforcomodification (){
If (modcount! = Expectedmodcount)
Throw new concurrentmodificationexception ();
}
}

The design skills here are the same as above. They all use abstract methods to implement a specific operation. Abstract methods, as the final implemented content, depend on specific sub-classes. An abstract class looks like a thing between an interface and a subclass.

In terms of design, it is suggested that all classes should be defined as interfaces. This is of course true, but it is somewhat extreme. When you need the maximum flexibility, you should use interfaces, while the abstract class can provide some default operations to unify subclass to the maximum extent. Abstract classes play an important role in many application frameworks. For example, in a framework, abstract classes can be used to implement some default services, such as message processing. These abstract classes allow you to easily and naturally embed your applications into the framework. For methods that depend on the specific implementation of each application, you can introduce them to the framework by defining abstract methods.

In fact, there is a similar concept in the old JDK version, called enumeration. In fact, iterator is similar to enmeration, but it only has more Delete functions. Iterator is more appropriate in terms of names. Another important function of the model is to form a language (or culture) for communication ). Sometimes, when you say enumeration, you don't understand it. If you say it, iterator will understand it.

Summary:

This section describes three modes: composite, strategy, and iterator. Composite is a structured model used to coordinate the relationship between the whole and the local, so that it can be uniformly arranged in a tree structure and simplify programming. The Strategy Mode is similar to the Bridge Mode in structure, but unlike the bridge mode, it is a behavior mode that focuses more on the Structure semantics and algorithm implementation. It allows the program to freely and conveniently choose between different algorithms and switch to other algorithms at runtime, greatly increasing the flexibility of the program. The iterator mode provides unified interface operations to traverse a data structure, so that the customer Code does not need any changes when the internal algorithms of the data structure change, you only need to change the corresponding iterator implementation to seamlessly integrate it into the original program.

References

  • Design Model: Reusable Basic Machinery Industry Press for Object-Oriented Software

  • Java2 class library supplemental version Machinery Industry Press
  • Java2 graphic design: AWT volume Machinery Industry Press
  • Visual Object-Oriented Modeling Technology Beijing University of Aeronautics and Astronautics Press
  • Dk1.3 source code
  • UML User Guide Mechanical Industry Press

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.