【mgm美高梅国际娱乐】依赖注入,依赖注入那些事儿

1.4 小李的下结论

Peter鲜明对改革后的代码比较知足,他让小李对照两份安插和代码,实行2个总计。小李简略思考了一下,并结成小于对3回规划提出的阙如,说道:

“我认为,革新后的代码有如下优点:

首先,纵然类的数码扩充了,可是种种类中艺术的代码都特别短,没有了在此以前Attack方法那种很短的法门,也绝非了洋洋洒洒的if…else,代码结构变得很清楚。

其次,类的天职更鲜明了。在率先个规划中,Role不但负责攻击,还背负给怪物裁减HP和判断怪物是还是不是已死。这眼看不该是Role的天职,创新后的代码将那五个任务移入Monster内,使得职分分明,提升了类的内聚性。

其三,引入Strategy情势后,不但化解了重复性代码,更关键的是,使得设计适合了OCP。假设将来要加贰个新武器,只要新建三个类,完毕IAttackStrategy接口,当剧中人物须要配备那个新武器时,客户代码只要实例化2个新武器类,并赋给Role的Weapon成员就足以了,已某些Role和Monster代码都并非改动。那样就兑现了对扩展开发,对修改关闭。”

Peter和小于听后都很满意,认为小李计算的10分美好。

IGame集团的座谈会还在开始展览着,内容是尤其精彩,可是大家先听到那里,因为,接下去,我们要对在那之中一些难点展开一些探究。别忘了,本文的主旨不过依赖注入,那几个主角还没出台呢!让主演等太久可不佳。

1.1 讨论会

话说有二个叫IGame的游乐公司,正在开发一款AENVISIONPG游戏(动作&剧中人物扮演类游戏,如魔兽世界、梦幻西游这一类的玩乐)。一般那类游戏都有三个为主的成效,就是打怪(玩家攻击怪物,借此赢得经验、虚拟货币和虚拟装备),并且依照玩家剧中人物所装备的兵器区别,攻击效果也不一致。那天,IGame集团的支出小组正在开会对打怪成效中的某贰个职能点什么兑现进行商量,他们前面的大屏幕上是这么一份必要描述的ppt:

mgm美高梅国际娱乐 1

图1.1 供给描述ppt

依次开发职员,面对那份必要,展开了热烈的座谈,上面我们看看研讨会上都发生了何等。

1.2 实习生小李的贯彻方式

在经过一番座谈后,项目COOPeter觉得有必不可少整理一下各方的观点,他首先询问小李的理念。小李是某高校总计机系大三学生,对游戏支付尤其感兴趣,近年来是IGame公司的一名实习生。

因而短暂的商量,小李演讲了温馨的见识:

“小编觉着,这几个须求能够如此实现。HP当然是怪物的三个性子成员,而武器是剧中人物的三个属性成员,类型能够使字符串,用于描述近日剧中人物所装备的军械。剧中人物类有2个攻击方法,以被口诛笔伐怪物为参数,当执行3遍攻击时,攻击方法被调用,而以此情势首先判断当前角色装备了何等武器,然后据此对被攻击怪物的HP实行操作,以发出不一样效率。”

而在论述完后,小李也相当慢的在祥和的总结机上写了八个德姆o,来演示他的想法,德姆o代码如下。

