C# 在运行时更改方法行为的最简单方法是什么?
我有一个名为“敌人”的类,我想有多种类型的敌人。每个C# 在运行时更改方法行为的最简单方法是什么?,c#,C#,我有一个名为“敌人”的类,我想有多种类型的敌人。每个敌人都会有不同的移动行为,例如,一个人可能会直接朝玩家移动,一个人可能会保持一定的距离,等等。我想知道的是,在一个类中,有多个不同行为的最简单方法是什么 我目前的想法是使用开关,并将所有行为包含在一个方法中 public class Enemy { public int health; public int damage; // etc etc public void Move(string type)
敌人
都会有不同的移动行为,例如,一个人可能会直接朝玩家移动,一个人可能会保持一定的距离,等等。我想知道的是,在一个类中,有多个不同行为的最简单方法是什么
我目前的想法是使用开关
,并将所有行为包含在一个方法中
public class Enemy
{
public int health;
public int damage;
// etc etc
public void Move(string type)
{
switch(type)
{
case "charge":
chargeMove();
break;
case "maintain":
maintainMove();
break;
}
}
private void chargeMove()
{
//stuff
}
private void maintainMove()
{
//stuff
}
//all the behaviors
}
我想知道的是,最好将所有内容都保留在这样一个函数中,还是为继承自敌方
的每种敌方类型创建一个新类?我更愿意将其保留为一个类,这样所有的敌人都可以很好地存储到IList
,而无需我进行任何强制转换来使用任何特定的函数
如有任何建议,将不胜感激
编辑:感谢所有的回复,我想我将使用Alastair提出的接口方法。使用代理:
public delegate void DoSth();
在运行时,将此委托与不同的实例相关联
请参见此处。听起来这将很有用
我认为你的建议是为每种敌人类型设置一个新类是一个好的建议。您仍然可以在一个列表中存储不同敌人类型的所有不同对象,因为它们都从该类继承
你也可以考虑将<代码>敌人类抽象,但这不是必要的。
如果您确实需要知道列表中特定对象的特定类型,您可以使用或我将创建多个从同一接口派生的类。您仍然可以拥有接口类型的列表。这是一个很好的例子。如下所示:
interface iEnemy
{
public void Move();
}
class Troll : iEmeny
{
public void Move()
{
Console.WriteLine("troll moves!");
}
}
class Ogre : iEmeny
{
public void Move()
{
Console.WriteLine("ogre moves!");
}
}
然后在代码中可以执行以下操作:
List<iEnemy> enemies = new List<iEnemy>();
enemies.Add(new Troll());
enemies.Add(new Ogre());
foreach(iEnemy e in enemies)
{
e.Move();
}
//Output would be:
//troll move!
//ogre move!
List敌人=新列表();
添加(新巨魔());
添加(新食人魔());
foreach(敌人中的iEnemy e)
{
e、 Move();
}
//产出将是:
//巨魔行动!
//食人魔行动!
这还将允许您遵循以下规则,即实体应为扩展而打开,但为修改而关闭。我将使用派生类。这正是它们的目的——在调用相同的方法时提供不同的行为
如果不想强制转换,则在基类上定义所有方法。如果派生类不重写某个特定的方法,它将获得基类中定义的任何行为,但如果您从未调用它,这并不重要。如果你想,如果你不想使用typeof之类的,你仍然可以有一个整数“type”字段
public enum EnemyType
{
Zombie,
Vampire
}
public class Enemy
{
private EnemyType mType;
protected Enemy(EnemyType type) { mType = type; }
public EnemyType getEnemyType() { return mType; }
public void walk() { }
public void attack() { }
public void eatBrains() { }
}
public class Vampire : Enemy
{
public Vampire : base(EnemyType.Vampire) { }
public void walk()
{
// walk like a vampire
}
public void attack()
{
// attack like a vampire
}
// don't bother implementing eatBrains() because vampires don't do this
// calling code will use getEnemyType() and won't bother call our eatBrains() method anyway
}
虽然这可能更适合于站点,但您可能需要考虑使用某种构图。
定义描述移动描述的接口。例如
public interface IMovementBehavior
{
void Move(Enemy enemy);
}
然后你会有很多不同的行为来描述不同的动作。
例如
所以你的敌方建筑商可能会有这样的情况:
public Enemy(IMovementBehavior movementBehavior) { ... }
这意味着你可以很容易地插入和输出不同的移动行为,而不必用所有不同的移动行为填充你的敌人职业
这被称为最好的方法是为每个敌人创建类,这是OOP中的多态性概念,如果只有特定类型的敌人将EatBrains
。。他引用不想强制转换作为不使用类的理由。因为它只供内部使用,所以我指出,他可以获得类的好处,而不必付出“正确”的代价。此外,函数总是添加到基类中,而不是在所有子类中实现。toString()在大多数OO语言中都是一个很好的例子。toString
是一个不好的例子,因为它有一个所有对象都依赖的默认实现(并且是框架的基本部分)。这是我的观点。。敌人的衍生产品,即。。说Policer
不需要EatBrains
方法。不需要它,但它没有理由不能简单地抛出,例如,您经常看到的修改只读集合类的方法。它们很少实现单独的IReadOnlyCollection接口。或者在不可搜索的流上搜索的方法。谢谢,这似乎是一个简单、灵活的解决方案!
public Enemy(IMovementBehavior movementBehavior) { ... }