There has always been a recent exposure to programming principles or patterns such as the IoC (inversion of control, controlled inversion), DI (Dependency injection, Dependency injection), which is at the heart of the famous Java framework Spring, Struts, and so on. According to this check the Wikipedia entries, and from the library to borrow related books, read some understanding, now combined with the book of the explanation and their processing as follows:
Eg1
Problem Description:
Develop a system that can generate Excel or PDF reports according to different requirements, such as daily reports, monthly statements, and so on.
Solution:
According to the principle of "interface-oriented Programming", the interface and implementation should be separated, the function of generating report will be extracted as a common interface reportgenerator, and two implementation classes Excelgenerator and Pdfgenerator are provided to generate Excel and PDF report forms. The client client then obtains the corresponding report printing function through the service provider Reportservice.
Implementation method:
According to the above mentioned, the following class diagram is obtained:
Code implementation:
Interface Reportgenerator {public void generate (table table); Class Excelgenerator implements Reportgenerator {public void generate (table table) {System.out.println ("genera
Te an Excel ... "); } class Pdfgenerator implements Reportgenerator {public void generate (table table) {System.out.println ("Gener
Ate an PDF ... ");
} class Reportservice {//is responsible for creating specific needs Report Builder private Reportgenerator generator = new Pdfgenerator ();
private static Reportgenerator generator = new Excelgenerator ();
public void Getdailyreport (date date) {table.setdate (date);
... generator.generate (table);
public void Getmonthlyreport (Month Month) {table.setmonth (Month);
... generator.generate (table); } public class Client {public static void main (string[] args) {Reportservice reportservice = new Reportserv
Ice ();
Reportservice.getdailyreport (New Date ());
Reportservice.getmonthlyreport (New Date ()); }
}
EG2
Problem Description:
As the comments in the above code show, the specific Report Builder is created by the Reportservice class internal hard coding, which reportservice already relies directly on pdfgenerator or excelgenerator, and must eliminate this obvious tight coupling relationship.
Solution: Introducing Containers
Introduce an intermediary manager, a container (Container), that manages the objects involved in the reporting system (the component, which we call the Bean), including the Reportservice and each xxgenerator. A HashMap instance of a key-value pair is used here to save these beans.
Implementation method:
Get the class diagram as follows:
Code implementation:
Class Container {//A key-value pair to save all the required components beans private static map<string, object> beans;
Public Container () {beans = new hashmap<string, object> ();
Create, save specific report Generator Reportgenerator Reportgenerator = new Pdfgenerator ();
Beans.put ("Reportgenerator", reportgenerator);
Obtain, manage Reportservice references reportservice reportservice = new Reportservice ();
Beans.put ("Reportservice", Reportservice);
public static Object Getbean (String ID) {return beans.get (ID);
} class Reportservice {//Eliminate tight coupling relationship, replaced by container//private static Reportgenerator generator = new Pdfgenerator ();
Private Reportgenerator generator = (reportgenerator) container.getbean ("Reportgenerator");
public void Getdailyreport (date date) {table.setdate (date);
Generator.generate (table);
public void Getmonthlyreport (Month Month) {table.setmonth (Month);
Generator.generate (table); } public class Client {public static void main (string[] ARGS) {Container Container = new Container ();
Reportservice Reportservice = (reportservice) container.getbean ("Reportservice");
Reportservice.getdailyreport (New Date ());
Reportservice.getmonthlyreport (New Date ());
}
}
The timeline diagram is roughly as follows:
Effect:
As shown above, Reportservice is no longer directly associated with specific reportgenerator, has already isolated the interface from the implementation in a container, increased the reusability of system component beans, and can also use configuration files in Container To obtain the definition of specific components in real time.
eg3
Problem Description:
However, looking at the above class diagram, it is easy to find a two-way association between Reportservice and Container, which is dependent on each other. Also, if you want to reuse reportservice, it is also directly dependent on the specific lookup logic of a single Container. If other containers are specific to different component lookup mechanisms (such as JNDI), reusing reportservice at this point means that the internal lookup logic of Container needs to be modified.
Solution: Introduce Service Locator
Again, introduce an indirect layer Service Locator, which provides an interface for component lookup logic, see the description in Wikipedia or Java EE's description 1, description 2. This will allow you to isolate the possible points of change.
Implementation method:
The class diagram is as follows:
Code implementation:
In practical applications, it is possible to use interface to provide a unified interface
class Servicelocator {
private static Container Container = new Container ();
public static Reportgenerator Getreportgenerator () {return
(reportgenerator) Container.getbean (" Reportgeneraator ");
}
}
Class Reportservice {
private reportgenerator reportgenerator = Servicelocator.getreportgenerator ();
// ...
}
Eg4
Problem Description:
However, whether introducing Container or using service Locator, Reportservice is ' active ' in finding and creating specific components, which means that reportservice as a customer must be aware of what they need, Where to get and how to get it. All of a sudden because of What, Where, how to increase the specific logical details.
For example, in the implementation method of ' introducing container ' earlier, there is the following code:
Class Reportservice {
//eliminate tight coupling relationship, replaced by container
//private static Reportgenerator generator = new Pdfgenerator ();
Through Container. Getbean ("Reportgenerator") ' actively ' finds
private reportgenerator generator = (reportgenerator) Container
. Getbean (" Reportgenerator ");
In the implementation method of ' introducing Service Locator ', there are the following code:
Class Servicelocator {
privatestatic Container Container = new Container ();
Publicstatic reportgenerator Getreportgenerator () {
//or Container.getbean (), return with a delegate
( Reportgenerator) Container.getbean ("Reportgeneraator");
}
Class Reportservice {
//Reportservice Finally "active" lookup, entrusted to Servicelocator only
private reportgenerator Reportgenerator = Servicelocator.getreportgenerator ();
}
Solution:
In this case, changing ' active ' to ' passive ' can undoubtedly reduce the internal knowledge of reportservice (that is, the logic of locating components). According to the control reversal (IoC) principle, this kind of pull (Pull, active) can be transformed into a push (push, passive) mode.
For example, the usual use of RSS subscriptions is the application of push, save us several times a day to login to their favorite site actively get the article update trouble.
and Dependency Injection (DI) is the drawback of realizing this passive reception, reducing the customer (here, reportservice) itself containing complex logic and knowing too much.
Implementation method:
Because we want to be ' passive ', we're going back to Container's example without using the service Locator mode. The resulting modified class diagram is as follows:
and the original class diagram is as follows, you can look at the notes, note the hint:
Code implementation:
In order for the example to compile, run, and slightly using the results of the trace code to explicitly instantiate the entire class diagram, the sequence of collaboration, in the constructor of each class to add a number of numbered print statements, as well as two of unimportant classes, a little bit of a nagging, specifically as follows:
Import Java.util.Date;
Import Java.util.HashMap;
Import Java.util.Map; In order to be able to compile and run, there are two trivial classes class Month {} class Table {publicvoid setdate (date date) {} publicvoid setmonth (Month Month)
{}}//------------None of the following are important changes-----------------//interface Reportgenerator {publicvoid Generate (table table);} Class Excelgenerator implements Reportgenerator {public excelgenerator () {System.out.println ("2 ... start initialization excelgenerat
Or ... ");
} Publicvoid generate (table table) {System.out.println ("Generate an Excel ..."); } class Pdfgenerator implements Reportgenerator {public pdfgenerator () {System.out.println ("2 ... start initialization pdfgenerato
R.. ");
} Publicvoid generate (table table) {System.out.println ("Generate an PDF ..."); }//------------None of the above is important change-----------------//class Container {//To save all the required component beans in a key-value pair privatestatic map<string
, object> beans;
Public Container () {System.out.println ("1 ... starts initializing Container ..."); Beans = new HashmAp<string, object> ();
Create, save specific report Generator Reportgenerator Reportgenerator = new Pdfgenerator ();
Beans.put ("Reportgenerator", reportgenerator);
Obtain, manage Reportservice references reportservice reportservice = new Reportservice ();
Inject the specific Reportgenerator instance that has been created above Reportservice.setreportgenerator (reportgenerator);
Beans.put ("Reportservice", Reportservice);
System.out.println ("5 ... end initialization Container ...");
Publicstatic Object Getbean (String id) {System.out.println ("Last Get Service component ... Getbean ()-->" + ID + "...");
Returnbeans.get (ID);
} class Reportservice {//private static Reportgenerator generator = new Pdfgenerator (); Eliminates the tight coupling relationship above, replaced by the container//private Reportgenerator generator = (reportgenerator) Container//. Getbean ("Reportgenerator"
);
Remove the "active" lookup above, provide private fields to save externally injected objects private reportgenerator generator; To inject publicvoid setreportgenerator (Reportgenerator generator) {System.out.println ("4)" from the outside in setter mode. Start Injecting Reportgener
Ator ... "); This.generatoR = Generator;
Private table table = new Table ();
Public Reportservice () {System.out.println ("3 ... starts initializing reportservice ...");
} publicvoid Getdailyreport (date date) {table.setdate (date);
Generator.generate (table);
} publicvoid Getmonthlyreport (Month Month) {table.setmonth (Month);
Generator.generate (table);
} publicclass Client {publicstaticvoid main (string[] args) {//Initialize container new Container ();
Reportservice Reportservice = (reportservice) Container. Getbean ("Reportservice");
Reportservice.getdailyreport (New Date ());
Reportservice.getmonthlyreport (New Date ());
}
}
Run Result:
1. Start initializing Container
... 2. Start initializing Pdfgenerator
... 3. Start initializing Reportservice
... 4. Start injecting Reportgenerator
... 5. End Initialization Container ...
Finally get Service components ... Getbean ()--> reportservice ...
Generate an PDF ...
Attention:
1, according to the results of the operation of the printing sequence, the visible code added to the specific number is reasonable, simulation of the program execution process, so also no longer draw sequence diagram.
2, attention to the example of the IOC, the use of Di is based on Reportservice for the client (that is, the component requirement), while the test code in the client class main () in the code is the end user of the service component, but it needs not the component but the service that the component has.
3, actually in the spring box, initializing container is clearly not what the end user client should do, it should be ready to be started by the service provider beforehand.
4. In the end user client, we still use Container.getbean ("Reportservice") to obtain the service components that have been instantiated in the container constructor in advance. But in the concrete application, usually uses the XML and so on the configuration file to deploy the usable service component to the server, then by container reads this profile unifies the reflection technology to create, injects the concrete service component.
Analysis:
Previously, the Reportservice actively requested the service component from the container, and now passively waits for the container injection (inject, or push) service component. Control is obviously transferred from the underlying module (Reportservice is the component requirement) to the high-level module (Container is the component provider), which is the control reversal.