mgm美高梅国际娱乐 2mgm美高梅国际娱乐 3

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IGameLi
{
    /// <summary>
    /// 怪物
    /// </summary>
    internal sealed class Monster
    {
        /// <summary>
        /// 怪物的名字
        /// </summary>
        public String Name { get; set; }

        /// <summary>
        /// 怪物的生命值
        /// </summary>
        public Int32 HP { get; set; }

        public Monster(String name,Int32 hp)
        {
            this.Name = name;
            this.HP = hp;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IGameLi
{
    /// <summary>
    /// 角色
    /// </summary>
    internal sealed class Role
    {
        private Random _random = new Random();

        /// <summary>
        /// 表示角色目前所持武器的字符串
        /// </summary>
        public String WeaponTag { get; set; }

        /// <summary>
        /// 攻击怪物
        /// </summary>
        /// <param name="monster">被攻击的怪物</param>
        public void Attack(Monster monster)
        {
            if (monster.HP <= 0)
            {
                Console.WriteLine("此怪物已死");
                return;
            }

            if ("WoodSword" == this.WeaponTag)
            {
                monster.HP -= 20;
                if (monster.HP <= 0)
                {
                    Console.WriteLine("攻击成功!怪物" + monster.Name + "已死亡");
                }
                else
                {
                    Console.WriteLine("攻击成功!怪物" + monster.Name + "损失20HP");
                }
            }
            else if ("IronSword" == this.WeaponTag)
            {
                monster.HP -= 50;
                if (monster.HP <= 0)
                {
                    Console.WriteLine("攻击成功!怪物" + monster.Name + "已死亡");
                }
                else
                {
                    Console.WriteLine("攻击成功!怪物" + monster.Name + "损失50HP");
                }
            }
            else if ("MagicSword" == this.WeaponTag)
            {
                Int32 loss = (_random.NextDouble() < 0.5) ? 100 : 200;
                monster.HP -= loss;
                if (200 == loss)
                {
                    Console.WriteLine("出现暴击!!!");
                }

                if (monster.HP <= 0)
                {
                    Console.WriteLine("攻击成功!怪物" + monster.Name + "已死亡");
                }
                else
                {
                    Console.WriteLine("攻击成功!怪物" + monster.Name + "损失" + loss + "HP");
                }
            }
            else
            {
                Console.WriteLine("角色手里没有武器,无法攻击!");
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IGameLi
{
    class Program
    {
        static void Main(string[] args)
        {
            //生成怪物
            Monster monster1 = new Monster("小怪A", 50);
            Monster monster2 = new Monster("小怪B", 50);
            Monster monster3 = new Monster("关主", 200);
            Monster monster4 = new Monster("最终Boss", 1000);

            //生成角色
            Role role = new Role();

            //木剑攻击
            role.WeaponTag = "WoodSword";
            role.Attack(monster1);

            //铁剑攻击
            role.WeaponTag = "IronSword";
            role.Attack(monster2);
            role.Attack(monster3);

            //魔剑攻击
            role.WeaponTag = "MagicSword";
            role.Attack(monster3);
            role.Attack(monster4);
            role.Attack(monster4);
            role.Attack(monster4);
            role.Attack(monster4);
            role.Attack(monster4);

            Console.ReadLine();
        }
    }
}

View Code

程序运维结果如下:

mgm美高梅国际娱乐 4

图1.2 小李程序的运作结果

4.3 .NET平台上一级IoC Container推荐介绍

2 研讨依赖注入

2.1 有趣的事的启发

咱们前日静下心来,再体会一下刚刚的轶事。因为,这几个传说里面隐藏注重视注入的产出原因。小编说过不只贰遍,想真正认清三个事物,不能够只看“它是怎么着?什么体统?”,而应超过弄驾驭“它是怎么来的?是怎样的急需和背景促使了它的出世?它被创立出来是做什么用的?”。

回想上边包车型客车传说。刚开始,首要需若是3个打怪的功能。小李做了3个开首面向对象的筹划:抽取领域场景中的实体(怪物、剧中人物等),封装成类,并为各种类赋予属性与方法,最终通过类的互动实现打怪效率,那应当算是面向对象设计的初级阶段。

在小李的安排基础上,架构师小于建议了几点不足,如不符合OCP,职务分开不明明等等,并依照事态引入政策方式。那是更高层次的面向对象设计。其实就着力来说,小于只做了一件事:利用多态性,隔绝变化。它知道认识到,那些打怪作用中,某个事情逻辑是不变的,如角色攻击怪物,怪物收缩HP,减到0怪物就会死;而生成的唯有是见仁见智的角色有所不相同武器时,每趟攻击的遵循不雷同。于是他的架构,本质便是把变化的有的和不变的有的隔开开,使得变化部分爆发变化时,不变部分不受影响。

咱俩再仔细看看小于的统筹图,那样设计后,有个主导的难点亟待缓解:未来Role不信赖具体武器,而单单重视一个IAttackStrategy接口,接口是不能够实例化的,就算Role的Weapon成员类型定义为IAttackStrategy,但最终照旧会被予以一个落到实处了IAttackStrategy接口的切切实实武器,并且随着程序开展,1个剧中人物会装备不比的火器,从而发出不一样的效能。赋予武器的职务,在德姆o中是放在了测试代码里。

此地,测试代码实例化多个现实的兵器,并赋给Role的Weapon成员的长河,正是借助注入!那里要通晓,倚重注入其实是2个进程的名目!

4.3.2 Unity

mgm美高梅国际娱乐 5

对于小型项目和爱抚敏捷的团体,Spring.NET恐怕有点太重量级,那么能够选拔轻量级的Unity。Unity是微软patterns
& practices共青团和少先队生产的轻量级框架,相当好用,近年来新星版本是1.2。

Unity的官方网站是:

参考文献

[1]  Shivprasad koirala, Design pattern – Inversion of control and
Dependency injection,

[2]  Martin Fowler, Inversion of Control Containers and the Dependency
Injection pattern,

[3]  Paul, IoC Types,

[4]  Eric Freeman, Elisabeth Freeman. Head First Design Patterns.
O’Reilly Media, 2004. ISBN 0596007142

[5]  Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design
Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley,

  1. ISBN 0201633612

[6]  Patrick Smacchia 著,施凡等 译,C#和.NET2.0
平台、语言与框架。贰零壹零.1,人民邮政和邮电通讯出版

[7]  Jeffrey Rechter 著,CLR via C#(影印版)。二〇一〇.8,人民邮政和邮电通讯出版

 

正文基于署名-非商业性利用
3.0许可协议公布,欢迎转发,演绎,不过必须保留本文的签订契约张洋(包涵链接),且不得用于生意指标。如你有别的难题依然授权方面包车型大巴协议,请与小编关系。

 

From

3.3.2 分歧活性多态的重视性注入选用

诚如的话,高活多态性适合利用Setter注入。因为Setter注入最灵敏,也是唯一允许在相同客户类实例运营时期变更服务类的注入格局。并且那种注入一般由上下文环境经过Setter的参数钦点服务类类型,方便灵活,适合频仍变动的高活多态性。

对其中活多态性,则吻合选用Constructor注入。因为Constructor注入也是由上下文环境经过Construtor的参数钦命服务类类型,但有些客户类实例化后,就无法展开重复流入,保险了其时间稳定性。

而对此低活多态性,则吻合利用Dependency
Locate并合作文件配置进行信赖注入,或Setter、Constructor合营配置文件注入,因为重视源来自文件,假诺要转移服务类,则要求转移配置文件,一则确认保证了低活多态性的年华和空中稳定性,二是改变配置文件的措施方便于广大服务类替换。(因为低活多态性一旦改变行为,往往规模非常的大,如替换整个数据访问层,若是运用Setter和Construtor传参,程序中供给转移的地点千千万万)

真相上,这种选拔是因为分歧的信赖性注入类型有着不一致的满面春风,我们能够细细咀嚼“活性”、“稳定性”和“注重注入类型”之间密切的关联。

3.1.3 注重获取

地点提到的注入格局,都是客户类被动接受所依靠的服务类,那也顺应“注入”那几个词。可是还有一种艺术,能够和正视注入达到同等的目标,正是凭借获取。

借助于获取(Dependency
Locate)是指在系统中提供三个取得点,客户类如故凭借服务类的接口。当客户类要求服务类时,从获得点主动赢得钦赐的服务类,具体的劳动类类型由获得点的配备决定。

能够看到,那种艺术变被动为主动,使得客户类在须求时积极赢得服务类,而将多态性的兑现封装到获取点里面。获取点能够有很各样贯彻,大概最简单想到的正是确立八个Simple
Factory作为得到点,客户类传入2个点名字符串,以获得相应服务类实例。若是所依赖的劳动类是一密密麻麻类,那么信赖获取一般选择Abstract
Factory形式创设获取点,然后,将服务类多态性转移到工厂的多态性上,而工厂的品种依赖一个表面配置,如XML文件。

唯独,不论选用Simple Factory依旧Abstract
Factory,都防止不了判断服务类类型或工厂类型,那样系统香港中华总商会要有1个地点存在不符合OCP的if…else或switch…case结构,那种缺陷是Simple
Factory和Abstract
Factory以及借助获取自作者不能排除的,而在一些帮助反射的言语中(如C#),通过将反射机制的引入彻底化解了那几个题材(后边研商)。

下边给叁个现实的例子,未来大家只要有个程序,既能够使用Windows风格外观,又有啥不可应用Mac风格外观,而当中业务是平等的。

mgm美高梅国际娱乐 6

图3.4 信赖获取示意

上海体育场所乍看有点复杂,但是只要读者熟练Abstract
Factory情势,应该能很简单看懂,那正是Abstract
Factory在实际上中的3个用到。那里的Factory
Container作为获得点,是叁个静态类,它的“Type构造函数”依照外部的XML配置文件,决定实例化哪个工厂。上边仍然来看示例代码。由于差别组件的代码是相似的,这里只给出Button组件的演示代码,完整代码请参见文末附上的完整源程序。

mgm美高梅国际娱乐 7mgm美高梅国际娱乐 8

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    internal interface IButton
    {
        String ShowInfo();
    }
}

View Code

mgm美高梅国际娱乐 9mgm美高梅国际娱乐 10

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    internal sealed class WindowsButton : IButton
    {
        public String Description { get; private set; }

        public WindowsButton()
        {
            this.Description = "Windows风格按钮";
        }

        public String ShowInfo()
        {
            return this.Description;
        }
    }
}

View Code

mgm美高梅国际娱乐 11mgm美高梅国际娱乐 12

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    internal sealed class MacButton : IButton
    {
        public String Description { get; private set; }

        public MacButton()
        {
            this.Description = " Mac风格按钮";
        }

        public String ShowInfo()
        {
            return this.Description;
        }
    }
}

View Code

mgm美高梅国际娱乐 13mgm美高梅国际娱乐 14

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    internal interface IFactory
    {
        IWindow MakeWindow();

        IButton MakeButton();

        ITextBox MakeTextBox();
    }
}

View Code

mgm美高梅国际娱乐 15mgm美高梅国际娱乐 16

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    internal sealed class WindowsFactory : IFactory
    {
        public IWindow MakeWindow()
        {
            return new WindowsWindow();
        }

        public IButton MakeButton()
        {
            return new WindowsButton();
        }

        public ITextBox MakeTextBox()
        {
            return new WindowsTextBox();
        }
    }
}

View Code

mgm美高梅国际娱乐 17mgm美高梅国际娱乐 18

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    internal sealed class MacFactory : IFactory
    {
        public IWindow MakeWindow()
        {
            return new MacWindow();
        }

        public IButton MakeButton()
        {
            return new MacButton();
        }

        public ITextBox MakeTextBox()
        {
            return new MacTextBox();
        }
    }
}

View Code

mgm美高梅国际娱乐 19mgm美高梅国际娱乐 20

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace DependencyLocate
{
    internal static class FactoryContainer
    {
        public static IFactory factory { get; private set; }

        static FactoryContainer()
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load("http://www.cnblogs.com/Config.xml");
            XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0].ChildNodes[0];

            if ("Windows" == xmlNode.Value)
            {
                factory = new WindowsFactory();
            }
            else if ("Mac" == xmlNode.Value)
            {
                factory = new MacFactory();
            }
            else
            {
                throw new Exception("Factory Init Error");
            }
        }
    }
}

