【问题标题】:C# Make properties visible if a condition is satisfied如果满足条件,C#使属性可见
【发布时间】:2015-06-15 13:44:49
【问题描述】:

我终于开始学习 OOP 原理,目前正在制作一个简单的游戏。 情况如下: 我有一个名为 Items 的抽象类,它将项目的所有可能属性作为属性和项目的质量作为枚举:

public enum ItemQuality
{
    Common,
    Uncommon,
    Rare,
    Epic,
    Legendary
}

public abstract class Items
{
    public ItemQuality ItemQuality { get; set; }
    public int Stamina { get; set; }
    public int Strength { get; set; }
    public int Agility { get; set; }
    public int Intelligence { get; set; }
    public int Damage { get; set; }
    public int Block { get; set; }
    public int Armor { get; set; }
}

我还有两个名为 Weapon 和 Armor 的类(它们继承了 Items 类),它们分别拥有 WeaponType 和 ArmorType,它们也是枚举。

考虑以下场景:我制作了一把剑类型的新武器,我可以给它一个格挡值,但它不能格挡。我想根据武器/盔甲类型显示不同的属性。

Weapon weapon = new Weapon();
weapon.WeaponType = WeaponType.Sword;
weapon.Block = 5;

在这种情况下,我应该看不到 Block 属性。

为了更进一步,我不想将武器和盔甲与角色分开实例化(我也有一个角色类)。

我的最终目标是做这样的事情:

Character character = new Character();
character.WeaponType = WeaponType.Sword;
character.WeaponType.Damage = 10;

或者类似的东西,我什至不确定我的结构是否正确,所以我愿意接受建议! 谢谢!

【问题讨论】:

  • 考虑使用接口代替继承。
  • 也许装饰器模式适合你。所以你可以用一个包含额外需要的属性的装饰器来包装基类
  • 谢谢大家!看来我还有很多东西要学:)
  • 你在这里所做的违反了 Listov 替换原则 (en.wikipedia.org/wiki/Liskov_substitution_principle)。定义一个包含所有内容的基类,然后有选择地尝试隐藏内容与“最佳实践”完全相反。相反,请遵循@JanneMatikainen 的建议并了解接口和组合,而不是继承。
  • 在您给定的场景中,最好在子类中包含 Damage、Block 等属性。这样只有武器有伤害等。

标签: c# oop


【解决方案1】:

在这里忘记继承并使用组合。例如,从基础开始:

公共枚举 ItemQuality { 常见的, 罕见, 稀有的, 史诗, 传奇的 }

public class Item
{
    public ItemQuality ItemQuality { get; set; }

    // other things common to all items here

    public List<IFeature> features { get; set; }
}

那么IFeature 是什么。首先,它是一个空界面:

public interface IFeature { }

现在让我们开始添加武器:

public interface IAttackWeapon : IFeature
{
    int Damage { get; set; }
}

public interface IDefenceWeapon : IFeature
{
    int Block { get; set; }
}

然后我们可以开始定义一些类:

public class Weapon : IAttackWeapon
{
    public Damage { get; set }
}

public class Shield : IDefenceWeapon
{
    public int Block { get; set; }
}

那么,我可能会定义一些武器:

public static readonly Item ShortSword = new Item
{
    ItemQuality = ItemQuality.Common,
    Cost = 5,
    Features = new List<IFeature>
    {
        new Weapon { Damage = 4 }
    }
}

通过这种组合方式,如果我们以后说想要一把魔法剑,我们不需要创建更多的类,需要隐藏更多的属性等等。我们也不会遇到“我的魔法剑应该从武器或魔法物品继承?”。相反,我们会添加一个新功能,例如:

public static readonly Item MagicSword = new Item
{
    ItemQuality = ItemQuality.Rare,
    Cost = 5000,
    Features = new List<IFeature>
    {
        new Weapon { Damage = 10 },
        new MagicItem { Spell = Spells.TurnToFrog }
    }
}

【讨论】:

  • 谢谢,看起来不错。我现在将更深入地研究接口。 :)
【解决方案2】:

我不会选择这种方式,尤其是如果您想保持良好的 OOP。

您为什么不使用接口,例如 IAttackable 和 IBlockable。盾牌只能实现 IBlockable 接口,剑 IAttackable 和 IBlockable 以及枪只实现 IAttackable

你会问武器对象是否可阻挡

   if (currentWeapon is IBlockable)
   {
        var blockWeapon = currentWeapon as IBlockable;
        blockWeapon.blockHorizontal();
        blockWeapon.blockVertical();
   }

【讨论】:

    【解决方案3】:

    根据 OOP 原则,将对象类型定义为枚举器是一种糟糕的设计。好的 OOP 会利用继承和可能的多态性。像这样:

    public abstract class Weapon {
        public int cost {get; set;}
    }
    public class Sword : Weapon {
        public int damage {get; set;}
    }
    public class Shield : Weapon {
        public int defense {get; set;}
    }
    

    现在你可以说:

    Sword blade = new Sword();
    blade.cost = 5;
    blade.damage = 6;
    
    Shield myShield = new Shield();
    myShield.cost = 4;
    myShield.defense = 7;
    

    如果您需要一种新型武器,您可以像我们对剑与盾所做的那样子类化武器类(假设您想要弓)。 如果您需要其他攻击性武器(例如刀),则可以将剑子类化。

    public class Knife {
        public int length {get; set;}
    }
    

    【讨论】:

    • 所以我应该为每种类型的物品(盔甲、武器)创建一个新类?如果我这样做,那么我需要实例化每个类,对吗?
    • 是的,好的 OOP 建议为每个 TYPE 设置单独的类。然后,您可以拥有该类的任意数量的实例,例如一系列剑。
    • 但我不希望这样。如果我这样做,我将不得不为每个类实例化 15 个对象,例如 Armor chest = new Armor();然后另一个用于 headguard 另一个用于 legguard 等等,相反,我希望所有项目都可以从 Character 类的角色实例中访问。与我主帖的最后几行类似。
    • 同样,好的 OOP 设计伴随着更多的代码,但它具有高度的可维护性。在您的情况下,您可以在 Character 类中拥有 Weapon 属性,而不是说 myChar.weapon = new Sword(); (剑)myChar.weapon.damage = 5;或 myChar.weapon = new Shield(); (盾)myChar.weapon.degense = 3;
    • David 是正确的,但每次需要一件新盔甲时实例化一个对象的论点才是正确的做法。每次有不同的项目时,都应该有一个单独的对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 2020-07-22
    • 2018-08-24
    • 2019-07-19
    • 2020-09-01
    相关资源
    最近更新 更多