Interface-Oriented Programming
Without interface-oriented programming there is no dependency injection (Dependency injection), so revisit the interface-oriented programming before you talk about dependency injection.
PS: Relationship of Dependency Injection (di,dependency injection) and control inversion (ioc,inversion of controls)
Public interface Vehicle {public String run ();}
public class Horse implements vehicle{ @Override public String run () { return "Horse run."; }}
public class Soldier implements Hero { Vehicle Vehicle; Public Soldier (Vehicle Vehicle) { this.vehicle = Vehicle; } @Override Public String Fight () { return Vehicle.run () + "charge"; }}
- Above is a kind of dependency injection programming, that is, the soldier fight method relies on a vehicle, we directly inject a vehicle into the soldier class, rather than temporarily create a fight within the vehicle method.
- Above is an interface-oriented programming approach. Assuming that vehicle is an external service that we rely on, we can implement a simple vehicle on our own, so that testing of soldier class fight methods is no longer dependent on that real external service. Of course, instead of using interface-oriented programming, you can do the same thing with a mock, but the individual feels that using a mock is obscure and error-prone.
The following is formally entered into the introduction of the use of Guice.
Put a UML diagram first to show the class structure of my demo program.
Using module binding interface and implementation, get implementation class from injector
Public interface Energy {public String getName ();}
public class Fuel implements energy{ @Override public String getName () { return "Fule"; }}
@ImplementedBy (horse.class) public interface Vehicle {public String run ();}
@Singletonpublic class Horse implements vehicle{public static int instancenum=0; @Inject Energy ; Public Horse () { instancenum++; } @Override public String run () { return ' Horse run with ' + Energy.getname ();} }
Public interface Hero {public String fight ();}
public class Soldier implements Hero { Vehicle Vehicle; Public Soldier (Vehicle Vehicle) { this.vehicle = Vehicle; } @Override Public String Fight () { return Vehicle.run () + "charge"; }}
1 public class MyModule implements Module {2 @Override 3 public void Configure (Binder binder) {4 binder . Bind (Vehicle.class). Annotatedwith (Fast.class). to (Copter.class). in (Scopes.singleton); 5 Binder.bind (Vehicle.class). Annotatedwith (names.named ("Speed")). to (Airship.class); 6 binder.requeststaticinjection (Airship.class); 7 8 Binder.bind (Energy.class) to (Fuel.class); 9 Binder.bind (Energy.class). Annotatedwith (Lightenergy.class). to (Gas.class), Binder.bind (Energy.class). An Notatedwith (names.named ("Cleanenergy")). to (Solar.class); Binder.bind (Hero.class). Toprovider (HeroProvi Der.class) Binder.bind (string.class) Annotatedwith (names.named ("Point1")). ToInstance ("0.4"); 15 InputStream stream = MyModule.class.getResourceAsStream ("App.properties"); properties appproperties = new Pro Perties (); try {appproperties.load (stream); Names.binDproperties (binder, appproperties); catch (IOException e) {binder.adderror (e); 22}23 }24}
public class Testsoldier { @Test public void Test () { Injector Injector = guice.createinjector (New MyModule ( )); Vehicle Vehicle = injector.getinstance (vehicle.class); for (int i = 0; i < 3; i++) { Soldier hero = new Soldier (vehicle); Assert.assertequals ("Horse Run with Fule charge", Hero.fight ()); Assert.assertequals ("inject. Soldier ", Hero.getclass (). Getcanonicalname ()); } Assert.asserttrue (1 = = Horse.instancenum);} }
Put a bunch of code on it and start explaining it now.
The interface and implementation bindings are specified in module, and a module is required to be passed in when creating injector. When we want to get an instance of vehicle, we can take it directly from the injector. There is an annotation @implementedby (horse.class) on the interface vehicle, which tells Injector:vehicle that the default implementation is Horse. And horse relies on energy, what kind of energy should be used to achieve it? We note that the energy member of Horse has a @inject annotation, in which case the energy realization class is obtained from injector, and injector will ask the module, The 8th line of MyModule indicates that the default implementation class for energy is fuel.
The two methods of binding interfaces and implementations are shown here: Using @implementedby on the interface, writing Binder.bind (interface) to (Implementation) in module. The default implementation of an interface cannot have two, that is, if it appears in code:
Binder.bind (Energy.class) to (Fuel.class), Binder.bind (Energy.class). to (Gas.class);
The runtime throws an exception.
The horse class has a @singleton annotation on it, which tells Injector to create only one instance of horse, and the injector that anyone obtains from horse are the same entity, that is, their hashcode are the same. We deliberately set a static variable instancenum to record the number of times the default constructor of horse was called, and the experiment proved that the constructor was only called 1 times. @Singleton annotations This is the same way as using the in (Scopes.singleton) effect in bind, see Line 4th of MyModule.
Instances created from injector are normal instances, not proxies and conversions. If it is an agent, the canonicalname of the output instance will be: Com.sun.proxy. $Proxy 0
There are a lot of grammatical explanations in mymodule.
public class Solar implements energy { @Override public String getName () { return "Solar"; }}
public class AirShip implements vehicle{ @Inject @Named ("Cleanenergy") of static energy; @Override public String run () { return ' AirShip Fly with ' + Energy.getname ();} }
Public class superhero implements Hero { @Inject @Named ("Speed") Vehicle Vehicle; @Override Public String Fight () { return Vehicle.run () + "boom"; }}
public class Testsuperhero { @Test public void Test () { Injector Injector = guice.createinjector (new MyModule ()); Superhero hero = Injector.getinstance (Superhero.class); Assert.assertequals ("AirShip Fly with Solar boom", hero.fight ());} }
The parameters of the Injector.getinstance () method can be not only an interface, but also a concrete implementation class (no binding is required in the module at this time). When you get an instance of superhero from injector, the @inject attribute in superhero also requires that the instance be obtained from injector. So which vehicle is superhero using? Is it horse? (Because horse is the default implementation of vehicle) @named annotations are used here, referring to the 5th line of MyModule We know superhero used vehicle is actually airship. Similarly, the energy used in airship is Solar, see Line 10th of MyModule.
Note that the energy attribute of AirShip is a static variable, so Binder.requeststaticinjection (Airship.class) must be stated in MyModule; The chain of dependence from airship to energy can be passed down.
The module cannot bind itself to itself, but can be bound to subclasses.
Binder.bind (Implementation) to (Implementation) error
Binder.bind (Implementation) to (Subimplementation) correct
Public class gas implements energy { @Override public String getName () { return ' gas '; }}
public class Copter implements Vehicle {public static int instancenum = 0; Energy energy; Public copter () {Energy = new gas (); } @Inject private void init (@LightEnergy energy) { this.energy = energy; instancenum++; } @Override public String run () { return ' copter Fly with ' + Energy.getname ();} }
public class Weaselgirl implements Hero { @Inject @Fast Vehicle Vehicle; @Override Public String Fight () { return Vehicle.run () + "shoot"; }}
public class Testweaselgirl { @Test public void Test () { Injector Injector = guice.createinjector (new MyModule ()); for (int i = 0; i < 3; i++) { Weaselgirl hero = injector.getinstance (Weaselgirl.class); Assert.assertequals ("Copter Fly with gas shoot", hero.fight ()); } Assert.asserttrue (1 = = Copter.instancenum);} }
Vehicle with @fast annotation in Weaselgirl, the 4th line of MyModule tells us that the vehicle implementation class should take copter at this time. Injectot takes precedence when creating an copter instance to invoke a non-private constructor of copter with @inject annotations, and if no such constructor is invoked, the empty constructor is called and injector executes all @inject methods immediately after the constructor is called. There is a @inject method called Init in Copter, the parameters in this method are @lightenergy annotated, and the 9th line of MyModule tells us that we should create a gas instance to pass to the Init () method. Since the 4th line of MyModule tells Injector:copter to be singleton, in test, although we have obtained 3 weaselgirl from Injector (each time a weaselgirl is created to request a copter), But in fact, Injetor only created a copter instance.
At this point we have learned 3 ways to bind interfaces and implementations: @ImplementedBy default bindings, binding with Annotatedwith (Annotation) when binder, and binder with Annotatedwith ( Names.named ("str")) to implement conditional binding. In fact, we can also implement a provider, when there is a dependency in a class (the dependency is an interface), by provider to provide the specific implementation class.
public class Mobile implements Vehicle ; Public Mobile () {Energy = new gas (); } @Inject public Mobile [energy] { this.energy = energy; } @Override public String run () { return ' Mobile run with ' + Energy.getname ();} }
public class Vehicleprovider implements provider<vehicle> { double point1; Double Point2; @Inject public Vehicleprovider (@Named ("Point1") string P1, @Named ("Point2") string p2) { this.point1 = Double.parsedouble (p1); This.point2 = double.parsedouble (p2); } @Override public Vehicle get () { Injector Injector = guice.createinjector (New MyModule ()); Double rnd = Math.random (); if (Rnd < point1) { return injector.getinstance (Mobile.class); } else if (Rnd < Point2) { return Inje Ctor.getinstance (Airship.class); } else { return injector.getinstance (Mobile.class);}}}
public class Frogman implements Hero { Vehicle Vehicle; Public frogman (provider<vehicle> Provider) { this.vehicle = Provider.get (); } @Override Public String Fight () { return Vehicle.run () + "hack"; }}
public class Testfrogman { @Test public void Test () { Injector Injector = guice.createinjector (New MyModule ()); provider<vehicle> Provider = injector.getinstance (vehicleprovider.class); for (int i = 0; i < i++) { frogman hero = new Frogman (provider); System.out.println (Hero.fight ()); } System.out.println (Copter.instancenum); }}
A provider is required in the Frogman constructor, and we pass in a vehicleprovider. The Vehicleprovider get method randomly returns the mobile and airship two entities, where the stochastic algorithm relies on two parameters point1 and Point2. Because Vehicleprovider is obtained from injector, injector calls Vehicleprovider's @inject constructor when it creates the Vehicleprovider instance. The parameters used in @Inject constructors are all provided by injector. The 14th line of MyModule tells us that point1 equals 0.4, which is an example of binding constants to PrimitiveType. In fact, you can also use the external configuration file to bind the constant to a string variable, such as MyModule Line 15th to line 22nd is read from a peoperties file configuration to bind the constant value to the string variable, our Point2 is in this way to assign value.
public class Heroprovider implements provider
public class Testheroprovider { @Test public void Test () { Injector Injector = guice.createinjector (new MyModule ()); for (int i = 0; i < i++) { Hero Hero = injector.getinstance (hero.class); System.out.println (Hero.fight ()); } System.out.println (Copter.instancenum); }}
The 12th line of MyModule indicates which specific hero the Heroprovider decides to produce when requesting hero from injector.
Download all the code for this article
Dependencies are introduced in the MAVEN project:
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
- This article is from: Linux Learning Tutorial Network
Guice--java Dependency Injection Framework