IoC模式简单学习

来源:互联网 发布:淘宝全屏海报轮播代码 编辑:程序博客网 时间:2024/06/07 09:50

1.依赖

依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖。如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它。下面看一个简单的示例:

复制代码
    /// <summary>    /// 用户播放媒体文件    /// </summary>    public class OperationMain    {        public void PlayMedia()        {            MediaFile _mtype = new MediaFile();            Player _player = new Player();            _player.Play(_mtype);        }    }    /// <summary>    /// 播放器    /// </summary>    public class Player    {        public void Play(MediaFile file)        {            Console.WriteLine(file.FilePath);        }    }    /// <summary>    /// 媒体文件    /// </summary>    public class MediaFile    {        public string FilePath { get; set; }    }
复制代码

上面是一个用户用播放器播放文件简单示例,用户操作是OperationMain类中的PlayMedia方法,打开一个播放器,选择一个文件来播放。先看看他们之间的依赖关系,可以简单找到有3个依赖

  1. Player依赖MediaFile
  2. OperationMain依赖Player
  3. OperationMain依赖MediaFile

2.依赖倒置

需求增加了,要用不同的播放器,播放不同的文件,我们要抽象出来,减少耦合。

耦合关系就是依赖关系,如果依赖关系相当繁杂,牵一发而动全身,很难维护;依赖关系越少,耦合关系就越低,系统就越稳定,所以我们要减少依赖。

幸亏Robert Martin大师提出了面向对象设计原则----依赖倒置原则:   

  • A. 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。  
  • B. 抽象不能依赖于具象,具象依赖于抽象。

理解:A.上层是使用者,下层是被使用者,这就导致的结果是上层依赖下层了,下层变动了,自然就会影响到上层了,导致系统不稳定,甚至是牵一发而动全身。那怎么减少依赖呢?就是上层和下层都去依赖另一个抽象,这个抽象比较稳定,整个就来说就比较稳定了。

B.面向对象编程时面向抽象或者面向借口编程,抽象一般比较稳定,实现抽象的具体肯定是要依赖抽象的,抽象不应该去依赖别的具体,应该依赖抽象。

 

上面播放器的示例中,我们已经找到依赖关系了,现在我们要按照依赖倒置原则,来进行优化。

根据原则如下改动:

  • Player依赖MediaFile,好办,让Player和MediaFile都去依赖一个抽象IMediaFile
  • OperationMain依赖Player,好办,让OperationMain和Player都依赖一个抽象IPlayer
  • OperationMain依赖MediaFile,好办,让OperationMain和MediaFile都依赖一个抽象IMediaFile
  • IPlayer不能依赖具体MediaFile,应该依赖于具体MediaFile的抽象IMediaFile

结构很简单,于是代码大致如下:

复制代码
    /// <summary>    /// 用户播放媒体文件    /// </summary>    public class OperationMain    {        public void PlayMedia()        {            IMediaFile _mtype = new MediaFile();            IPlayer _player = new Player();            _player.Play(_mtype);        }    }    /// <summary>    /// 播放器    /// </summary>    public interface IPlayer    {        void Play(IMediaFile file);    }    /// <summary>    /// 默认播放器    /// </summary>    public class Player : IPlayer    {        public void Play(IMediaFile file)        {            Console.WriteLine(file.FilePath);        }    }    /// <summary>    /// 媒体文件    /// </summary>    public interface IMediaFile    {        string FilePath { get; set; }    }    /// <summary>    /// 默认媒体文件    /// </summary>    public class MediaFile : IMediaFile    {        public string FilePath { get; set; }    }
复制代码

上面代码进行了抽象,可以看到,目的是减少了依赖,但是看上去依赖关系增加了,如用户PlayMedia方法,依赖还增加了依赖接口和具体的实现,但是接口是稳定的,可以不考虑,具体的实现才是变动的,这个依赖还是要的,要播放文件,必定要用到具体的播放器和具体文件。

3.控制反转(IoC)

现实生活中,是具体的播放器和具体的媒体文件没有关系,你给它一个Mp3文件他可以播放,给它一个Mp4文件它也可以播放,你删掉你的媒体文件,播放器照样在,具体什么播放器,播放什么文件,控制权全部是我们用户自己。

上面的示例中基本实现了隔离,具体的播放器跟具体的媒体隔离了,具体的播放器只跟媒体接口和播放器接口有关。但是PlayMedia的方法里面的具体对象,写死了,控制权非常小,如果我想用百度影音播放呢,我想换一首音乐呢,只能重新改代码,那控制怎么进行转移呢?

我们可以通过反射来创建,把具体的文件名写在配置文件里,这时候客户端代码也不用变了,只需要改配置文件就好了,稳定性又有了提高,如下:

复制代码
        public void PlayMedia()        {            IMediaFile _mtype = Assembly.Load(ConfigurationManager.AppSettings["AssemName"]).CreateInstance(ConfigurationManager.AppSettings["MediaName"]);            IPlayer _player = Assembly.Load(ConfigurationManager.AppSettings["AssemName"]).CreateInstance(ConfigurationManager.AppSettings["PlayerName"]);            _player.Play(_mtype);        }
复制代码

这个具对象是哪一个,全由配置文件来控制了,这个具体对象的控制权交给了配置文件了,这也是人们常说的控制反转。

