【发布时间】: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 等。
标签: c# .net dependency-injection inversion-of-control ioc-container