Application of design patterns in actual projects
SummaryThe leader designs and implements an osgi-based architecture. Different functional modules are integrated into the system as plug-ins. Because ibatis is used, the injection of different modules produces a requirement. A manager is required to manage ibatis configuration files to dynamically load and uninstall different modules. This task is handed over to me.
Requirement AnalysisHibernate supports the integration of configuration files. However, I have not found the corresponding solution for ibatis. This manager needs to integrate, separate, and dynamically generate sqlmapclient and daomanager configuration files, and print logs after corresponding operations, it is even necessary to provide high flexibility and scalability for users who use this manager. Users may only register (deregister) modules, but do not immediately update sqlmapclient and daomanager. Therefore, the manager needs to cache some operations and information.
Design and ImplementationAfter a new module is injected, notify the manager to determine whether to reload the new configuration file and replace the current sqlmapclient and daomanager instances based on the conditions. After registration, you must re-generate the three phases of the instance before deregistering. Different events must be handled. This process can be followed by event listening on buttons in swing. Add listeners to the manager. Different listeners have different functions. The functions are customized by the user. The manager only executes the methods on a specific listener. This will provide customers with great flexibility. The observer pattern enters our field of view. The key to this mode is that the manager does not need to know who triggered the event and how to handle the event. Its responsibility is to complete the XML registration, logout, and update of two objects. When the manager calls different methods, it iterates the registered tracker to trigger different events of the tracker. If you want to add different events to the Manager (such as adding log output, verification, and whatever), you only need to add tracker with different functions to the manager after triggering different events of the manager. You do not need to change the object to be observed (manager ). Adding a tracker does not require changing the observer. This process is similar to adding multiple buttons to the Panel. You do not know the operation panel that each button completes. When a button is triggered, the button will complete a custom operation. Different operations will not change the Panel logic. The change is just a different adapter. Can the observer pattern be used to solve all the problems? The answer is no. There are two problems. When you call the manager method to obtain sqlmapclient and daomanager: 1. How to determine whether the sqlmapclient and daomanager need to be updated; 2. How to Make sqlmapclient, how does daomanager adjust updates? We can use another mode to solve the above problem: the proxy pattern acts as a proxy for sqlmapclient and daomanager; the event-driven reset of sqlmapclient and daomanager. Proxy is used to replace the latest sqlmapclient and daomanager objects in the system with existing instances. In addition, the corresponding events are implemented during the update or different events are provided. The manager can use transparent proxy to make the customer feel the changes of sqlmapclient and daomanager instances. Specific Interface Design: public interface isqlmapbuildermanager {...... /*** This method triggers the aftersqlmapconfigregistered of Tracker after registering the SQL map configuration information. * If the registration causes reconstruction of the client or daomanager (determined by isautorebuild ), * The tracker's aftersqlmapclientrebuild/resume ** @ Param ID * configuration ID * @ Param inputstream * configuration information input stream */Public void registersqlmapconfig (Object ID, inputstream) throws ibatisbuildexception; /*** this method triggers beforesqlmapconfigunregistered of tracker * If the logout triggers client or daomanager reconstruction (determined by isautorebuild (), * the tracker's aftersqlmapclientrebuild/afterdaomanagerrebuild ** @ Param ID */Public void unregistersqlmapconfig (Object ID) is triggered) throws ibatisbuildexception;/*** obtain the SQL Map Client and specify whether to re-create ** @ Param rebuild * re-create * @ return */Public sqlmapclient getsqlmapclient (Boolean rebuild ); public void addtracker (isqlmaptracker tracker );......} Public interface isqlmaptracker {/*** get the tracker ID, which is used to register * @ return */Public String GETID (); /*** triggered when the new configuration information is registered * @ Param ID configuration ID * @ Param configuration information */Public void aftersqlmapconfigregistered (Object ID, iconfiguration configuration ); /*** triggered * @ Param ID * @ Param configuration */Public void beforesqlmapconfigunregistered (Object ID, iconfiguration configuration) before configuration cancellation;/*** when sqlma After the pclient object is rebuilt, * @ Param sqlmapclient */Public void aftersqlmapclientrebuild (sqlmapclient) is triggered ); /*** triggered after daomanager is re-built * @ Param daomanager */Public void afterdaomanagerrebuild (daomanager);} transparent proxy implementation: public class sqlmapbuildermanager implements isqlmapbuildermanager {...... Public sqlmapclient getsqlmapclient (Boolean rebuild) {If (rebuild) {sqlmapclientproxy proxy = new sqlmapclientproxy (this. sqlmapclient); this. addtracker (proxy); Return proxy;} else {return sqlmapclient ;}}......} Public class sqlmapclientproxy implements sqlmapclient, isqlmaptracker {...... Public sqlmapclientproxy (sqlmapclient) {This. sqlmapclient = sqlmapclient;} public void beforesqlmapconfigunregistered (Object ID, iconfiguration configuration) {system. out. println ("sqlmanager has been uninstalled successfully ");}......} Test code: Public void test () {sqlmapbuildermanager buildermanager = new sqlmapbuildermanager (); try {buildermanager. registersqlmapconfig ("1", new fileinputstream ("sql-map-config3.xml"); assertnull (buildermanager. getsqlmapclient (); sqlmaptrackeradapters trackeradapter = new sqlmaptrackeradapters (); buildermanager. addtracker (trackeradapter); buildermanager. setautorebuild (true); buildermanager. regist Ersqlmapconfig ("2", new fileinputstream ("sql-map-config4.xml"); assertnotnull (buildermanager. getsqlmapclient (true); buildermanager. registersqlmapconfig ("3", new fileinputstream ("sql-map-config5.xml"); buildermanager. unregistersqlmapconfig ("2"); assertnotnull (buildermanager. getsqlmapclient (true);} catch (exception e) {e. printstacktrace () ;}}in combination with the above implementation and this test, we can understand the working process of buildermanager: We can manage To add different functions. However, extensions are transparent to the manager. The agent makes sqlmapclient updates transparent and provides the implementation of specific tracker events. The following code is easily written during implementation: Private void runtrackerafter (Object ID, iconfiguration result) {for (iterator it = trackerlist. keyset (). iterator (); it. hasnext ();) {string tid = (string) it. next (); isqlmaptracker tracker = (isqlmaptracker) This. trackerlist. get (TID); tracker. aftersqlmapconfigregistered (ID, result) ;}} private void runtrackerbefore (Object ID, iconfiguration unuse) {for (iterator it = Tracker List. keyset (). iterator (); it. hasnext ();) {isqlmaptracker tracker = (isqlmaptracker) it. next (); tracker. beforesqlmapconfigunregistered (ID, unuse) ;}} private void runtrackerafterbuild () {for (iterator it = trackerlist. entryset (). iterator (); it. hasnext ();) {isqlmaptracker tracker = (isqlmaptracker) it. next (); tracker. aftersqlmapclientrebuild (sqlmapclient) ;}} application in iteration mode and return mode: How ugly a small method is repeated! Pai_^ we can still use the pattern to make the code stronger: Private void trackerswalker (itrackerprocessor processor) {for (iterator it = trackerlist. values (). iterator (); it. hasnext ();) {isqlmaptracker tracker = (isqlmaptracker) it. next (); processor. process (tracker) ;}} interface itrackerprocessor {public void process (isqlmaptracker tracker);} private void runtrackerbefore (final object ID, final iconfiguration unuse) {This. trackerswalker (New itrackerprocessor () {public void process (isqlmaptracker tracker) {tracker. beforesqlmapconfigunregistered (ID, unuse );}});}
ConclusionAt this point, although the demand has been implemented, the optimization and Reconstruction of the Code is far from over. I have learned a lot of valuable experience in the project. I am very grateful to leader-shi Xin for his guidance. Thank you very much!