View Code

mgm美高梅国际娱乐 21mgm美高梅国际娱乐 22

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DependencyLocate
{
    class Program
    {
        static void Main(string[] args)
        {
            IFactory factory = FactoryContainer.factory;
            IWindow window = factory.MakeWindow();
            Console.WriteLine("创建 " + window.ShowInfo());
            IButton button = factory.MakeButton();
            Console.WriteLine("创建 " + button.ShowInfo());
            ITextBox textBox = factory.MakeTextBox();
            Console.WriteLine("创建 " + textBox.ShowInfo());

            Console.ReadLine();
        }
    }
}

View Code

此地我们用XML作为配置文件。配置文件Config.xml如下:

mgm美高梅国际娱乐 23mgm美高梅国际娱乐 24

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <factory>Mac</factory>
</config>

View Code

能够看看,那里大家将布署安装为Mac风格,编写翻译运营上述代码,运营结果如下:

mgm美高梅国际娱乐 25

图3.5 配置Mac风格后的周转结果

最近,大家不动程序,仅仅将配置文件中的“Mac”改为Windows,运维后结果如下:

mgm美高梅国际娱乐 26

图3.6 配置为Windows风格后的运转结果

从运维结果看出,大家惟有通过修改配置文件,就改变了全部程序的一颦一笑(大家照旧不曾重新编写翻译程序),那就是多态性的威力,也是重视注入效果。

