1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 代码的演化-DI(理解依赖注入di 控制反转ioc)

代码的演化-DI(理解依赖注入di 控制反转ioc)

时间:2023-08-20 08:05:30

相关推荐

代码的演化-DI(理解依赖注入di 控制反转ioc)

控制反转(Inversion of Control IoC)在java中,Spring就是一个很好的应用。用于解除使用者和生产者的耦合。

一般的代码中。使用者即是生产者,使用者在调用它需要的对象的时候,去创建它(new a instance),然后使用。这样就造成了强依赖。

简单说来就是:a调用b, 那么a 就依赖于b. 而控制反转呢,就是用来解除这样一来的一种方式。

演变成: a调用 构造容器c ,构造容器c去创建b. 这样的好处是, b是可变的,解除了a和b的依赖,将依赖延迟到 构造容器c 中了。但依赖依旧存在。

这样就产生了一个控制的反转效果,a不再控制b的形态,而反倒由b的“构造容器c"来控制。

DI(Dependency Injection) 和 服务定位器(Service Location) 是IoC模式的两个实现方法(模式)。

我们想做一个演示,来一步步的演示这个过程。

例如:我们想模拟士兵持武器进行攻击的场景。

一般我们会写出这样的代码,构造两个类,一个士兵,一个武器。还有个就是main方法。代码如下

/* demo1

author:vir56k@

date:-8-12 */

//武器

class Weapon

{

public void Attack()

{

Console.WriteLine("用武器攻击");

}

}

//士兵

class Soldier

{

/* p1 */ private Weapon _Weapon = new 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();//构建一个战士

soldier.Attack();//攻击

Console.Read();

}

}

我们看到,士兵和武器是耦合在一起的,这是一个强依赖。

场景变化要求:我们觉得武器太广泛了,武器还是有种类的,有剑和匕首。于是场景更改如下:

例如:我们想模拟士兵持武器进行攻击的场景,士兵可以使用的武器有剑和匕首。

于是我们更改了我们的代码,为武器抽象一个接口,它有两个实现类,一个是剑,一个是匕首类。代码如下:

interface IWeapon

{

void Attack();

}

class Sword : IWeapon

{

public void Attack()

{

Console.WriteLine("用剑攻击");

}

}

class Knife : IWeapon

{

public void Attack()

{

Console.WriteLine("用匕首攻击");

}

}

//士兵

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();

}

}

我们看到,这下我们可以选择武器了,代码位置p2和p3可以让我们选择使用哪个武器。我们在需要更换武器的时候,就注释掉 第p2 或者第p3行,然后重新

编译我们的代码。但每次的更改都需要重新编译,确实让人觉得很讨厌。于是我们想到解除耦合。 写一个 构造容器c,来解除a对b的依赖。

代码如下:

interface IWeapon

{

void Attack();

}

class Sword : IWeapon

{

public void Attack()

{

Console.WriteLine("用剑攻击");

}

}

class Knife : IWeapon

{

public void Attack()

{

Console.WriteLine("用匕首攻击");

}

}

//士兵

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");//返回配置好的士兵

soldier.Attack();

Console.Read();

}

}

我们看到,战士类不再依赖具体的武器,而改为依赖 武器接口。剑类和匕首类依赖 武器接口。 Program中,调用 应用程序上下文类 获得组装好的(配置好

的)战士,然后执行攻击方法。 应用程序上下文类,实现了组装各种元素的功能,专业说来:就是 装配程序组件。

它实现了 组件的配置和使用的分离。

但我们看到,我们如果想要更改成其他武器,就仍然得更改代码重新编译。那么配置文件或许是个好的解决方案。

最终代码如下:

interface IWeapon

{

void Attack();

}

class Sword : IWeapon

{

public void Attack()

{

Console.WriteLine("用剑攻击");

}

}

class Knife : IWeapon

{

public void Attack()

{

Console.WriteLine("用匕首攻击");

}

}

//士兵

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)

{

//解析xml配置文件,并反射创建对象

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");//返回配置好的士兵

soldier.Attack();

Console.Read();

}

}

在 应用程序上下文中,通过反射,获得配置文件里的设置。为 战士对象 配置 指定的武器。这就是一个注入的过程。我们这里采用的方法是

设置方法注入,另外的两种注入方法是,构造方法注入和 接口注入。

更重要的是:配置和使用分开。

下载代码资料参考: martin fowler 的Ioc容器和Dependency Injection模式。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。