26.3 complete solution
Developers of Sunny software company use the visitor mode to reconstruct the employee data summary module in the OA system, so that the system can easily add new types of visitors, it is more in line with the "single Responsibility Principle" and "open and closed principle". The reconstructed basic structure is 26-3:
In Figure 26-3, fadepartment represents the Finance Department, hrdepartment represents the human resources department, which acts as a specific visitor, and its abstract parent Department acts as an abstract visitor; employeelist acts as an object structure to store the employee list; fulltimeemployee indicates a formal employee, parttimeemployee indicates a temporary employee. They act as specific element roles, and its parent interface employee acts as abstract element roles. The complete code is as follows:
Import Java. util. *; // employee class: abstract element class interface employee {public void accept (Department handler); // receives an abstract visitor access} // full-time employee class: specific element class fulltimeemployee implements employee {private string name; private double weeklywage; private int worktime; Public fulltimeemployee (string name, double weeklywage, int worktime) {This. name = Name; this. weeklywage = weeklywage; this. worktime = worktime;} public void setname (string name) {T His. name = Name;} public void setweeklywage (double weeklywage) {This. weeklywage = weeklywage;} public void setworktime (INT worktime) {This. worktime = worktime;} Public String getname () {return (this. name);} public double getweeklywage () {return (this. weeklywage);} public int getworktime () {return (this. worktime);} public void accept (Department handler) {handler. visit (this); // call the visitor's access method} // part-time employee class: Body element class parttimeemployee implements employee {private string name; private double hourwage; private int worktime; Public parttimeemployee (string name, double hourwage, int worktime) {This. name = Name; this. hourwage = hourwage; this. worktime = worktime;} public void setname (string name) {This. name = Name;} public void sethourwage (double hourwage) {This. hourwage = hourwage;} public void setworktime (INT work Time) {This. worktime = worktime;} Public String getname () {return (this. name);} public double gethourwage () {return (this. hourwage);} public int getworktime () {return (this. worktime);} public void accept (Department handler) {handler. visit (this); // call the visitor's access method} // Department class: Abstract visitor class Department {// declare a set of overloaded access methods, used to access different types of specific elements public abstract void visit (fulltimeemployee employee); public abstract void Visit (parttimeemployee employee);} // Finance Department class: Specific visitor class fadepartment extends Department {// implement finance department's access to public void visit (fulltimeemployee employee) for full-time employees) {int worktime = employee. getworktime (); double weekwage = employee. getweeklywage (); If (worktime> 40) {weekwage = weekwage + (worktime-40) * 100;} else if (worktime <40) {weekwage = weekwage-(40-worktime) * 80; If (weekwage <0) {weekwage = 0 ;}} system. out. Println ("formal employee" + employee. getname () + "actual salary:" + weekwage + "RMB. ");} // Implement the finance department's access to public void visit (parttimeemployee employee) {int worktime = employee. getworktime (); double hourwage = employee. gethourwage (); system. out. println ("temporary" + employee. getname () + "actual salary:" + worktime * hourwage + "RMB. ") ;}}// Human Resources Department: Visitor class hrdepartment extends Department {// enables the human resources department to access public void visit (fulltimeemployee employee) for full-time employees) {int worktime = employee. getworktime (); system. out. println ("formal employee" + employee. getname () + "actual working time:" + worktime + "hour. "); If (worktime> 40) {system. out. println ("formal employee" + employee. getname () + "overtime:" + (worktime-40) + "hour. ");} Else if (worktime <40) {system. out. println ("formal employee" + employee. getname () + "leave time:" + (40-worktime) + "hour. ") ;}}// Enables the human resources department to access public void visit (parttimeemployee employee) {int worktime = employee. getworktime (); system. out. println ("temporary" + employee. getname () + "actual working time:" + worktime + "hour. ") ;}}// Employee list class: object structure class employeelist {// defines a set to store the employee object private arraylist <employee> List = new arraylist <employee> (); public void addemployee (employee) {list. add (employee);} // traverse to access each employee object in the employee set public void accept (Department handler) {for (Object OBJ: List) {(employee) OBJ ). accept (handler );}}}
To improve system flexibility and scalability, we store the class names of specific visitor classes in the configuration file, and read the configuration file and reflect the generated objects through the tool class xmlutil, the xmlutil class code is as follows:
Import javax. XML. parsers. *; import Org. w3C. dom. *; import Org. XML. sax. saxexception; import Java. io. *; Class xmlutil {// This method is used to extract a specific class name from the xml configuration file and return an instance object public static object getbean () {try {// create Document Object documentbuilderfactory dfactory = documentbuilderfactory. newinstance (); documentbuilder builder = dfactory. newdocumentbuilder (); document DOC; Doc = builder. parse (new file ("config. XML "); // get the text node containing the class name nodelist NL = Doc. getelementsbytagname ("classname"); node classnode = NL. item (0 ). getfirstchild (); string cname = classnode. getnodevalue (); // generate an Instance Object using the class name and return Class C = Class. forname (cname); object OBJ = C. newinstance (); Return OBJ;} catch (exception e) {e. printstacktrace (); return NULL ;}}}
The configuration file config. xml stores the class name of a specific visitor class. The Code is as follows:
<?xml version="1.0"?><config><className>FADepartment</className></config>
Write the following client test code:
Class client {public static void main (string ARGs []) {employeelist list = new employeelist (); employee fte1, fte2, fte3, pte1, pte2; fte1 = new fulltimeemployee ("Zhang Wuji", 3200.00, 45); fte2 = new fulltimeemployee ("Yang Guo", 2000.00, 40); fte3 = new fulltimeemployee ("Duan Yu", 2400.00, 38); pte1 = new parttimeemployee ("Hong qigong", 80.00, 20); pte2 = new parttimeemployee ("Guo Jing", 60.00, 18); list. addemployee (fte1); list. addemployee (fte2); list. addemployee (fte3); list. addemployee (pte1); list. addemployee (pte2); Department Dep; Dep = (department) xmlutil. getbean (); list. accept (DEP );}}
Compile and run the program. The output result is as follows:
The actual salary of formal employee Zhang Wuji is 3700.0 yuan. The actual salary of the formal employee Yang Guo is: 2000.0 yuan. The actual salary of formal employee Duan Yu is 2240.0 yuan. The actual salary of temporary worker Hong Qigong is 1600.0 yuan. The actual salary of temporary workers Guo Jing is: 1080.0 yuan. |
If you need to change the visitor class without modifying the source code, you only need to modify the configuration file. For example, to change the visitor class from Finance Department to Human Resources Department, you only need to change the specific visitor class fadepartment stored in the configuration file to hrdepartment, the following code is used:
<?xml version="1.0"?><config> <className>HRDepartment</className></config>
Run the client program again. The output result is as follows:
Formal employee Zhang Wuji's actual working time is: 45 hours. Formal employee Zhang Wuji's overtime time is: 5 hours. The actual working time of the formal employee Yang Guo is: 40 hours. The actual working time of formal employee Duan Yu is 38 hours. Formal employee Duan Yu's leave time is: 2 hours. The actual work time of temporary worker Hong Qigong is: 20 hours. The actual work time of temporary job Guo Jing is: 18 hours. |
If you want to add a new visitor to the system, you don't need to modify the source code. You just need to add a new visitor class, this visitor encapsulates a new method for operating element objects. From the perspective of adding new visitors, the visitor mode complies with the "open and closed principle ".
If you want to add a new specific element to the system, for example, adding a new employee type as "retirees ", because the original system does not provide the corresponding access interface (the abstract visitor does not declare any access method for "retirees"), the original system must be modified, add the corresponding access method to the original abstract visitor class and specific visitor class. From the perspective of adding new elements, the visitor mode violates the "open and closed principle ".
In summary, the visitor mode is similar to the abstract factory mode. The support for the "open and closed principle" is skewed, so that new visitors can be easily added, but adding new elements is troublesome.
[Author: Liu Wei http://blog.csdn.net/lovelion]