博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
依赖注入
阅读量:5209 次
发布时间:2019-06-14

本文共 6159 字,大约阅读时间需要 20 分钟。

    很久以前就接触过依赖注入,一直也没怎么搞明白那是个什么东西,这两天发现书上专门有一章讲依赖注入的也仔细看了下,写出来,边理解边记录。

    为了更好地理解依赖注入,我们先来看一下设计模式中的控制反转模式。几乎每个人都编写过下面这段代码吧!  

public class EmailService    {        public void SendMessage() { }    }    public class NoticeSystem    {        private EmailService svc;        public NoticeSystem()        {            svc = new EmailService();        }        public void NoticeHappened()        {            svc.SendMessage();        }    }

    这里NoticeSystem和EmailService是高耦合(一个类知道与它交互的类的大量信息)的,为了降低二者的耦合性,一般采取两个独立的步骤:

    1>在两个代码块中间添加抽象层。下面的代码中绿色注释的是与前例不同的地方,主要任务是将NoticeSystem中的私有副本抽象成接口IMessageService,不再是具体的类型。    这里的IMessageService接口就是我们的依赖注入点.

  //比上上述例子多了IMessageService接口    public interface IMessageService    {        void SendMessage();    }    //比上上述例子多了IMessageService接口    public class EmailService : IMessageService //实现IMessageService接口    {        public void SendMessage() { }    }    public class NoticeSystem    {        private IMessageService svc; //EmailService变成了接口IMessageService        public NoticeSystem()        {            svc = new EmailService();        }        public void NoticeHappened()        {            svc.SendMessage();        }    }

    2>将选择抽象实现的责任移到消费者类的外部。就是说将上述代码中EmailService的创建也移到NoticeSystem的外部去。

    到这里我们就可以给控制反转下一个定义了:将依赖的创建移到使用这些依赖的类的外部,这称为控制反转模式,之所以这样命名,是因为反转的是依赖的创建,正因为如此,才消除了消费者类(NoticeSystem)对依赖创建的控制。让NoticeSystem类本身不能决定是创建EmailService、XXService还是XXXService

    要将svc=new EmailService();的创建从类NoticeSystem内部移出,有两种常见的方法:服务定位器和依赖注入上面讲到IMessageService是依赖注入点,所以依赖注入通俗的理解就是为依赖注入点IMessageService创建对象

    服务定位器:      

   ///     /// 服务定位器接口,GetMessageService方法用来返回一个IMessageService接口的对象    ///     public interface IServiceLocator    {        IMessageService GetMessageService();    }    ///     ///     ///     public class NoticeSystem    {        private IMessageService svc; //EmailService变成了接口IMessageService        public NoticeSystem(IServiceLocator locator)        {            svc = locator.GetMessageService();        }        public void NoticeHappened()        {            svc.SendMessage();        }    }    ///     /// 实现了       IServiceLocator接口的类EmailLocator    /// 返回实现了   IMessageService接口的类EmailService    ///     public class EmailLocator : IServiceLocator    {        public IMessageService GetMessageService()        {            return new EmailService();        }    }

 

   下图对上述代码做了一个补充,帮助我们来理解服务定位器。可以看到,强类型服务定位器有两个弊端:<1>如果我们为IMessageService又添加了一种服务后,服务定位器IServiceLocator也就要再添加一个类,来返回IMessageService新添加的类对象。<2>从图中我们可以清晰地看到EmailLocator返回的是EmailService对象,PhoneLocator返回的是PhoneService对象,但是这是建立在我们知道的基础上,那如果我把返回对象写反了,那即使返回了错误的对象也没人知道吧!所以有一种叫泛型的东西就出现了,这就是下面要说的的弱类型服务定位器。

   

 

    弱类型服务器看得一头雾水,正在研究中。

    直接说依赖注入吧。

    有了上面的基础,依赖注入就不难理解了。在使用服务定位器的情况下,我们要通过接口IServiceLocator来创建IMessageService对象。现在我们抛弃了IServiceLocator,他会很伤心的,但是我们真的不需要他了,他是多余的。我们直接用IMessageService对象来替代IServiceLocator的位置,就OK了。

    这个就是构造函数注入,通过NoticeSystem的构造函数对依赖注入点IMessageService svc创建依赖对象。

  public class NoticeSystem    {        private IMessageService svc; //EmailService变成了接口IMessageService        public NoticeSystem(IMessageService service)        {            this.svc = service;        }        public void NoticeHappened()        {            svc.SendMessage();

    还有就是属性注入,通过对属性赋值,实现依赖注入。      

public class NoticeSystem    {               public IMessageService svc        {            get;            set;        }        public void NoticeHappened()        {            svc.SendMessage();        }    }

    现在通过一个例子来看一下依赖注入的应用,有篇文章叫《依赖注入那些事》,借用下你的素材啊,不会告我侵权吧!......

    现在要实现下面这么个打怪功能,看需求

    

    说实话,我第一次做的时候真做的不怎么样。还是分析的不到位,现在一起来分析一下吧。

    首先:需求中的对象有什么?角色、武器、怪物

    然后:要求是什么呢? 1>角色可以装备不同的武器   2>不同的武器有不同的伤害   3>角色攻击怪物,怪物失血,没血了就死亡了。

    最后:分析一下这里面的对象与要实现的方法的关系,我一开始就是没搞清那个对象该实现哪个方法,最终代码写的一塌糊涂。

        1>角色装备武器,这个是角色与武器的关系,根据前面讲的依赖注入,可以放在角色的构造函数中实现。  

        2>不同的武器有不同的伤害,这个肯定是在武器类内部实现的,与角色没什么关系,角色只需要知道自己装备的是什么武器就可以了。但是与怪物又有些关系,因为装备不同的武器,怪物每次掉血是不一样的。

        3>角色、攻击、怪物,这三个分开来看,这里的“攻击”应该是角色的一个方法吧!而“怪物”是“角色”攻击的对象,应该是可变的,作为一个参数吧!因为我们打完小喽啰还要打大BOSS的啊,要不谁玩这个游戏呢?

       4>怪物失血,“失血”这个动作在哪里实现呢?应该是怪物这个对象失血,所以应该在怪物类内部实现,我一开始就写错了。

     角色:      

///     /// 角色    ///     public class Person    {        ///         /// 武器接口        ///         private IWeapon weapon;        ///         /// 构造函数        ///         ///         public Person(IWeapon weapon)        {            this.weapon = weapon;        }        ///         /// 打怪方法        ///         ///         public void Attrack(Monster monster)        {            weapon.Attack(monster);        }    }

    武器:(这里为了方便写在了一起,实际写的时候还是建新类比较好)    

///     /// 武器接口    ///     public interface IWeapon    {        void Attack(Monster monster);    }    ///     /// 木剑    ///     public class WoodSword : IWeapon    {        public void Attack(Monster monster)        {            monster.LessBlood(20);        }    }    ///     /// 铁剑    ///     public class IronSword : IWeapon    {        public void Attack(Monster monster)        {            monster.LessBlood(50);        }    }    ///     /// 魔剑    ///     public class MagicSword : IWeapon    {        private Random _random = new Random();        public void Attack(Monster monster)        {            int loss = (_random.NextDouble() < 0.5) ? 100 : 200;            if (loss == 200)                Console.WriteLine("出现暴击!!");            monster.LessBlood(loss);        }    }

    怪物:    

///     /// 怪物    ///     public class Monster    {        ///         /// 怪物名字        ///         public string Name { get; set; }        ///         /// 怪物血量        ///         public int Blud { get; set; }        ///         /// 构造函数        ///         ///         ///         public Monster(string name, int blud)        {            this.Name = name;            this.Blud = blud;        }        ///         /// 怪物掉血        ///         ///         public void LessBlood(int less)        {            while (this.Blud > 0)            {                this.Blud -= less;                Console.WriteLine(this.Name+"减去"+less+"血!");            }                Console.WriteLine(this.Name+"已死!");        }    }

    到这里,依赖注入就算是学习完了。

    

      

      

  

转载于:https://www.cnblogs.com/feiDD/articles/2881203.html

你可能感兴趣的文章
关于安装虚拟机
查看>>
GRPC 截止时间与元数据
查看>>
request.getAttribute()和request.getParameter()区别
查看>>
Python导出Excel为Lua/Json/Xml实例教程(二):xlrd初体验
查看>>
Linux_学习_Day1
查看>>
英语口语练习系列-C16-钱
查看>>
回忆我的大学
查看>>
hibernate + hsqldb单元测试
查看>>
OO_JAVA_表达式求导_单元总结
查看>>
父类的属性或者方法被private修饰过之后,子类是否能继承的问题,以及this和super的区别...
查看>>
java之理解面向对象
查看>>
java——数据类型和运算符
查看>>
java——值传递和引用传递
查看>>
java——内存中的数组
查看>>
java——面向对象
查看>>
java类的访问修饰符
查看>>
java字节和字符的区别
查看>>
java之Lambda表达式
查看>>
java中的自动装箱和拆箱
查看>>
java之集合那些事
查看>>