控制反转IoC是Inversion of Control的缩写,是说对象的控制权进行转移,转移到第三方,比如转移交给了IoC容器,它就是一个创建工厂,你要什么对象,它就给你什么对象,有了IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。

4.依赖注入(DI)

上面说到控制反转,是一个思想概念,但是也要具体实现的,上面的配置文件也是一种实现方式。依赖注入提出了具体的思想。

依赖注入DI是Dependency Injection缩写,它提出了“哪些东东的控制权被反转了,被转移了?”,它也给出了答案:“依赖对象的创建获得被反转”。

所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。

上面的示例中,哪些要依赖注入,依赖对象需要获得实例的地方,即 PlayMedia方法,需要IPlayer具体对象和IMediaFile的具体对象,找到了地方就从这里下手,为了灵活的控制这两个对象,必须是外面能够控制着两个对象的实例化,提供对外的操作是必要的,可以是属性,可以是方法,可以是构造函数,总之别的地方可以控制它,下面将会使用Unity来注入,使用的是构造函数注入,代码如下:

复制代码
    /// <summary>    /// 用户播放媒体文件    /// </summary>    public class OperationMain    {        IMediaFile _mtype;        IPlayer _player;        public OperationMain(IPlayer player, IMediaFile mtype)        {            _player = player;            _mtype = mtype;        }        public void PlayMedia()        {            _player.Play(_mtype);        }    }    /// <summary>    /// 播放器    /// </summary>    public interface IPlayer    {        void Play(IMediaFile file);    }    /// <summary>    /// 默认播放器    /// </summary>    public class Player : IPlayer    {        public void Play(IMediaFile file)        {            Console.WriteLine(file.FilePath);        }    }    /// <summary>    /// 媒体文件    /// </summary>    public interface IMediaFile    {        string FilePath { get; set; }    }    /// <summary>    /// 默认媒体文件    /// </summary>    public class MediaFile : IMediaFile    {        public string FilePath { get; set; }    }
复制代码

给 OperationMain类一个构造函数,因为Unity有一个构造函数注入,调用代码如下:

复制代码
        static UnityContainer container = new UnityContainer();        static void init()        {            container.RegisterType<IPlayer, Player>();            container.RegisterType<IMediaFile, MediaFile>();        }        static void Main(string[] args)        {            init();            OperationMain op1 = container.Resolve<OperationMain>();            op1.PlayMedia();            OperationMain op3 = container.Resolve<OperationMain>();            op3.PlayMedia();            //普通方式            OperationMain op2 = new OperationMain(new Player(), new MediaFile());            op2.PlayMedia();            Console.Read();        }
复制代码

看出来吧,Unity的功能远不止这些,你可以初始化时注册N多,以后直接使用,而不用使用new,还有实例周期的控制、配置文件等灵活控制,具体可以看看Unity(具体不是本节的范畴)的说明。

5.小结

通过一个小例子由浅入深地进行优化,已加深对IoC模式的理解,我想复杂的结构也是从这种简单的架构累加起来的。

最近在看相关文章,很多都太专业化了没怎么看懂,这是自己现在对IoC的一些理解,记录下来,要不然时间一久,也就忘了。

自己对IoC模式理解还很浅,希望得到各位的指点。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 八十多了膀胱癌手术复发了怎么办 尿蛋白和尿隐血2个加怎么办 小肝癌手术后两个月又复发了怎么办 膀胱癌血尿堵塞尿道和尿管怎么办 肾炎腰疼一条腿疼尿血怎么办 孕晚期尿常规检查尿蛋白高怎么办? 腰开车疼的不会动了怎么办 小孩跑完满头大汗就咳嗽怎么办 小孩剧烈咳嗽喘吃了药不管用怎么办 做什么事都有点轻微的手抖怎么办 见到喜欢的人做事情就手抖怎么办 做了尿结石手术还尿血怎么办 宝宝十一个大运动发展缓慢怎么办 一岁八个月宝宝肚里有蛔虫怎么办 孕妇5个月了缺碘怎么办 4个月婴儿折了下腰怎么办 签了居间合同网签合同有异议怎么办 魅族3s手机返回键失灵怎么办 英语冠词和名词的关系用不好怎么办 炸好了的肉梭子不脆了怎么办 跑步的时候胸抖的疼怎么办 小区内安装了乒乓球桌扰民了怎么办 裁判出示红牌如果球员不走怎么办 高三文化课不好又没有特长怎么办 孩子做事磨蹭拖拉不讲效率怎么办 宝贝幼儿园哭的嗓子哑了怎么办 我给孩子转学学校不接收怎么办 眼睛被太阳晒了胀豉豉的怎么办 电脑电源灯亮着屏幕是黑的怎么办 刚办健身卡健身房跑路了怎么办 孕妇怀孕初期胖的太快怎么办 魔幻陀螺二的陀螺拆不动怎么办 我不干了小厂不给我发工资怎么办 货车司机把人撞成重伤没钱出怎么办 房主卖房定金收了不想卖怎么办 领导迟迟不给升职加薪机会怎么办 加工中心铣圆进出刀有接刀痕怎么办 烧茄子时炸茄子茄子太吸油怎么办? 梦金园黄金刚买了不给退怎么办 给同学抄作业被老师发现了怎么办 不准体罚和变相体罚后熊孩子怎么办