In Java, Spring is a good application. Used to decouple consumers and producers. In general code. The user is the producer. When the user calls the object it needs, it creates it (new a instance) and then uses it. This creates a strong dependency. In simple terms, A calls B, so A depends on B. Inversion of control is a way to undo this. A calls constructor c and constructor C creates constructor B. The advantage of this is that b is mutable, removing the dependency of a and B and deferring the dependency to constructor C. But the dependency remains. This creates a control reversal effect, in which A no longer controls B’s form, but b’s “construction container C” controls it. DI(Dependency Injection) and Service Location (Service Location) are two implementations of IoC pattern (pattern).

We want to do a demonstration, step by step, of this process. For example, we want to simulate soldiers attacking with weapons.

Typically we write code that constructs two classes, one soldier and one weapon. And then there’s the main method. The following code

/* demo1 author:[email protected] date:2009-8-12 */ // Weapon class Weapon {public void Attack() {Console.WriteLine(” Attack with Weapon “); }}

// private Weapon = new Weapon(); // Grant a weapon;

public Weapon Weapon { get { return _Weapon; } set { _Weapon = value; }}

public void Attack() { Weapon.Attack(); }}

class Program { static void Main(string[] args) { Soldier soldier = new Soldier(); // Build a soldier.Attack(); / / attack

Console.Read(); }} We see that soldiers and weapons are coupled together, and this is a strong dependency.

Scene change requirements: we feel that the weapons are too broad, there are still types of weapons, there are swords and daggers. So the scene changes as follows:

For example, we want to simulate a scenario where soldiers attack with weapons, such as swords and daggers.

So we changed our code to abstract an interface for the weapon, which has two implementation classes, one sword and one dagger. The code is as follows:

  interface IWeapon

{

void Attack();

}

Class Sword: IWeapon {public void Attack() {Console.WriteLine(” Attack with Sword “); }}

Class Knife: IWeapon {public void Attack() {console. WriteLine(” Attack with dagger “); }}

// Soldier class Soldier {* p2 */ private IWeapon _Weapon = new Sword(); /* p3 */// private IWeapon _Weapon = new Knife();

public IWeapon Weapon { get { return _Weapon; } set { _Weapon = value; }}

        public void Attack()

{

Weapon.Attack();

}

}

class Program

{

static void Main(string[] args)

{

Soldier soldier = new Soldier();

soldier.Attack();

Console.Read(); }}

As we can see, we now have a choice of weapons, code positions P2 and P3 allow us to choose which weapons to use. When we need to change weapons, we comment out line P2 or p3 and recompile our code. But it’s annoying to have to recompile every change. So we thought about decoupling. Write a construct container C to remove a’s dependence on B.

Interface IWeapon {void Attack(); }

Class Sword: IWeapon {public void Attack() {Console.WriteLine(” Attack with Sword “); }}

Class Knife: IWeapon {public void Attack() {console. WriteLine(” Attack with dagger “); }}

// Soldier class Soldier {private IWeapon _Weapon;

public IWeapon Weapon { get { return _Weapon; } set { _Weapon = value; }}

public void Attack() { Weapon.Attack(); }}

Public Class ApplicationContext {public Object GetObject(string id) {if (id == “Soldier”) {Soldier solider = new Soldier(); solider.Weapon = new Sword(); return solider; } return null; }}

class Program { static void Main(string[] args) { ApplicationContext ctx = new ApplicationContext(); Soldier soldier = (Soldier)ctx.GetObject(“Soldier”); // Return the configured soldier soldier.attack ();

Console.Read(); }}

We see that the warrior class no longer relies on specific weapons, but instead relies on weapon interfaces. Swords and daggers rely on weapon interfaces. Program calls the application context class to get the assembled (configured) fighter, and then executes the attack method. The application context class implements the ability to assemble various elements, or, technically speaking, assembly program components.

It separates the configuration and use of components.

But we saw that we still had to change the code and recompile if we wanted to switch to another weapon. Configuration files might be a good solution. The final code is as follows: interface IWeapon {void Attack(); }

Class Sword: IWeapon {public void Attack() {Console.WriteLine(” Attack with Sword “); }}

Class Knife: IWeapon {public void Attack() {console. WriteLine(” Attack with dagger “); }}

// Soldier class Soldier {private IWeapon _Weapon;

public IWeapon Weapon { get { return _Weapon; } set { _Weapon = value; }}

public void Attack() { Weapon.Attack(); }}

Public Class ApplicationContext {public Object GetObject(string id) {// Parse XML configuration file, XmlDocument doc = new XmlDocument(); doc.Load(“DI_Config.xml”); XmlNode node = doc.SelectSingleNode(string.Format(“//beans/bean[@id='{0}’]”,id)); if (node ! = null) { string className = node.Attributes[“class”].Value; Type tp = Assembly.GetExecutingAssembly().GetType(className); object objVal = Activator.CreateInstance(tp); XmlNodeList nodeProperties = node.SelectNodes(“./property”); foreach (XmlNode var in nodeProperties) { string propertyName = var.Attributes[“name”].Value; foreach (PropertyInfo pInfo in tp.GetProperties()) { if (pInfo.Name == propertyName) { string clsRef = var.SelectSingleNode(“./ref”).Attributes[“local”].Value; XmlNode node3 = doc.SelectSingleNode(string.Format(“//beans/bean[@id='{0}’]”, clsRef)); if (node3 ! = null) { string className2 = node3.Attributes[“class”].Value; Type tp2 = Assembly.GetExecutingAssembly().GetType(className2); pInfo.SetValue(objVal, Activator.CreateInstance(tp2), null); } } } } return objVal; }

return null; }}

class Program { static void Main(string[] args) { ApplicationContext ctx = new ApplicationContext(); Soldier soldier = (Soldier)ctx.GetObject(“Soldier”); // Return the configured soldier soldier.attack (); Console.Read(); }}

In the application context, the Settings in the configuration file are retrieved by reflection. Configures the specified weapon for the warrior object. This is an injection process. The method we use here is set method injection, and the other two injection methods are constructor injection and interface injection.

More importantly: separate configuration and use. \

Download code reference: Martin Fowler’s Ioc container and Dependency Injection pattern. \