为什么通过其继承的抽象类而不是自己的类来声明对象

时间:2012-04-25 18:23:03

标签: c# inheritance object polymorphism abstract-class

public abstract class Character
{
    protected Weapon weapon;

    public string Name;
    public int Health = 10;
    public int Strength;

    public Character()
    {
    }

    public void Attack()
    {
        weapon.useweapon();
    }
}

public class Warrior : Character
{
    public Warrior()
    {
        weapon = new Sword();
        Health = 10;
        Strength = 25;
    }

    public void SetWeapon(Weapon newweapon)
    {
        weapon = newweapon;
    }

}

public class Wizard : Character
{
    public Wizard()
    {
        weapon = new Spell();
        Health = 15;
        Strength = 10;
    }
}

如您所见,有一个抽象的Character类和两个Character子类。在这个程序中,只有战士才能改变武器。现在,我不打算讨论代码本身,我想知道的是,在我的实现代码中为什么我会使用它:

Character Zizo = new Warrior();
Character Hang = new Wizard();

而不是 -

Warrior Zizo = new Warrior();
Wizard Hang = new Wizard();
Zizo.SetWeapon(new Axe()); //I can only use this method in this implementation

两者之间有什么区别,通过抽象类声明对象可以获得什么好处?

6 个答案:

答案 0 :(得分:4)

客户端代码应使用最低要求的接口或抽象类定义。这样做主要是为了使代码更加松散耦合。在您的示例中,如果调用代码只需要Attack(),但不关心如何执行,实现或特定类型(例如WarriorWizard等)进行攻击然后它应该使用abstract Character类。

必然必须知道某个特定实现或具体类时,那么明确地使用它是合适的。

答案 1 :(得分:3)

您所获得的是编写代码的能力,该代码可以与任何字符类型的任何公开公开的Character类型成员进行交互,无论它是什么。

例如:

public void AttackAndHeal(Character character)
{
    character.Attack();
    character.Health++;
}

Warrior zizo = new Warrior();
Wizard hang = new Wizard();

AttackAndHeal(zizo);
AttackAndHeal(hang);

答案 2 :(得分:1)

如果您始终知道您将使用它们,那就没有必要了。但通常你想抽象出角色的类型,只执行所有角色实现的动作。

让我们假设有人在屏幕中间放下一枚H炸弹。你不会在乎你的角色是巫师还是勇士()他们都会死,所以你只需要打电话给Kill或者你有什么方法。

答案 3 :(得分:1)

您可以拥有WarriorWizard的通用集合,并重用Character类的任何成员

var characters = new List<Character>();
characters.Add(new Warrior());
characters.Add(new Wizard());
foreach (var c in characters)
{
    //use members exposed by c
}

答案 4 :(得分:0)

通过将Zizo声明为Character,您现在可以将任何类型的Character对象分配给Zizo。不幸的是,这也将限制您仅调用为Character显式声明的属性和函数。要在Zizo上调用特定于Warrior的任何内容,您需要先将其投射。

答案 5 :(得分:0)

如果你在基类和子类上有一个相同名称的常规方法(即没有被覆盖),那么键入对象的变量作为基类将导致基类的方法被选中,如果方法被调用。如果您正在寻找该行为,这可能是将其键入字符的原因。如果将warrior添加到List或将其传递给需要Character作为参数的方法,那么它会自动转换为Character(我认为),所以如果你刚刚去的话,输入一个warrior作为Character可能会使代码不那么容易出错将其添加到列表或执行任何其他需要字符类型的操作。