本节共研讨了二种为主的重视注入种类,有关越多依赖注入连串和不一致种类比较的文化,能够参考马丁福勒的《Inversion of Control Containers and the Dependency Injection
pattern》。

目录

目录

1 IGame游戏公司的故事

    1.1 讨论会

    1.2 实习生小李的兑现方式

【mgm美高梅国际娱乐】依赖注入,依赖注入那些事儿。    1.3 架构师的提出

    1.4 小李的下结论

2 商讨重视注入

    2.1 旧事的启示

    2.2 正式定义重视注入

3 依赖注入那个事儿

    3.1 重视注入的花色

        3.1.1 Setter注入

        3.1.2 Construtor注入

        3.1.3 依赖获取

    3.2 反射与依靠注入

    3.3 多态的活性与依靠注入

        3.3.1 多态性的活性

        3.3.2 区别活性多态性信赖注入的挑选

4 IoC Container

    4.1 IoC Container出现的必然性

    4.2 IoC Container的分类

        4.2.1 重量级IoC Container

        4.2.2 轻量级IoC Container

    4.3 .NET平台上首屈一指IoC Container推荐介绍

        4.3.1 Spring.NET

        4.3.2 Unity

参考文献

3.3 多态的活性与依靠注入

4.2.2 轻量级IoC Container

还有一种IoC
Container,一般不借助外部配置文件,而重庆大学利用传参的Setter或Construtor注入,那种IoC
Container叫做轻量级IoC
Container。那种框架很灵活,使用方便,但屡次不安静,而且信赖点都以程序中的字符串参数,所以,不相符须求大规模替换和周旋安静的低活多态性,而对于高活多态性,有很好的意义。

Unity是二个非凡的轻量级IoC Container。

3.3 多态的活性与依靠注入

3.1.1 Setter注入

率先种正视注入的艺术,正是Setter注入,上边的例证中,将武器注入Role正是Setter注入。正式点说:

Setter注入(Setter
Injection)是指在客户类中,设置1个服务类接口类型的多少成员,并设置二个Set方法作为注入点,那个Set方法接受1个实际的服务类实例为参数,并将它赋给服务类接口类型的数据成员。

mgm美高梅国际娱乐 27

图3.1 Setter注入示意

上海教室彰显了Setter注入的结构示意图,客户类ClientClass设置IServiceClass类型成员_serviceImpl,并设置Set_ServiceImpl方法作为注入点。Context会负责实例化1个有血有肉的瑟维斯Class,然后注入到ClientClass里。

下边给出Setter注入的演示代码。

 

mgm美高梅国际娱乐 28mgm美高梅国际娱乐 29View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal interface IServiceClass
    {
        String ServiceInfo();
    }
}

 

mgm美高梅国际娱乐 30mgm美高梅国际娱乐 31View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal class ServiceClassA : IServiceClass
    {
        public String ServiceInfo()
        {
            return “我是ServceClassA”;
        }
    }
}

 

mgm美高梅国际娱乐 32mgm美高梅国际娱乐 33View Code

using System;
【mgm美高梅国际娱乐】依赖注入,依赖注入那些事儿。using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal class ServiceClassB : IServiceClass
    {
        public String ServiceInfo()
【mgm美高梅国际娱乐】依赖注入,依赖注入那些事儿。        {
            return “我是ServceClassB”;
        }
    }
}

 

mgm美高梅国际娱乐 34mgm美高梅国际娱乐 35View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal class ClientClass
    {
        private IServiceClass _serviceImpl;
 
        public void Set_ServiceImpl(IServiceClass serviceImpl)
        {
            this._serviceImpl = serviceImpl;
        }
 
        public void ShowInfo()
        {
            Console.WriteLine(_serviceImpl.ServiceInfo());
        }
    }
}

 

mgm美高梅国际娱乐 36mgm美高梅国际娱乐 37View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    class Program
    {
        static void Main(string[] args)
        {
            IServiceClass serviceA = new ServiceClassA();
            IServiceClass serviceB = new ServiceClassB();
            ClientClass client = new ClientClass();
 
            client.Set_ServiceImpl(serviceA);
            client.ShowInfo();
            client.Set_ServiceImpl(serviceB);
            client.ShowInfo();
        }
    }
}

 

运营结果如下:

mgm美高梅国际娱乐 38

图3.2 Setter注入运转结果

3.2 反射与依靠注入

