第一次看到TinyIoCContainer是在用NancyFx的時候,在Bootstrapper那里看到了她的影子。
那些叫Tiny的東西都挺有意思,IoC容器是我第一次遇到,于是找了些文章看了看,自己寫了點代碼實踐下,這件事就算這么過了,然后今天想起來,在做下筆記。
首先是Dip的概念:依賴倒置原則,OOD的產物。
那么IoC就是DIP的實現方式,用我粗糙的話來說就是類依賴抽象就不在類內部自己new,交給別人new好了再用。
來一個應用場景:
玩家玩游戲機。
代碼差不多這樣:
1 interface IGameMachine 2 { 3 void Launch(); 4 } 5 6 class Player 7 { 8 public IGameMachine GameMachine; 9 10 public void Play()11 {12 if(GameMachine!=null)13 GameMachine.Launch();14 }15 }16 17 class PS3 : IGameMachine18 {19 public void Launch()20 {21 Console.WriteLine("索尼大法好,PS3開起來啦!");22 }23 }
這里定義了一個Player類表示玩家,玩家玩的是游戲機,并不指定是什么游戲機,所以有個可以“跑”的游戲機接口,PS3實現了這個接口。那么我就可以在通過賦值更換玩家手上的游戲機來玩PS3了。
1 Player player = new Player();2 player.GameMachine = new PS3();3 player.Play();
這樣就實現了上面說的“不在類內部new,交給別人new”這一點。
交給TinyIoCContainer來完成就是這樣:
1 TinyIoCContainer tiny = new TinyIoCContainer();2 tiny.Register<IGameMachine, PS3>();3 Player player = new Player4 {5 GameMachine = tiny.Resolve<IGameMachine>()6 };7 player.Play();
大多數情況下,在項目中遇到的還沒這種可能隨時更換的,而是一旦啟動就不更換的組件,像數據庫之類的,這樣的情況下,這個接口成員就可以不public出來,而是PRivate并且通過構造函數初始化。
還是同樣的應用場景,只是玩家都變得很窮很窮了,一輩子就只能買一臺游戲機。改造下Player類之后,我們可以這樣使用TinyIoCContainer了:
class Player { private readonly IGameMachine _gameMachine; public Player(IGameMachine gameMachine) { _gameMachine = gameMachine; } public void Play() { if (_gameMachine != null) _gameMachine.Launch(); else Console.WriteLine("沒初始化"); } } static void Main(string[] args) { TinyIoCContainer tiny = new TinyIoCContainer(); tiny.Register<IGameMachine, PS3>(); Player player = tiny.Resolve<Player>(); player.Play(); Console.ReadLine(); }
哈,這里只是注冊了IGameMachine對應PS3,也可以Resolve出Player來,并且通過構造函數創建了PS3呢。
于是,再進一步想一下,假如GameMachine也有依賴的抽象需要實現呢?
那么應用場景再進一步調整:
玩家有一臺游戲機,游戲機可以插各種游戲卡帶
那么游戲機就有了一個屬性游戲卡帶,我也希望游戲卡帶能通過構造函數初始化。上面說過的DIP的概念只是說依賴抽象,所以,游戲機從接口抽象改成了抽象類。
1 class GameBoy : GameMachine 2 { 3 protected override void OnPlay() 4 { 5 Console.WriteLine("我是任飯,我玩GameBoy!"); 6 } 7 8 public GameBoy(GameCard currentCard) : base(currentCard) 9 {10 11 }12 }13 14 abstract class GameMachine15 {16 private GameCard _currentCard;17 18 protected GameMachine(GameCard currentCard)19 {20 _currentCard = currentCard;21 }22 23 public void Launch()24 {25 OnPlay();26 Console.WriteLine("我在玩{0}", _currentCard.Name);27 }28 29 protected abstract void OnPlay();30 }31 32 public abstract class GameCard33 {34 public abstract string Name { get; }35 }36 37 public class PoketMonster:GameCard38 {39 public override string Name40 {41 get { return "口袋藍"; }42 }43 }
稍微更改下Player類,替換接口IGameMachine成抽象類GameMachine。
那么使用的時候,我們在容器中注冊GameCard為PoketMonster,GameMachine為GameBoy試試看。
1 static void Main(string[] args) 2 { 3 TinyIoCContainer tiny = new TinyIoCContainer(); 4 tiny.Register<GameMachine, GameBoy>(); 5 tiny.Register<GameCard, 口袋妖怪>(); 6 7 Player p = tiny.Resolve<Player>(); 8 p.Play(); 9 10 Console.ReadLine();11 }
運行輸出

新聞熱點
疑難解答