我对IOC控制反转,依赖注入原理的理解

前提:

什么是可扩展性良好的程序:在需求变更或需求增加时,不需要修改代码,而是增加代码的方式来适应需求的变化。

现假设需要拍一个电影的场景:

需要剧本(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概念的理解,希望对大家有所帮助。

 转自:http://www.deepleo.com/archives/782

源代码:https://files.cnblogs.com/deepleo/IOC.zip

posted @ 2012-03-30 17:33  夜の魔王  阅读(1572)  评论(4编辑  收藏  举报