忆起上边Dependency Locate的例子,大家就算采用了多态性和Abstract
Factory,但对OCP贯彻的不够彻底。在驾驭这一点前,朋友们一定要留心潜在扩大在哪儿,潜在会产出恢弘的地方是“新的组件种类”而不是“组件种类”,也便是说,那里大家只要组件就两种,不会追加新的零部件,但可能出现新的外观类别,如供给加一套Ubuntu风格的组件,大家得以新增UbuntuWindow、UbuntuButton、UbuntuTextBox和UbuntuFactory,并分别达成相应接口,那是适合OCP的,因为那是扩充。但我们除了修改配置文件,还要无可幸免的修改FactoryContainer,供给加二个拨出条件,那几个地点破坏了OCP。正视注入作者是没有能力消除那个题指标,但如若语言援助反射机制(Reflection),则这么些标题就消除。

大家思考,未来的难点是出在那边:对象最后仍然要通过“new”来实例化,而“new”只好实例化当前已有的类,假使前景有新类添加进去,必须修改代码。即使,我们能有一种办法,不是透过“new”,而是经过类的名字来实例化对象,那么大家就算将类的名字作为配置项,就能够达成在不改动代码的动静下,加载今后才面世的类。所以,反射给了语言“预言现在”的力量,使得多态性和依赖性注入的威力大增。

上面是引入反射机制后,对地方例子的改进:

mgm美高梅国际娱乐 39

图3.7 引入反射机制的Dependency Locate

能够观察,引入反射机制后,结构简单了诸多,三个反光工厂代替了此前的一堆工厂,Factory
Container也不须求了。而且现在有新组件类别参与时,反射工厂是不要改变的,只需变更配置文件就能够形成。上边给出反射工厂和布署文件的代码。

mgm美高梅国际娱乐 40mgm美高梅国际娱乐 41

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;

namespace DependencyLocate
{
    internal static class ReflectionFactory
    {
        private static String _windowType;
        private static String _buttonType;
        private static String _textBoxType;

        static ReflectionFactory()
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load("http://www.cnblogs.com/Config.xml");
            XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0];

            _windowType = xmlNode.ChildNodes[0].Value;
            _buttonType = xmlNode.ChildNodes[1].Value;
            _textBoxType = xmlNode.ChildNodes[2].Value;
        }

        public static IWindow MakeWindow()
        {
            return Assembly.Load("DependencyLocate").CreateInstance("DependencyLocate." + _windowType) as IWindow;
        }

        public static IButton MakeButton()
        {
            return Assembly.Load("DependencyLocate").CreateInstance("DependencyLocate." + _buttonType) as IButton;
        }

        public static ITextBox MakeTextBox()
        {
            return Assembly.Load("DependencyLocate").CreateInstance("DependencyLocate." + _textBoxType) as ITextBox;
        }
    }
}

View Code

配备文件如下:

mgm美高梅国际娱乐 42mgm美高梅国际娱乐 43

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <window>MacWindow</window>
    <button>MacButton</button>
    <textBox>MacTextBox</textBox>
</config>

View Code

反射不仅能够与Dependency Locate结合,也足以与Setter
Injection与Construtor
Injection结合。反射机制的引入,下降了依靠注入结构的复杂度,使得注重注入彻底符合OCP,并为通用重视注入框架(如Spring.NET中的IoC部分、Unity等)的规划提供了只怕性。

3.2 反射与依靠注入

回首上边Dependency Locate的事例,我们就算应用了多态性和Abstract
Factory,但对OCP贯彻的不够彻底。在知道那一点前,朋友们自然要留心潜在扩大在哪儿,潜在会产出扩展的地点是“新的零件类别”而不是“组件体系”,也便是说,那里我们如若组件就三种,不会大增新的零部件,但或者出现新的外观种类,如需求加一套Ubuntu风格的零件,大家得以新增UbuntuWindow、UbuntuButton、UbuntuTextBox和UbuntuFactory,并分别完成相应接口,那是契合OCP的,因为那是扩充。但我们除了修改配置文件,还要无可幸免的修改FactoryContainer,供给加一个分段条件,那一个地点破坏了OCP。信赖注入小编是绝非力量化解那一个题材的,但一旦语言帮忙反射机制(Reflection),则那一个难点就一蹴即至。

咱俩考虑,未来的难关是出在此间:对象最终照旧要经过“new”来实例化,而“new”只好实例化当前已有的类,若是前景有新类添加进去,必须修改代码。尽管,我们能有一种方法,不是通过“new”,而是经过类的名字来实例化对象,那么大家假诺将类的名字作为配置项,就足以兑今后不改动代码的景况下,加载今后才出现的类。所以,反射给了言语“预感以后”的力量,使得多态性和凭借注入的威力大增。

上面是引入反射机制后,对地点例子的一字不苟:

mgm美高梅国际娱乐 39

图3.7 引入反射机制的Dependency Locate

可以见到,引入反射机制后,结构不难了广大,一个反光工厂代替了在此之前的一堆工厂,Factory
Container也不须求了。而且其后有新组件体系到场时,反射工厂是不用改变的,只需变更配置文件就足以做到。上面给出反射工厂和布置文件的代码。

 

mgm美高梅国际娱乐 45mgm美高梅国际娱乐 46View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;
 
namespace DependencyLocate
{
    internal static class ReflectionFactory
    {
        private static String _windowType;
        private static String _buttonType;
        private static String _textBoxType;
 
