前提:
什么是可扩展性良好的程序:在需求变更或需求增加时,不需要修改代码,而是增加代码的方式来适应需求的变化。
现假设需要拍一个电影的场景:
需要剧本(Screenplay),演员(Palyer),导演(Director)。
导演按照剧本的流程,挑选演员去完成拍戏工作。
1. 最一般,最直接的实现是这样写的:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Com.DeepLeo.IOC.Normal { class Program { static void Main(string[] args) { Screenplay screenplay = new Screenplay(); screenplay.Paly(); Console.ReadKey(); } /// <summary> /// 剧本 /// </summary> public class Screenplay { public string Name { private set; get; } public Screenplay() { Name = "China"; } public void Paly() { Palyer palyer = new Palyer(); palyer.Play("Play"); } } /// <summary> /// 演员 /// </summary> public class Palyer { public void Play(string mes) { Console.WriteLine(mes); } } } }
这样写的不足:如果需要更换演员,需要重写剧本(Screenplay)或者直接更改Palyer类,也就是无法以最小的代码更改来达到需求变更的需要。这样需要修改大量代码,不是好的设计。
2.对选择演员的“控制”反转给剧本:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Com.DeepLeo.IOC.IndependenceRole { class Program { static void Main(string[] args) { Screenplay screenplay = new Screenplay(); screenplay.Driver(); Console.ReadKey(); } public class Screenplay { public string Name { private set; get; } public Screenplay() { Name = "China"; } public void Driver() { Palyer palyer= new MoviePalyer(); palyer.Play(); } } public abstract class Palyer { public abstract void Play(); } public class MoviePalyer : Palyer { public override void Play() { Console.WriteLine("Paly a movie"); } } public class TelePalyer : Palyer { public override void Play() { Console.WriteLine("Paly a teleplay"); } } } }
这个的好处是剧本可以选择演员了,想排成电影就用演电影的演员,想排成电视剧就用电视剧的演员。很好了降低了演员变更对剧本的影响。
但是:在适应这个变化是以改剧本为代价的。有什么方法在换演员的时候不需要该剧本也可以达到同样的效果呢?
3. 将更改剧本的“控制”反转给导演,由导演来决定。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Com.DeepLeo.IOC.IndependenceRole { class Program { static void Main(string[] args) { Director director = new Director(); director.Drive(); Console.ReadKey(); } public class Director { public Director() { } public void Drive() { Palyer palyer = new MoviePalyer();//导演想拍电影 Screenplay screenplay = new Screenplay(palyer); screenplay.Run(); } } public class Screenplay { public Palyer Palyer { set; get; } public string Name { private set; get; } public Screenplay(Palyer palyer) { Palyer = palyer; Name = "China"; } public void Run() { Palyer.Play(); } } public abstract class Palyer { public abstract void Play(); } public class MoviePalyer : Palyer { public override void Play() { Console.WriteLine("Paly a movie"); } } public class TelePalyer : Palyer { public override void Play() { Console.WriteLine("Paly a teleplay"); } } } }
好处:不管你是改剧本还是改导演,只需要修改Director类就可以了,剧本和演员可以按照导演的喜好随意改。
譬如:导演想拍电视剧版的:
Palyer palyer = new TelePalyer (); Screenplay screenplay = new Screenplay(palyer); screenplay.Run();
换剧本与换演员是一样的道理。
当然,你也可以用接口实现IOC
4.利用接口依赖注入,Screenplay 实现IInjectPalyer接口来注入,控制权还是在导演手中。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Com.DeepLeo.IOC.InterfaceInjectScreenplay { class Program { static void Main(string[] args) { Director director = new Director(); director.Drive(); Console.ReadKey(); } public interface IInjectPalyer { void InjectPalyer(Palyer palyer); } public class Director { public Director() { } public void Drive() { Palyer palyer = new MoviePalyer(); Screenplay screenplay = new Screenplay(); screenplay.InjectPalyer(palyer); screenplay.Run(); } } public class Screenplay : IInjectPalyer { public Palyer Palyer { private set; get; } public void InjectPalyer(Palyer palyer) { Palyer = palyer; } public string Name { private set; get; } public Screenplay() { Name = "China"; } public void Run() { Palyer.Play(); } } public abstract class Palyer { public abstract void Play(); } public class MoviePalyer : Palyer { public override void Play() { Console.WriteLine("Paly a movie"); } } public class TelePalyer : Palyer { public override void Play() { Console.WriteLine("Paly a teleplay"); } } } }
以上仅仅是我对IOC概念的理解,希望对大家有所帮助。