前提:
什么是可扩展性良好的程序:在需求变更或需求增加时,不需要修改代码,而是增加代码的方式来适应需求的变化。
现假设需要拍一个电影的场景:
需要剧本(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概念的理解,希望对大家有所帮助。