        static ReflectionFactory()
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(“”);
            XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0];
 
            _windowType = xmlNode.ChildNodes[0].Value;
            _buttonType = xmlNode.ChildNodes[1].Value;
            _textBoxType = xmlNode.ChildNodes[2].Value;
        }
 
        public static IWindow MakeWindow()
        {
            return Assembly.Load(“DependencyLocate”).CreateInstance(“DependencyLocate.” + _windowType) as IWindow;
        }
 
        public static IButton MakeButton()
        {
            return Assembly.Load(“DependencyLocate”).CreateInstance(“DependencyLocate.” + _buttonType) as IButton;
        }
 
        public static ITextBox MakeTextBox()
        {
            return Assembly.Load(“DependencyLocate”).CreateInstance(“DependencyLocate.” + _textBoxType) as ITextBox;
        }
    }
}

 

布署文件如下:

 

mgm美高梅国际娱乐 47mgm美高梅国际娱乐 48View Code

<?xml version=”1.0″ encoding=”utf-8″ ?>
<config>
    <window>MacWindow</window>
    <button>MacButton</button>
    <textBox>MacTextBox</textBox>
</config>

 

反射不仅能够与Dependency Locate结合,也得以与Setter
Injection与Construtor
Injection结合。反射机制的引入,下跌了借助注入结构的复杂度,使得正视注入彻底符合OCP,并为通用正视注入框架(如Spring.NET中的IoC部分、Unity等)的宏图提供了恐怕性。

3.3.1 多态性的活性

这一节我们谈谈多态的活性及其与依靠注入类型选拔间密切的涉及。

率先表达,“多态的活性”这么些术语是小编个人定义的,因为作者没有找到既有的概念名词可以公布自小编的意味,所以就自个儿造了二个词。那里,某多态的活性是指被此多态隔断的扭转所爆发变化的屡屡程度,频仍程度越高,则活性越强,反之亦然。

上文说过,多态性能够凝集变化,不过,不一致的变迁,发生的作用是不等同的,这就使得多态的活性有所出入,那种差距影响了依赖注入的连串采用。

举例来说,本文最起始波及的器械多态性,其活性相当高,因为在十二分程序中,Role在一遍运维中恐怕更换多次器械。而现行我们假如Role也兑现了多态性,那是很也许的,因为在玩耍中,差别品类的剧中人物(如暗夜天使、牛头人、矮人等)很多性格和工作是想通的,所以很只怕由此一个IRole或AbstractRole抽象类完成多态性,不过,Role在实例化后(一般在用户登录成功后),是不会变动的,很少有游戏允许同贰个玩家在运维中变换Role类型,所以Role应该是一但实例化,就不会生成,但万一再实例化1个(如另三个玩家登录),则大概就变更了。最终,还有一种多态性是活性十分的低的,如我们耳熟能详的数据访问层多态性,即使我们贯彻了SQL
Server、Oracle和Access等三种数据库的访问层,并完成了依靠注入,但差不离遇不到程序运转着就改数据库或长期内数据库频仍转移的意况。

上述不一样的多态性,不但特征不相同,其目标一般也差异,计算如下:

高活多态性——指在客户类实例运转时期,服务类恐怕会转移的多态性。

中活多态性——指在客户类实例化后,服务类不会变动,但同一时间内设有的两样实例也许有所区别品种的服务类。

低活多态性——指在客户类实例化后,服务类不会改变,且同如今间内有着客户类都拥有同样类别的服务类。

以上三种多态性,比较好的事例便是上文提到的枪炮多态性(高活)、剧中人物多态性(中活)和数码访问层多态性(低活)。此外,我们说一种多态性是空中稳定的,即使同样客户类在同一时间内的保有实例都凭借相同类其余服务类,反之则名为空间不安静多态性。我们说一种多态性是时间稳定的,借使一个客户类在实例化后,所以来的劳务类不能够重复更改,反之则称之为时间不安定多态性。显明,高活多态性时空均不稳定;中活多态性是时间稳定的,但空间不平静;低活多态性时间空间均稳定。

4.2.1 重量级IoC Container

所谓重量级IoC
Container,是指一般用外表配置文件(一般是XML)作为重视源,并托管整个系统依次类的实例化的IoC
Container。那种IoC
Container,一般是承接了百分之百体系差不多拥有多态性的依靠注入工作,并承载了独具服务类的实例化学工业作,而且那个实例化重视于二个表面配置文件,那种IoC
Container,很像经过2个文书,定义整个连串多态结构,视野宏大,想要很好驾驭那种IoC
Container,需求自然的架构划设想计能力和增加的实践经验。

Spring和Spring.NET是重量级IoC Container的事例。一般的话,那种IoC
Container稳定性有余而活性不足,适合举行低活多态性的借助注入。

4.3.1 Spring.NET

mgm美高梅国际娱乐 49

Spring.NET是Java平台上Spring对.NET平台的移植,使用办法和Spring很像,并且成效强大,是.NET平台上大中型开发IoC
Container的首选之一。除了DI外,Spring.NET也包括AOP等许多成效。

Spring.NET的官方网站是:

4.1 IoC Container出现的必然性

上边切磋了很多凭借注入的话题。说道注重注入,就必须说IoC
Container(IoC容器),那么毕竟什么是IoC容器?我们还是先来看望它的出现背景。

