|
|
content: |
|
preface |
overall structure overview |
abstractfactory mode and scalability |
proxy mode and permission Control |
decorator mode and filter |
iterator mode and Forum browsing |
references |
about the author |
|
|
Liu Wudong (wdliu@chinaren.com) November 2001 Preface Jive is an open JAVA SourceCodeProject. The goal is to build an open-structured, strong, and scalable JSP-based forum. Under the guidance of its design objectives, its structure is well designed, integrating many new ideas, such as design pattern, replaceable skin, and pluggable plug. Interpreting the source code in detail is helpful for understanding these new design concepts. If you have some knowledge about design pattern and Java, but you are still confused about it, you may wish to study the source code of jive, we will certainly have a deeper understanding of many of these concepts. This articleArticleMy jive source code research notes hope to outline and lead everyone into this beautiful world. Of course, if you don't have time to read the source code carefully, I think it will be helpful to read this article. Before we start, we need to point out that the application of design pattern in jive is not subject to the implementation method given in the gof book, but there are many alternatives. On the one hand, I think it is because of actual needs. On the other hand, I think this is also the result of the evolution of design concepts. Therefore, these changes will be the focus of my explanation. Overall structure Overview Based on an OO design principle: interface-oriented programming, rather than implementation programming. During the design of jive, most of its basic objects are designed as interfaces or abstract classes. In jive, basic interfaces include Forum, forummessage, forumthread, group, user, authorization, and query. We can easily know their functions from the names of these interfaces. The following class diagram shows some static relationships between these classes: Figure 1: Overall jive relationship You may have doubts, why are all interfaces? This is based on scalability considerations. In the implementation provided by jive, all these interfaces, forum, forummessage, and user, are implemented by the database. One message, or a user corresponding to a message in the database, jive uses dbforum, dbforummessage, dbuser and other classes to implement these interfaces, and uses JDBC to operate the database, making it the underlying support of the Forum. However, sometimes we may not want to use databases. For example, we want to use a file system as the underlying support of the Forum. At this time, all we need to do is encode and implement objects such as filefroum and fileforummessage for the Forum and other interfaces, and then embed them into the jive. You don't need to change any original code !!! This is the power of interface-oriented programming! Let's take a look at the specific design and coding. Abstractfactory mode and scalability To achieve better scalability, The abstractfactory mode is indeed a powerful tool. As mentioned above, if you want to create different implementations of the Forum interface without changing the code, you need to use the abstract factory. In jive, The authorizationfactory class is an abstract class used to create an authorization object. This is an abstract factory. You can use different subclasses to create different authorization objects. The implementation method of this factory is: Use a private static variable factory in authorizationfactory to reference an instance of a specific Abstract Factory:
Private Static authorizationfactory factory = NULL; Use a Private Static string to specify the subclass Class Name of the specific Abstract Factory:
Private Static string classname = "com. coolservlets. Forum. database. dbauthorizationfactory "; then, a Private Static loadauthorizationfactory method is used to assign values to the factory variable to generate a specific abstract factory class:
Private Static void loadauthorizationfactory () {If (factory = NULL) {synchronized (classname) {If (factory = NULL) {string classnameprop = propertymanager. getproperty ("authorizationfactory. classname "); If (classnameprop! = NULL) {classname = classnameprop;} Try {Class C = Class. forname (classname); factory = (authorizationfactory) C. newinstance ();} catch (exception e) {system. err. println ("exception loading class:" + E); E. printstacktrace () ;}}}} |
When the static getauthorization method returns an authorization, initialize the factory-class factory variable and create it using the createauthorization method of the factory:
Public static authorization getauthorization (string username, string password) throws unauthorizedexception {loadauthorizationfactory (); Return factory. createauthorization (username, password );}
|
Different subclasses have different createauthorization methods. For example, in the database implementation subclass of the authorizationfactory dbauthorizationfactory, The createauthorization method is implemented as follows:
Public Authorization createauthorization (string username, string password) throws unauthorizedexception {If (username = NULL | Password = NULL) {Throw new unauthorizedexception ();} Password = stringutils. hash (password); int userid = 0; connection con = NULL; preparedstatement pstmt = NULL; try {con = dbconnectionmanager. getconnection (); pstmt = con. preparestatement (Authorize); pstmt. setstrin G (1, username); pstmt. setstring (2, password); resultset rs = pstmt.exe cutequery (); If (! Rs. next () {Throw new unauthorizedexception ();} userid = Rs. getint (1);} catch (sqlexception sqle) {system. err. println ("exception in dbauthorizationfactory:" + sqle); sqle. printstacktrace (); throw new unauthorizedexception ();} finally {try {pstmt. close ();} catch (exception e) {e. printstacktrace ();} Try {con. close ();} catch (exception e) {e. printstacktrace () ;}return new dbauthorization (userid );}
|
In this class, we can see the relationship between abstract classes and specific sub-classes, how they work together, and how to divide abstract methods and non-abstract methods. This is worth noting. In general, abstract methods need to be implemented by subclasses, while non-abstract methods in abstract classes should be shared by all subclasses, or they are high-level methods defined on abstract methods. This is indeed a good example of an abstract factory! Although the implementation method has been far different from the implementation in gof, the idea has not changed. The implementation here is indeed clever. There is also the use of static methods, which makes this class look somewhat Singleton. This makes it easy to create abstractfactory. The following class diagram shows the overall implementation of the abstractfactory: Figure 2: Implementation class diagram of abstractfactory Mode Other methods defined in authorizationfactory refer to how to create authorization as abstract methods. The specific implementation is left to the subclass. In this way, when you need to generate an authorization, you only need to call the static method getauthorization of authorizationfactory. The sub-class implements the specific details. Others, as mentioned above, the forumfactory used when creating the Forum has the same implementation as above. This is why the mode is called the mode. Proxy mode and permission Control Proxy mode has many functions, such as remote proxy, which is used to provide a local representation for remote objects; virtual proxy, which is used to buffer the creation of large overhead objects, and so on. In jive, protection proxy is used to provide permission Control for protected objects. We all know that permission control is required in a forum. Otherwise, the Forum may be messy. The proxy object, authorization interface, and permission descriptive class are introduced in jive to provide protection for the Forum. Taking forumfactory as an example, an additional forumfactoryproxy is used to process permission authentication. It provides a proxy for a forumfactory to ensure that only authorized users can access some operations of forumfactory. In fact, forumfactory is not just a forum generation class here, it is more like a forum management class. A series of functions are provided, such as adding, deleting, and enumerating. Some functions are not available to anyone, so another proxy class is introduced to handle permissions. Of course, the proxy class must inherit forumfactory to make the method signature consistent:
Forumfactoryproxy extends forumfactory In its constructor, A forumfactory object is provided, which is the object to be proxy; an authorization object that provides user information; and a forumpermissions that provides authentication information:
Public forumfactoryproxy (forumfactory factory, authorization, forumpermissions permissions) {This. Factory = factory; this. Authorization = Authorization; this. Permissions = permissions ;}
|
The general proxy process is like this. Before accessing a method, you must accept the permission check. Take createforum as an example:
Public Forum createforum (string name, string description) throws unauthorizedexception, forumalreadyexistsexception {If (permissions. get (forumpermissions. system_admin) {Forum newforum = factory. createforum (name, description); return New forumproxy (newforum, authorization, permissions);} else {Throw new unauthorizedexception ();}}
|
The class diagram of this mode is shown below: Figure 3: proxy pattern class diagram The implementation of this mode is basically the same as the implementation in gof. In jive, almost all interfaces, such as forum, forummessage, and forumthread, have a corresponding proxy object for permission control. When creating a specific object, the corresponding proxy object is used to replace the original object. For example, when the forumfactory getinstance () method needs to return a forum, jive does this:
Public static forumfactory getinstance (authorization) {... forumfactoryproxy proxy = new forumfactoryproxy (factory, authorization, factory. getpermissions (authorization); Return proxy ;}
|
Therefore, all created objects are actually proxy objects. The Abstract Factory ensures that objects without permission verification will not be obtained by the customer at all. They will only assume roles within the proxy, but it will never be accessed by external objects. In this way, the security of the Forum is fundamentally guaranteed. Decorator mode and filter Generally, in the OO design, the addition of external functions is implemented through inheritance, but inheritance is sometimes not flexible enough, and when there are many combinations of functions, the inherited sub-classes will grow in Geometric Order, making it difficult to control many classes. Based on this consideration, the decorator model was born. The decorator mode encapsulates a specific operation. When an object requires this operation, add the decorator. In addition, multiple decorator can be combined to provide more functions. In jive, the decorator mode is applied to some filters. Filter re-constructs the content of the forummessage object. For example, when a forummessage object flows through a filter named filtercodehighlight, all Java source code text in the message will be re-constructed into a message with syntax highlighted. For example, when a message highlighted by syntax flows through a filter named filterhtml, the HTML segment in the message will be annotated to display text inside the HTML, this prevents abnormal page display after you enter HTML control labels. In jive, all the filters inherit from an abstract class forummessagefilter, while forummessagefilter implements the forummessage interface. That is to say, each filter is actually a forummessage object. Forummessagefilter also encapsulates a forummessage object. The method for filtering is simple. getbody () is used, for example, in the filtercodehighlight class:
Public String getbody () {return highlightcode (message. getbody ());}
|
Highlightcode is a private method that implements specific filtering details. The getbody () method is actually defined in the forummessage interface. When the getbody () method of the filter is called, The forummessage object after structure reorganization can be obtained. This object can be referenced by other customers or be passed to another filter for further operations. When a specific message is filtered, The addforummessagefilter () and applyfilters () methods in Forum are used to apply the filter. For a forum, when addforummessagefilter () method is used to add a filter, no specific message is specified, but only a rule (filter encapsulates the filter rules), and then applyfilter () to implement these rules:
Public forummessage applyfilters (forummessage message) {// loop through filters and apply them for (INT I = 0; I <filters. length; I ++) {message = filters [I]. clone (Message) ;}return message ;}
|
The clone () method of the filter to copy the message body. The use of this method separates the initialization process for message bodies and filter rules in the filter. This is also a useful technique! The following is a class diagram of the decorator mode: Figure 4: class diagram of the decorator Mode We can see that the decorator mode is actually very similar to the proxy mode, but they represent two different functional meanings. The proxy mode provides an object control, while the decorator mode provides additional functions for the object. Iterator mode and Forum browsing The iterator mode is used to separate data structures and traverse data.AlgorithmTo reduce the coupling between the two, so that the same data structure can still have the same interface through different algorithms. On the other hand, the iterator mode allows when the traversal algorithm is changed, no need to changeProgram. In Java JDK, an iterator interface is defined. In the iterator interface, only three methods are defined. hasnext () determines whether to traverse the last element. Next () method returns an object in the data structure to be traversed. If you remove (), the current object is deleted. In jive, The iteratorproxy abstract class inherits this interface. Here, the proxy has the same meaning as above. That is to say, this iteratorproxy will implement iterator's traversal function, and also has the proxy permission control function. The basic objects Forum, forumthread, forummessage, group, and user in the Forum have corresponding traversal devices. For example, the Forum interface has a forumiteratorproxy object. The forumiteratorproxy traversal is equivalent to a collection class that encapsulates a series of Forum objects. The defined interfaces hasnext () and next () can be used to easily traverse the set, you do not need to know how to traverse this set. Traversal Algorithms may be simple and complex, but they are no different for external customers. The specific Traversal method in the Forum depends on the specific implementation. In jive, the database implementation is provided. The following uses messageiteratorproxy as an example to describe how to use the iterator mode. The dbthreaditerator object implements the iterator interface. It is used to traverse all messages in a thread. Let's see how it is implemented. Hasnext () determines if there is another message in this thread:
Public Boolean hasnext () {If (currentindex + 1> = messages. Length) {return false;} return true ;}
|
The next () method extracts the next message from the database and in this thread:
Public object next () throws java. util. nosuchelementexception {forummessage message = NULL; If (nextmessage! = NULL) {message = nextmessage; nextmessage = NULL;} else {message = getnextmessage (); If (Message = NULL) {Throw new Java. util. nosuchelementexception () ;}} return message ;}
|
In this way, through database operations, dbthreaditerator implements the method of traversing all messages in a thread. Then, the forumthread Interface contains the messages () method, which returns an iterator of all messages in this thread, which actually returns a set of messages:
Public iterator messages (); This method is implemented in dbforumthread:
Public iterator messages () {return New dbthreaditerator (this );} The returned result from the messages () method of dbforumthread is a traversal of all the messages in this thread. With this traversal tool, we can access all the messages in the thread. Of course, the process is not complete yet. Due to permission issues, we also need to construct the proxy object of the traversal server, and then access the traversal through this proxy object. The following class diagram shows how to implement the iterator mode in jive: Figure 5: Implementation of the iterator mode in jive In jive, message is organized in a tree structure under a thread. Therefore, when the relationship between messages in a thread needs to be displayed in a hierarchy, it is not enough to use the linear iterator mentioned above. In this case, the treewalker interface is introduced to promote the concept of iterator. As the name suggests, treewalker provides a method to traverse a tree and access a node on the tree:
Public interface treewalker {public forummessage getroot (); Public forummessage getchild (forummessage parent, int index); Public int getchildcount (forummessage parent); Public int getrecursivechildcount (forummessage parent ); public int getindexofchild (forummessage parent, forummessage child); Public Boolean isleaf (forummessage node );
|
Treewalker is just a simple extension of iterator and is not as widely used as iterator. It can also easily be used to set up an iterator layer on treewalker, let it exercise the iterator's responsibilities in some situations. I will not discuss it more here. In addition, all the design patterns involved in jive design are basically finished. After reading it, do you have a better understanding of the design patterns? The content in the next part will involve the specific encoding and go deep into the JSP. We will see how the replaceable skin is implemented in jive, it also involves some content of the tag library. Okay, this is the time. See you next time. Resources
- Www.jivesoft.com jive source code v1.2.4
- Design model-the basis for reusable object-oriented software, Mechanical Industry Press
- Www.java.sun.com JDK 1.3 source code
About the author Liu Wudong: 2001 graduate student at the School of Computer Science, Wuhan University. Research Direction: Reusable Component technology and design pattern. |
|