我应该使用构造函数注入还是 IoC.Resolve?
Posted
技术标签:
【中文标题】我应该使用构造函数注入还是 IoC.Resolve?【英文标题】:Should I use Constructor Injection or IoC.Resolve? 【发布时间】:2016-02-20 13:26:12 【问题描述】:我正在构建非常简单的棋盘游戏(只是为了学习一些新东西)。它将是跨平台的(使用 Xamarin 编写)。我已经编写了游戏的核心,但我不确定(仍然)应该使用 构造函数注入 还是 IoC 解析。现在我使用 IoC.Resolve 然后传递参数。
这是我的代码。我有 Game
有 2 个依赖项和类型。我有工厂来创建游戏和播放器:
Abc.MyGame.Domain
接口
public interface IGame
GameType GameType get;
IGameBoard GameBoard get;
List<IPlayer> Players get;
// Other stuff...
public interface IGameBoard
//board stuff...
public interface IPlayer
int PlayerId get; set;
PlayerType PlayerType get; set;
工厂接口
public interface IGameFactory
IGame CreateGame(GameType type, IGameBoard board);
public interface IPlayerFactory
IPlayer CreatePlayer(PlayerType type, int id);
工厂
public class GameFactory : IGameFactory
public IGame CreateGame(GameType type, IGameBoard board)
switch (type)
case GameType.SinglePlayer:
return new MyGame(type, board,
new List<IPlayer> CreateHuman(1), CreateBot(2) );
case GameType.TwoPlayers:
return new MyGame(type, board,
new List<IPlayer> CreateHuman(1), CreateHuman(2) );
case GameType.Online:
return new MyGame(type, board,
new List<IPlayer> CreateHuman(1), CreateOnlinePlayer(2) );
return null;
然后,有一个 API。由 UI 使用:
Abc.MyGame.API
public class GameAPI
public IGame CurrentGame get; set;
public IGame CreateGame(IGameFactory gameFactory, GameType type, IBoard board)
CurrentGame = gameFactory.CreateGame(type, board);
return CurrentGame;
// Other stuff, like make move etc...
...和我的用户界面:
Abc.MyGame.UI.WinForms
public partial class Form1 : Form
private GameAPI api = new GameAPI();
IKernel kernel = new StandardKernel();
public Form1()
InitializeComponent();
// Load all dependencies
var modules = new List<INinjectModule> new GameModule() ;
kernel.Load(modules);
private void buttonStartGame(object sender, EventArgs e)
IGameBoard board = kernel.Get<IGameBoard>(
new ConstructorArgument("width", 7),
new ConstructorArgument("height", 6)
);
api.CreateGame(kernel.Get<IGameFactory>(), GameType.TwoPlayers, board);
我需要在我的IGame
中添加IGameBoard
。只有那里。我需要将棋盘和玩家注入IGame
。
这是我的问题/疑问:
我真的需要在程序的最“前端”解析IGameBoard
吗?当有人单击“开始游戏”按钮时,我在UI
中解决了它。然后我通过API
传递这个板,然后我将它传递给GameFactory
,然后我将它传递给Game
构造函数(终于!)。在GameFactory
中创建(或解决)IPlayerFactory
和IGameBoard
是一种不好的做法吗? API.CreateGame
在这种情况下将只有 type
参数?我的意思是对于特定的 GameFactory 只有一个板(每次都一样),所以我不确定我是否需要在一开始就创建板......
编辑: MyGame 构造函数:
public class MyGame : IGame
public IBoard Board get;
public GameType Type get;
public List<IPlayer> Players get;
public MyGame(GameType type, IBoard board, List<IPlayer> players)
Type = type;
Board = board;
Players = players;
//...
【问题讨论】:
您是否应该使用构造函数注入与属性注入或注入与从对象内解析? @DStanley 构造函数注入与从对象内解析。我是否应该在 UI 项目中解析IGameBoard
并通过构造函数通过 GameAPI
、GameFactory
将解析的实例注入到 Game
或......在创建 GameFactory
的对象中解析它 MyGame
?
简短的回答是你应该支持构造函数注入而不是其他模式;特别是Service Locator, which is an anti-pattern。不过,尚不清楚为什么您必须通过层传递board
。为什么GameAPI.CreateGame
将IGameBoard
作为参数?为什么IGameFactory.CreateGame
? (为什么GameAPI.GameFactory
是一个可设置的属性?)
@MarkSeemann 我知道 Service Locator anit-pattern。这就是我问这个问题的原因。 为什么你必须通过层传递板? - 因为,当我打电话给api.CreateGame
时,我知道它取决于板(它需要板)。我可以跳过它,通过GameFactory.CreateGame
中的new
创建板-但我认为这很糟糕。 为什么 GameAPI.CreateGame 将 IGameBoard 作为参数? - 我需要一个棋盘来创建游戏。不是构造函数注入吗?
@MarkSeemann 为什么 GameAPI.GameFactory 是可设置的属性? - 抱歉,这是个错误。我修好了它。 CurrentGame 稍后在课程中用于:CurrentGame.MakeMove 等。
【参考方案1】:
我真的需要在程序的最“前端”解析 IGameBoard 吗?
是的,需要在应用程序的入口点和生命周期范围(如果有)的开始处解决依赖关系。通常,这是抽象的(就像在 ASP.NET MVC 中一样),因此您永远不必自己调用 kernel.Get<>
(或任何其他 container.Resolve<>
)。在 WinForms 中没有这样的机制,所以你必须自己解决依赖关系,最好只有这样的根依赖:
public static class Program
private static void Main()
var kernel = new StandardKernel();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(kernel.Get<Form1>());
通过在您的主窗体上放置正确的依赖项(可能在您的游戏案例中包括一个工厂),您的应用程序中应该不再需要kernel.Get<>
。
【讨论】:
以上是关于我应该使用构造函数注入还是 IoC.Resolve?的主要内容,如果未能解决你的问题,请参考以下文章