咱俩领略,软件开发领域有句盛名的判断:不要再度发明轮子!因为软件开发讲求复用,所以,对于利用频仍的供给,总是有人设计各个通用框架和类库以减轻人们的开发负担。例如,数据持久化是尤其频仍的必要,于是种种OTiguanM框架应运而生;再如,对MVC的须要催生了Struts等一批用来促成MVC的框架。

乘胜面向对象分析与设计的进化和老成,OOA&D被进一步广泛应用于各系列别中,但是,大家理解,用OO就不容许并非多态性,用多态性就不恐怕毫无注重注入,所以,依赖注入变成了要命频仍的需求,而借使全部手工业完结,不但负责太重,而且还不难出错。再加上反射机制的阐发,于是,自然有人起初规划开发各个用于注重注入的专用框架。那些越发用来落到实处依靠注入功用的组件或框架,就是IoC
Container。

从那一点看,IoC
Container的出现有其历史必然性。近来,最有名的IoC只怕正是Java平台上的Spring框架的IoC组件,而.NET平台上也有Spring.NET和Unity等。

3.3.2 不一样活性多态的借助注入采纳

一般的话,高活多态性适合选取Setter注入。因为Setter注入最灵敏,也是绝无仅有允许在一如既往客户类实例运维时期变更服务类的注入格局。并且那种注入一般由上下文环境经过Setter的参数内定服务类类型,方便灵活,适合频仍转移的高活多态性。

对于中活多态性,则吻合选择Constructor注入。因为Constructor注入也是由上下文环境经过Construtor的参数钦赐服务类类型,但一些客户类实例化后,就不可能开始展览重复流入,有限帮忙了其时间稳定性。

而对于低活多态性,则吻合选择Dependency
Locate并合营文件配置进行重视注入,或Setter、Constructor合作配置文件注入,因为依赖源来自文件,若是要改成服务类,则要求改变配置文件,一则确定保证了低活多态性的时间和空中稳定性,二是改变配置文件的法子方便于广大服务类替换。(因为低活多态性一旦改变行为,往往规模十分的大,如替换整个数据访问层,假如利用Setter和Construtor传参,程序中须要改变的地点不胜枚举)

实为上,那种选取是因为差别的依靠注入类型有着不一样的安居,大家能够细细咀嚼“活性”、“稳定性”和“正视注入类型”之间密切的关联。

2.2 正式定义注重注入

下边,用多少正式一点的语言,定义重视注入产生的背景缘由和注重注入的意义。在读的经过中,读者能够构成方面包车型大巴例证进行领悟。

依傍注入产生的背景:

乘机面向对象分析与安插的发展,二个妙不可言的筹划,大旨标准之一就是将转移隔开,使得变化部分发生变化时,不变部分不受影响(那也是OCP的指标)。为了实现那一点,要动用面向对象中的多态性,使用多态性后,客户类不再直接正视服务类,而是依靠于八个华而不实的接口,那样,客户类就不能在中间直接实例化具体的服务类。不过,客户类在运营中又合理必要现实的服务类提供服务,因为接口是无法实例化去提供劳务的。就发出了“客户类不准实例化具体服务类”和“客户类需求实际服务类”这样一对抵触。为了消除那一个争辩,开发职员提议了一种方式:客户类(如上例中的Role)定义三个注入点(Public成员Weapon),用于服务类(完结IAttackStrategy的具体类,如伍德Sword、IronSword和MagicSword,也囊括今后加进去的富有完成IAttackStrategy的新类)的流入,而客户类的客户类(Program,即测试代码)负责依照事态,实例化服务类,注入到客户类中,从而缓解了那个龃龉。

借助注入的业钦点义:

注重注入(Dependency
Injection),是那样3个进度:由于某客户类只依靠于服务类的1个接口,而不借助于现实服务类,所以客户类只定义2个注入点。在程序运营进程中,客户类不直接实例化具体服务类实例,而是客户类的运营上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保障客户类的常规运维。

4.2.2 轻量级IoC Container

再有一种IoC
Container,一般不注重外部配置文件,而根本行使传参的Setter或Construtor注入,那种IoC
Container叫做轻量级IoC
Container。那种框架很利索,使用方便,但往往不安定,而且重视点都以先后中的字符串参数,所以,不吻合要求大规模替换和相对平静的低活多态性,而对此高活多态性,有很好的效应。

Unity是三个特出的轻量级IoC Container。

4.3 .NET平台上压倒元稹和白居易IoC Container推荐介绍

1.2 实习生小李的落成方式

在通过一番谈论后,项目COOPeter觉得有需求整理一下各方的眼光,他第叁询问小李的观点。小李是某学校总括机系大三学生,对游戏支付越发感兴趣,近来是IGame集团的一名实习生。

透过短暂的思索,小李解说了上下一心的见地:

“笔者觉得,那些须要能够这么实现。HP当然是怪物的1个本性成员,而武器是角色的一个属性成员,类型能够使字符串,用于描述近期剧中人物所装备的火器。角色类有多少个攻击方式,以被口诛笔伐怪物为参数,当执行二次攻击时,攻击格局被调用,而这几个点子首先判断当前剧中人物装备了哪些武器,然后据此对被口诛笔伐怪物的HP进行操作,以发出不一样作用。”

而在解说完后,小李也快速的在大团结的微型总计机上写了3个德姆o,来演示他的想法,德姆o代码如下。

 

