【问题标题】:Get Instance of the same type using polymorphism使用多态获取相同类型的实例
【发布时间】:2020-04-10 23:30:00
【问题描述】:

我有下一个场景: 有一个类负责管理应用程序的所有货币。所有货币都扩展了 Currency,因此它可以表现得像它。货币是抽象的,因此无法实例化。 在应用程序的某些部分中,我将软货币、硬货币或事件货币作为成本货币,例如,玩家按下某个菜单上的某个购买按钮。这个动作触发了一次购买,购买有货币作为参考,在这个例子中它可以是costSoftCurrency。 这个想法是,如果 PlayerCurrencies 收到货币,玩家货币会评估他的货币并返回相同类型的关联货币,然后您可以安全地减去成本。

我的问题是......如果没有这个可怕的 if,我怎么能得到相同的逻辑?我读到了double dispatch,但我不知道它是否可以在这里应用。

有谁知道这是否可以实现?

public class PlayerCurrencies
{
    public SoftCurrency softCurrency = new SoftCurrency();
    public HardCurrency hardCurrency = new HardCurrency();
    public EventCurrency eventCurrency = new EventCurrency();

    public Currency GetCurrencyFromType(Currency currency)
    {
        if (currency is SoftCurrency)
        {
            return this.softCurrency;
        }

        if (currency is HardCurrency)
        {
            return this.hardCurrency;
        }

        if (currency is EventCurrency)
        {
            return this.eventCurrency;
        }

        return null;
    }
}

public abstract class Currency
{
    public float Value
    {
        get;
        set;
    }

    public void Add(Currency currency)
    {
        this.Value += currency.Value;
    }

    public void Substract(Currency currency)
    {
        this.Value -= currency.Value;
    }
}

public class EventCurrency : Currency
{

}

public class HardCurrency : Currency
{

}

public class SoftCurrency : Currency
{

}

internal class Program
{
    private static void Main(string[] args)
    {
        PlayerCurrencies playerCurrencies = new PlayerCurrencies();

        Currency costSoftCurrency = new SoftCurrency();
        Currency costHardCurrency = new HardCurrency();

        playerCurrencies.GetCurrencyFromType(costSoftCurrency).Substract(costSoftCurrency); // there i get a SoftCurrency from Player Currencies 
        playerCurrencies.GetCurrencyFromType(costHardCurrency).Substract(costHardCurrency); // there i get a HardCurrency from Player Currencies 
    }
}

【问题讨论】:

  • 听起来访问者设计模式可以提供帮助
  • 您可以维护每种不同货币的集合。然后按类型检索货币,您可以使用.OfType()
  • Tbh 不同货币的整个不同类,然后搞乱类型似乎过于工程。功能方面,货币之间没有区别,所以对我来说,感觉应该只有一类。创建一个enum 以区分您的不同货币类型并将其传递给它的构造函数(使其成为只读字段)并在PlayerCurrencies 类中保留一个Dictionary<CurrencyType, Currency> 以直接访问不同的货币:return playerCurrencies[currency.Type];
  • 有什么不对劲。您将 Currency 作为参数传递,但您并不关心它的值。你只关心它的类型。如果您将其更改为GetCurrencyFromType(Type currencyType) 并将currency.GetType() 传递给它而不是currency,这将在功能上相同。这看起来应该是通用的,但我们不知道它是如何被调用的。最好从调用它的代码的角度来设计这样的东西。如果我们知道它需要做什么,我们可以帮助描述一些可以做的事情(也许)。
  • @ScottHannen 如果我按照您的建议将 Currency 的类型更改为 Type,然后永远不会触发 if(type is SoftCurrency)GetCurrencyFromType(Type type) 总是返回 null。将其重构为 Type var 的正确方法是检查 if(type == typeof(SoftCurrency) 以保留相同的功能。

标签: c# architecture polymorphism


【解决方案1】:

我会为此使用工厂方法设计模式,因为它专门用于您使用子类来确定应该创建哪些类的时候。这基本上就是你在这里所做的。我最初的回答提到了反射,因为我在链接到的网站上看到了映射配置,并认为这很酷,但在昨晚考虑之后,它也有很多开销。使用字典绕过 if 块或 switch 语句会更简单,也更快。

这是我要添加/更改您的代码的内容:

//The Factory class that creates the different types of currency based
//on a name parameter
static class CurrencyFactory
{
    private static readonly Dictionary<string, Currency> _currencyDictionary =
        new Dictionary<string, Currency>
    {
        { "HardCurrency", new HardCurrency() },
        { "SoftCurrency", new SoftCurrency() },
        { "EventCurrency", new EventCurrency() }
    };

    public static Currency Create(string currencyTypeName)
    {
        return _currencyDictionary[currencyTypeName];
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        //This class will no longer be needed as it is redundant
        PlayerCurrencies playerCurrencies = new PlayerCurrencies();

        var costSoftCurrency = CurrencyFactory.Create("softCurrency");
        var costHardCurrency = CurrencyFactory.Create("hardCurrency");

        //I wasn't sure of your goals here so I kept it as is,
        //but as I said above, playerCurrencies won't be needed.
        playerCurrencies.GetCurrencyFromType(costSoftCurrency)
            .Substract(costSoftCurrency); // there i get a SoftCurrency from Player Currencies 

        playerCurrencies.GetCurrencyFromType(costHardCurrency)
            .Substract(costHardCurrency); // there i get a HardCurrency from Player Currencies 
    }
}

您可以在此处找到更详尽的示例和对该模式的详细说明:https://dev.to/gary_woodfine/how-to-use-factory-method-design-pattern-in-c-3ia3

【讨论】:

  • 在不添加您自己的示例来演示他们需要做什么的情况下让人们查看其他示例不是一个好习惯。 URL 会随着时间的推移而改变和打破。
  • 啊,谢谢,我刚开始回答。今天晚些时候有空我会写一个例子。
  • 您花时间这样做真是太好了! SO 社区试图通过审查和提供反馈来改进第一个答案。
【解决方案2】:

您可以使用pattern matching

public class PlayerCurrencies
{
    public SoftCurrency Soft = new SoftCurrency();
    public HardCurrency Hard = new SoftCurrency();
    public EventCurrency Event = new EventCurrency();

    public Currency GetCurrencyFromType(Currency currency)
    {
        switch (currency)
        {
            case EventCurrency: return Event;
            case HardCurrency: return Hard;
            case SoftCurrency: return Soft;
        }
        return null;
    }
}

我将字段名称更改为HardSoftEvent,以便更容易地将它们与具有相同名称的类型区分开来。

在这个特定示例中,传入currency 参数并仅将其用于其类型似乎很奇怪。可能有另一种方法可以解决您的特定问题。但至于如何在没有多个if 语句的情况下做到这一点,这就是你可以做到的。

您会经常看到这通过声明的变量来演示,如下所示:

switch (currency)
{
    case EventCurrency ec : return Event;
    case HardCurrency hc: return Hard;
    case SoftCurrency sc: return Soft;
}
return null;

例如,如果currency 的类型是EventCurrency,那么在case 的范围内,ec 将是currency 参数转换为EventCurrency。但由于在本例中您没有使用该值,因此不需要变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    相关资源
    最近更新 更多