C#A Noob" Trapped"在多态性

时间:2017-12-02 14:17:08

标签: c# inheritance polymorphism

好吧,所以我有以下问题。 我有以下继承的类层次结构

Character ->     Melee    -> Warrior
                          -> Assassin
                          -> Knight
          -> Spellcasters -> Mage
                          -> Druid
                          -> Necromancer

感谢继承和多态性,我能够从基类中提取几乎所有冗余代码(warrior,assassin ....)。角色,近战和施法者都是抽象的。

所以我继续编写我的逻辑,想法是让两队近战和施法者相互战斗,直到其中一支球队获胜。 最后一个条件让事情非常糟糕,很快。

所以我创建了一个List,它包含了所有6个派生类型的字符,然后我将它们相应地分配到另外两个列表List和List with loops(我的理由是,如果我想在战斗中添加更多字符我只需要将它们添加到初始列表中,其余的将自动处理)

我遇到的问题显然是(我应该预料到的)我失去了对派生类(近战,施法者,战士等)中所有属性/方法的访问权限。

我尝试做的是在Melee和Spellcaster课程中添加一个属性DeadTeam,我会用它来跟踪其中一个队伍是否输掉了战斗,当然我无法访问这个属性......

那么我应该如何重构我的逻辑,仍然具有Polymorphism给我的灵活性,而不是编写大量代码并且能够在没有转换的情况下访问我最派生的类?

class EntryPoint
{
    static void Main()
    {
        Random rng = new Random();
        int turnCounter = 0;
        bool gameOver = false;

        List<Character> characters = new List<Character>()
        {
            new Warrior(),
            new Knight(),
            new Assassin(),
            new Mage(),
            new Necromancer(),
            new Druid()
        };

        List<Character> meleeTeam = new List<Character>();
        List<Character> spellTeam = new List<Character>();

        foreach (var character in characters)
        {
            if (character is Melee)
            {
                meleeTeam.Add(character);
            }
            else if (character is Spellcaster)
            {
                spellTeam.Add(character);
            }
        }



        while (!gameOver)
        {
            //meleeTeam[turnCounter].Attack(spellTeam[rng.Next(0, spellTeam.Count)]);
            //spellTeam[turnCounter].Attack(meleeTeam[rng.Next(0, meleeTeam.Count)]);

            turnCounter++;

            if (turnCounter == 3)
            {
                turnCounter = 0;
            }

            gameOver = CheckForWinner(meleeTeam, spellTeam);
        }

    }

    private static bool CheckForWinner(List<Character> meleeTeam, List<Character> spellTeam)
    {

        bool allMeleeDead = true;
        bool allSpellDead = true;

        foreach (var character in meleeTeam)
        {
            if (character.IsAlive == true)
            {
                allMeleeDead = false;
            }
        }

        foreach (var character in spellTeam)
        {
            if (character.IsAlive == true)
            {
                allSpellDead = false;
            }
        }

        if (allMeleeDead)
        {
            Console.WriteLine("Spellcaster team wins!");

            return true;
        }
        else if (allSpellDead)
        {
            Console.WriteLine("Melee team wins!");

            return true;
        }
        else
        {
            return false;
        }
    }
}

我创建的CheckForWinner方法显然会完成这项工作,但它是一个我不想保留的解决方法,它甚至不是一个解决方法,因为我将继续需要我的派生类中的其他东西,我仍然不会有访问它。我想到了这个问题,当我发现这个问题时,我没有关于这个方法的信息,关于团队是死还是活

另一个显而易见的问题是,我想让我的近战团队和拼写团队列表属于近战和施法者类型,但当然这也是不可能的。

P.S。我知道我可以将它们输入到派生类型中,但这会使我的代码翻两番,这就是我要避免的。

P.S。 2

我已经改变了我的meleeteam和spellteams并且我将字符列表中的项目添加到这两个列表中,这似乎可以解决问题,我完全重写了我粘贴在上面的其余代码。除此之外,这仍然不能让我访问我最派生的类,但我现在还不需要它,似乎没有办法在时间到来时为每种类型编写代码:)

2 个答案:

答案 0 :(得分:0)

您的列表类型为begin emp_pos('&employee_name'); end; ,类型Character对派生类的属性和方法一无所知。

您应该将列表中的对象强制转换为特定的派生类型:

Character

如果您想要var testMelee = meleeTeam[0] as Melee; if (testMelee != null) { // now testMelee is of type Melee and has property DeadTeam (or other properties declared in Character and Melee types) testMelee.DeadTeam = yourValue; // ok, there is such property } 的所有属性,那么您应该转换为此类型:

Warrior/Assasin/...

如果您使用C#7或更高版本,则代码可以更改为:

var testWarrior = meleeTeam[0] as Warrior; 

if (testWarrior != null)
{
    // now testWarrior is of type Warrior and has property DeadTeam (or other properties declared in Character, Melee and Warrior types)        
}

另外,在你的帖子中有:

  

我尝试做的是在近战和混战中添加属性DeadTeam   施法者课程

无需在两个类中声明相同的属性。您可以在if (meleeTeam[0] as Warrior testWarrior) { // now testWarrior is of type Warrior and has property DeadTeam (or other properties declared in Character, Melee and Warrior types) } 类中简单地声明此属性,并且所有派生类都可以访问它(如果它不是私有的)。

答案 1 :(得分:0)

  

我尝试做的是在Melee和Spellcaster课程中添加一个属性DeadTeam,我会用它来跟踪其中一个队伍是否输掉了战斗,当然我无法访问这个属性......

这些类不应该担心他们所属的整个团队是否死亡(这是与团队相关的代码的责任 - 团队类提示提示)。字符类应该有一个方法来确定该特定字符是否已死(f.ex:public bool isAlive())你应该做你的&#34;整个团队死了吗?&#34;循环中的逻辑循环遍历团队中的角色并说“是”,他们已经死了#34;如果其中没有活着的字符。

在代码中:

public abstract class Character
{
    ...
    public bool isAlive();
}

...
bool allDead = true;
foreach(Character char in spellteam)
{
    if(Character.isAlive())
    {
        allDead = false;
        break;
    }
}

if(allDead)
{
    //Do whatever you need to do when everyone is dead.
}

通常,您需要通过重构和重新创建强制您拥有当前结构的抽象来避免必须在代码中进行类型测试。

这方面的一个例子就是拥有施法者和近战职业 - 你永远不可能拥有一个同时施法者和近战的类,而不是因为你在游戏中说过,没有两个类都是,但是因为你以一种不可能的方式构建你的游戏。

也许只是在基类中为你想要做的事情(或者只是DoAction(actiontype),Attack()或甚至只是TakeYourTurn())进行操作,让类的实现担心什么最终行动是(因为它知道哪些行动可用)。

通过这种方式,你可以拥有你想要的任何类型的团队,而不受基于他们行为的限制 - 如果你愿意,你仍然可以使用施法者/近战团队,但不限制当前存在的未来可能的添加。