mgm美高梅国际娱乐 50mgm美高梅国际娱乐 51View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IGameLi
{
    /// <summary>
    /// 怪物
    /// </summary>
    internal sealed class Monster
    {
        /// <summary>
        /// 怪物的名字
        /// </summary>
        public String Name { get; set; }
 
        /// <summary>
        /// 怪物的生命值
        /// </summary>
        public Int32 HP { get; set; }
 
        public Monster(String name,Int32 hp)
        {
            this.Name = name;
            this.HP = hp;
        }
    }
}

 

mgm美高梅国际娱乐 52mgm美高梅国际娱乐 53View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IGameLi
{
    /// <summary>
    /// 角色
    /// </summary>
    internal sealed class Role
    {
        private Random _random = new Random();
 
        /// <summary>
        /// 表示角色近来所持武器的字符串
        /// </summary>
        public String WeaponTag { get; set; }
 
        /// <summary>
        /// 攻击怪物
        /// </summary>
        /// <param name=”monster”>被攻击的天使</param>
        public void Attack(Monster monster)
        {
            if (monster.HP <= 0)
            {
                Console.WriteLine(“此怪物已死”);
                return;
            }
 
            if (“WoodSword” == this.WeaponTag)
            {
                monster.HP -= 20;
                if (monster.HP <= 0)
                {
                    Console.WriteLine(“攻击成功!怪物” + monster.Name + “已病逝”);
                }
                else
                {
                    Console.WriteLine(“攻击成功!怪物” + monster.Name + “损失20HP”);
                }
            }
            else if (“IronSword” == this.WeaponTag)
            {
                monster.HP -= 50;
                if (monster.HP <= 0)
                {
                    Console.WriteLine(“攻击成功!怪物” + monster.Name + “已去世”);
                }
                else
                {
                    Console.WriteLine(“攻击成功!怪物” + monster.Name + “损失50HP”);
                }
            }
            else if (“MagicSword” == this.WeaponTag)
            {
                Int32 loss = (_random.NextDouble() < 0.5) ? 100 : 200;
                monster.HP -= loss;
                if (200 == loss)
                {
                    Console.WriteLine(“出现暴击!!!”);
                }
 
                if (monster.HP <= 0)
                {
                    Console.WriteLine(“攻击成功!怪物” + monster.Name + “已归西”);
                }
                else
                {
                    Console.WriteLine(“攻击成功!怪物” + monster.Name + “损失” + loss + “HP”);
                }
            }
            else
            {
                Console.WriteLine(“角色手里没有武器,不可能攻击!”);
            }
        }
    }
}

 

mgm美高梅国际娱乐 54mgm美高梅国际娱乐 55View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IGameLi
{
    class Program
    {
        static void Main(string[] args)
        {
            //生成怪物
            Monster monster1 = new Monster(“小怪A”, 50);
            Monster monster2 = new Monster(“小怪B”, 50);
            Monster monster3 = new Monster(“关主”, 200);
            Monster monster4 = new Monster(“最终Boss”, 1000);
 
            //生成剧中人物
            Role role = new Role();
 
            //木剑攻击
            role.WeaponTag = “WoodSword”;
            role.Attack(monster1);
 
            //铁剑攻击
            role.WeaponTag = “IronSword”;
            role.Attack(monster2);
            role.Attack(monster3);
 
            //魔剑攻击
            role.WeaponTag = “MagicSword”;
            role.Attack(monster3);
            role.Attack(monster4);
            role.Attack(monster4);
            role.Attack(monster4);
            role.Attack(monster4);
            role.Attack(monster4);
 
            Console.ReadLine();
        }
    }
}

 

程序运转结果如下:

mgm美高梅国际娱乐 4

图1.2 小李程序的运行结果

 

3.1.2 构造注入

除此以外一种信赖注入格局,是透过客户类的构造函数,向客户类注入服务类实例。

组织注入(Constructor
Injection)是指在客户类中,设置3个服务类接口类型的数量成员,并以构造函数为注入点,那个构造函数接受四个现实的服务类实例为参数,并将它赋给服务类接口类型的数码成员。

mgm美高梅国际娱乐 57

图3.3 构造注入示意

图3.3是布局注入的示意图,能够看看,与Setter注入很相近,只是注入点由Setter方法变成了构造方法。那里要小心,由于组织注入只幸好实例化客户类时注入3次,所以一点注入,程序运维期间是心急火燎改变三个客户类对象内的服务类实例的。

由于组织注入和Setter注入的IServiceClass,ServiceClassA和ServiceClassB是千篇一律的,所以那里给出此外ClientClass类的言传身教代码。

 

mgm美高梅国际娱乐 58mgm美高梅国际娱乐 59View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConstructorInjection
{
    internal class ClientClass
    {
        private IServiceClass _serviceImpl;
 
        public ClientClass(IServiceClass serviceImpl)
        {
            this._serviceImpl = serviceImpl;
        }
 
        public void ShowInfo()
        {
            Console.WriteLine(_serviceImpl.ServiceInfo());
        }
    }
}

 

可以看来,唯一的变型正是构造函数取代了Set_ServiceImpl方法,成为了注入点。

4.3.1 Spring.NET

mgm美高梅国际娱乐 49

Spring.NET是Java平台上Spring对.NET平台的移植,使用方法和Spring很像,并且功效强大,是.NET平台上海大学中型开发IoC
Container的首要选拔之一。除了DI外,Spring.NET也席卷AOP等诸多功能。

Spring.NET的官方网站是: