每次我想制作类似“静态覆盖”的东西(在C#中都不可能),我发现问题表明这是由糟糕的设计引起的。您将如何设计代码以避免这种情况?
示例:一些具有大量单位的游戏,每个游戏都有不同的成本(int或类似的东西),但每个子类具有相同的成本。这里(IMHO)使用“抽象静态”是有意义的,但这是不可能的。对这种情况进行建模的最佳方法是哪种?
我通常最终创建一个抽象方法,它返回一个我必须在每个子类中创建(并记住!)的静态变量,但是我总是依赖于每个类的实例,还有其他任何想法吗?
答案 0 :(得分:3)
根本不需要在这里使用静力学。只需为所有具体单元定义一个基类,它将成本作为初始化参数:
public abstract class UnitBase
{
public int Cost { get; private set; }
public UnitBase(int cost)
{
this.Cost = cost;
}
}
以此作为继承树的基础,然后您将沿着这些方向前进:
public abstract class Unit1Base : UnitBase
{
public Unit1() : base(<actual_cost>) { }
}
public class ConcreteUnit1 : Unit1Base {}
public class ConcreteUnit2 : Unit1Base {}
这样,每个具体单位都将具有所需的成本价值......
答案 1 :(得分:2)
但每个子类具有相同的成本。
对于包含其他人将继承的Cost
属性的基类来说,这似乎是一个很好的候选者:
public virtual decimal Cost
{
get { return 20m; }
}
然后,如果您在链上的任何地方有其他价格,您可以覆盖Cost属性。
答案 2 :(得分:1)
你是正确的,因为你不能拥有static virtual
/ override
财产。对于你描述的情况,这可能很烦人,我过去也一直在努力。
但是,您可以使用static
属性...和new
关键字来隐藏基本实现。
例如,我们在这里定义一些单位:
public abstract class BaseUnit
{
public static int UnitCost { get { return 10; } }
}
public class CheapUnit : BaseUnit
{
new public static int UnitCost { get { return 5; } }
}
public class ExpensiveUnit : BaseUnit
{
new public static int UnitCost { get { return 20; } }
}
public class MultipleUnit : BaseUnit
{
new public static int UnitCost { get { return BaseUnit.UnitCost * 4; } }
}
然后一个小测试程序输出它们的值:
public void Run()
{
Console.WriteLine("Base unit cost:\t\t{0}", BaseUnit.UnitCost);
Console.WriteLine("Cheap unit cost:\t{0}", CheapUnit.UnitCost);
Console.WriteLine("Expensive unit cost:\t{0}", ExpensiveUnit.UnitCost);
Console.WriteLine("Multiple unit cost:\t{0}", MultipleUnit.UnitCost);
}
我们得到......
Base unit cost: 10
Cheap unit cost: 5
Expensive unit cost: 20
Multiple unit cost: 40
啊哈哈!正是我们想要的。我不是百分之百满意这个解决方案但是我不知道更好的方法而不必创建一个我认为访问多态类常量很愚蠢的实例。所以我就是这样做的。
编辑:在我发现自己这样做的情况下,我经常选择将这种“查找”逻辑转移到经理(单身)课程中。例如,UnitManager
或类似名称,我可以在其中传入类型名称("CheapUnit"
),它会在Dictionary
中查找费用。
只是一个快速的模型想法:
sealed class UnitManager
{
static readonly UnitManager instance = new UnitManager();
public static UnitManager Instance { get { return instance; } }
Dictionary<string, int> unitCostDictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); // Ignore Case of Keys
public int LookupUnitCost(string unitType)
{
int unitCost = 0;
unitCostDictionary.TryGetValue(unitType, out unitCost);
return unitCost;
}
}
当单位成本可能发生变化时,这也允许动态单位成本和集中通知。
答案 3 :(得分:0)
创建一个Factory类(静态),它返回您想要的实例,但是工厂方法的声明是否返回抽象类型?
答案 4 :(得分:0)
虽然我有时会错过在.net中覆盖静态方法的能力,但这不适用于这种情况。 除了简单地使用你似乎因为某些原因而无法理解的继承之外,我无法理解,另一种方法可能是,将成本委托给一个以单元类型作为参数的静态类。 另一种方法是将费用作为班级的一个属性,并通过反思来查找。