前言
新手使用Zenject框架经常会遇到一个头痛的问题,怎么样在游戏启动以后动态创建新物体;
假如你做一个游戏需要生成很多的敌人(Enemies),然后你将会去构建新的敌人实类,
并且要确保这些敌人实类会注入到框架里面,建议使用工厂来处理
摘要
DI框架重要的部分是储备使用容器,严格的遵循"Composition Root Layer"组合跟节点层;
DiContainer容器类包括自身的自动引用,因此将无法阻止你忽略这个规则并且注入容器任意你想要的类,代码示例:
public class Enemy
{
DiContainer Container;
public Enemy(DiContainer container)
{
Container = container;
}
public void Update()
{
...
var player = Container.Resolve<Player>();
WalkTowards(player.Position);
...
etc.
}
}
然而,上面的代码是一个反面例子,可以正常运行,你可以使用Container访问游戏里面其他的类,
如果你这样做的话,严格意义上来说,这不是DI框架的魅力所在;
当然,你可以这样编写代码:
public class Enemy
{
Player _player;
public Enemy(Player player)
{
_player = player;
}
public void Update()
{
...
WalkTowards(_player.Position);
...
}
}
但现在,每一个创建新Enemy的地方需要补充一个Player的实例,这样违背了软件设计原则的开闭原则,
当使用工厂来处理以后,Zenject会自动补充另外需要的实类
代码示例
public class Player
{
}
public class Enemy
{
readonly Player _player;
public Enemy(Player player)
{
_player = player;
}
public class Factory : PlaceholderFactory<Enemy>
{
}
}
public class EnemySpawner : ITickable
{
readonly Enemy.Factory _enemyFactory;
public EnemySpawner(Enemy.Factory enemyFactory)
{
_enemyFactory = enemyFactory;
}
public void Tick()
{
if (ShouldSpawnNewEnemy())
{
var enemy = _enemyFactory.Create();
// ...
}
}
}
public class TestInstaller : MonoInstaller
{
public override void InstallBindings()
{
Container.BindInterfacesTo<EnemySpawner>().AsSingle();
Container.Bind<Player>().AsSingle();
Container.BindFactory<Enemy, Enemy.Factory>();
}
}
通过使用Ememy.Factory来替代new Enemy,所有的敌人引用类,类如Player类会自动填充;
我们也可以给工厂添加参数,代码示例:
public class Enemy
{
readonly Player _player;
readonly float _speed;
public Enemy(float speed, Player player)
{
_player = player;
_speed = speed;
}
public class Factory : PlaceholderFactory<float, Enemy>
{
}
}
public class EnemySpawner : ITickable
{
readonly Enemy.Factory _enemyFactory;
public EnemySpawner(Enemy.Factory enemyFactory)
{
_enemyFactory = enemyFactory;
}
public void Tick()
{
if (ShouldSpawnNewEnemy())
{
var newSpeed = Random.Range(MIN_ENEMY_SPEED, MAX_ENEMY_SPEED);
var enemy = _enemyFactory.Create(newSpeed)