China
DW China all content ............... DW China Technology Zone: Component Technology Java Technology Linux XML ............... DW China Special Topics: Safety Unicode Site Architecture ............... IBM full content search help IBM Home | Products & Services | Support & Download | Personalized Services
IBM: DeveloperWorks China website: Java: All articles
Use design pattern to improve program structure (2)
content:
Retrospective Description Problem Analysis Solution Conclusion Reference About the author
Deng Hui, Sun Ming (DHUI@263.net)
software engineer
In this series
In the first article, how to guide our program reconstruction processes through design patterns, and focus on the importance of design mode integration and motivation. In this article, we will continue to discuss the article, this time mainly focused on the applicability of design patterns, the mastery of design mode applicability helps to determine if a design pattern is truly suitable for us from another different aspect Actual problem, thus making wise choices.
1. Review In the previous article, we give an example of using design patterns to improve the program structure, focusing on the intention of design patterns, motivation in our program reconstruction process. Now, we will pay attention to another important aspect of the design model: the applicability of design mode. Solving the same problem generally have multiple programs or patterns, but these modes are concerned with different aspects of the same problem, solve different needs, have their own advantages and restrictions, each has its own solutions. This requires us to have a good understanding of our own problems when choosing design patterns: What is our needs, what kind of features we have to overcome? Then you can see if we want to use the problem of design mode applies to our problem. If you don't apply, you can use other modes to make up, you can improve this design pattern to make it meet our requirements. In this section, we will further analyze the final solution in the previous article, to see what kind of demand we meet, what kind of shortcomings are exposed, and finally we will give a more In order to meet the requirements. 2. Problem Description In the previous article, we reconstructed the code of the error handling section in a network management system, and finally used a Visitor design pattern to solve our problem. The careful readers will definitely find a problem like this final program: if the type of error is not fixed, but the result of the system is increasing, what results? Let's take a look at the final class chart in the last article:
In this class diagram, I added a number of dependencies, ie ERRORHANDLERs are dependent on DBERROR and COMMERROR. At this point we can see: ErrorBase depends on Errorhandler, Errorhandler depends on ErrorBase's derived class (DBERROR and Commerror), and ErrorBase's derived class is dependent on ErrorBase itself. This forms a loop dependency process, which is the ERRORBASE depends on all of its derived classes. This cycle dependency will bring serious problems. Once ErrorBase has added a derived class, then Errorhandler classes must be modified. Because ErrorBase rely on Errorhandler, all classes depend on ERRORBASE need to recompile. This means that all of ErrorBase's derivatives and all these derived users must recompile. This large-scale recompilation will lead to very much workload when developing a distributed system, because it is to be re-distributed Re-compiling the class, if there are some errors when reset (such as: Forget some classes), you will cause subtle errors, and it is not easy to find. In addition, there is a hypothesis that there is a hypothesis that any error handler is to handle all the error types, this assumption is not established in some cases, such as: If we don't intend to notify Logsys if we don't intend to notify Logsys for LogSys? ? We have to write an empty function that handles the error (of course you can write a default implementation in Errorhandler). If ErrorBase's class hierarchology is getting bigger, and the processing methods they require, it will lead to a large number of methods in the Errorhandler interface, and any ErrorBase's derived class change will lead to large-scale recompilation. (Even if there is no relationship, it is also recompiled), re-distribution, if this change is more frequent, the result is of course unbearable. 3. Problem Analysis The above problem description exposed some of the usage restrictions of the Visitor mode, ie, which applies only to the accessible class hierarchical architecture, resulting in such reasons to use a famous object-oriented design principle to explain, This principle is: DIP (Dependency Inversion Princi), the core meaning of this principle is that the high-level module should not directly depend on the low-level module, and all modules must depend on abstraction. That is to say: something that is easy to change must depend on something that is not easy to change, because abstract things are not easily changed, the specific thing is easy to change, so specific should depend on abstraction. In Visitor mode, Errorhandler depends on all specific derived classes of ErrorBase, and if these derived classes are easy to change, they will result in unacceptable results. With the above analysis, you can see the key to interrupting this loop dependent loop to overcome the scope limit for the Visitor mode. 4, the solution in the above-mentioned cycle dependencies, two dependencies are unable to interrupt, one is the dependence of ErrorBase's derived class for ERRORBASE, and the ErrorBase is dependent on ERRORHANDLER, and these two dependencies are also In line with DIP, we must interrupt the only dependency, this relationship is that ErrorHandler's dependence on ErrorBase all derived classes, and this relationship is also violating DIP.
If we don't let Errorhandler know the derived class of ErrorBase, how can it be handled for each specific ErrorBase derived class? Object-oriented Master Robert C. Martin gives an elegant solution. The skills he use is recommended by the OO method to avoid use, RTTI (runtime type identification). It can be seen that if the RTTI is properly used, it can get a good design, and can also overcome some problems that can solve the plurality of methods in OO (of course, if the problem can be solved using polymorphism, it is recommended or used by polymorphism solve). Let's take a look at this solution: It can be seen by the above figure, there is no method in Errorhandler, which has been degraded into an empty interface, so it is impossible to rely on any ErrorBase derived class. Unlike the Visitor mode, this scheme defines a corresponding processing interface for each particular ErrorBase, in the Handle method implementation of each derived class, using RTTI technology to perform the corresponding type conversion (convert ErrorHandler to own Error handling interface, such as: In the handle method of DBERROR, transform ErrorHandler to DBERRORHANDLER.JAVA is doing well in this regard, can perform comparison type conversion), you want to handle the error to implement Errorhandler interface It also achieves the corresponding processing interface for specific error classes, such as GuISYS, implements three interfaces (Errorhandler, Dberrorhandler, and Commerrorhandler), thereby implementing processing of DBERROR and COMMERROR. This method interrupts the cyclic dependencies between classes, making it easy to increase new error types and avoid large-scale recompilation and reset of classes. Also, you can also choose the wrong process, such as: If Guisys does not want to handle DBERROR, it is simple, do not implement the DBERRORHANDLER interface, so that the structure of the program is very clear. It can be seen that this program overcomes the shortcomings of the original Visitor design model. It can be seen by comparing two classes in the upper and lower classes. The following is complicated than the above, which is also a disadvantage of the program. If the problem is small, it is still possible to use the original Visitor mode if the problem is not large, recompile and reset it. This scenario is considered when the size of the problem cannot be applied to the scale of the problem. In addition, the use of RTTI techniques in the improved scheme can lead to loss of performance and unpredictability, special attention in use. We do the following levels to facilitate better understanding the original Visitor mode and the improved solution. The original Visitor mode seems to be a matrix, which is a specific error type in the X direction. In the Y direction, it is an entity that can handle errors. Each intersection is a specific processing method, and each location in the matrix. There must be a processing method. The improved solution is like a sparse matrix, only has a specific processing method in the required position, thereby reducing a lot of redundancy. The key code segment is given below:
Interface Errorbase
{
Public void Handle;
}
Class DBERROR IMPLEMENTS ERRORBASE
{
Public void handle (ERRORHANDLER HANDLER) {
Try {
DBERRORHANDLER DBHANDLER = (DBERRORHANDAL) HANDLER; DBHANDLER.HANDE (this);
}
Catch (ClassCastException E) {
}
}
}
Class Commerror Implements ErrorBase
{
Public void handle (ERRORHANDLER HANDLER) {
Try {
Commerrorhandler CommHandler = (Commerrorhandler) Handler;
CommHandler.handle (this);
}
Catch (ClassCastExce E) / {
}
}
}
Interface Errorhandler
{
}
Interface DBERRORHANDLER
{
Public Void Handle (DBRROR DBERROR);
}
Interface Commerrorhandler
{
Public void handle (Commerror Commeror);
}
Class Guisys Implements Errorhandler, DBERRORHANDAL, Commerrorhandler
{
Public void Announceerror (ErrorBase Error) {
Error.handle (this);
}
Public void handle (dberror dberror) {
/ * Notify the user interface to process the relevant database error processing * /
}
Public void handle (commerror) {
/ * Notify the user interface for processing related to communication errors * /
}
}
Class Logsys Implements Errorhandler, Dberrorhandler, Commerrorhandler
{
Public void Announceerror (ErrorBase Error) {
Error.handle (this);
}
Public void handle (dberror dberror) {
/ * Notification Log System Performs Database Error Processing * /
}
Public void handle (commerror) {
/ * Notification Log System for processing related to communication errors * /
}
}
5. Conclusions This article uses the applicability of design patterns, and explores how to select reconstructed targets at the time of program reconstruction, and how to improve our goals in the existing design model. The main purpose of this article is to explain that when the design mode is selected, it is necessary to pay attention to the design mode, but also to pay any constraints and restrictions when using this design pattern. This will help you better understand the problem, make reasonable gains, or you can modify your requirements according to your needs, if you do this, you are likely to create A new design pattern. References [1] Design Patterns, Gamma, et. Al., Addison Wesley [2] Design Principles and Design Patterns, Robert C. Martin, www.objectmentor.com [3] Refactoring To Patterns, Joshua Kerievsky, industriallogic.com [ 4] The Visitor Family of Design Patterns, Robert C. Martin, www.Objectmentor.com
Page