C# 抽象类静态字段继承

19

我感觉好像漏掉了一两个 C# 课程,但这是我的困境:

我有一个抽象类,从中派生出多个子类。

我确定每个子类都需要一个构造函数,该函数需要一个特定的静态对象作为模型,而这个对象对于每个子类都不同。

我的第一个尝试是在抽象父类中创建一个公共静态对象,然后在创建任何子类实例之前,我将其修改为每个子类所需的对象。但事实证明,这种方法实际上只创建了一个静态对象,即用于抽象类的对象,并且每个子类都使用它。

我该如何解决这个问题?

更确切地说,这是伪代码:

抽象父类:

 abstract class AbstractClass
{
   static public ModelObject Model;
   ...
}

一个子类:

class Child : AbstractClass
{
    ...
    public Child()
    {
        this.someField = Model.someField;
    }
}

编辑:

模型需要是“ModelObject”类的成员,它不应该是单例或其他任何东西。

编辑2:

更确切地说,我选择了这种实现方式用于国际象棋游戏:我有一个抽象类表示棋子,在子类中表示游戏中具体的棋子:兵、马等等。

抽象类继承自MeshMatObject,这是一个代表具有基本功能的通用3D对象的类,如旋转、网格、材质、纹理等,并为棋盘上的棋子定义抽象方法,例如GetPossibleMoves()。

我之前提到的Model对象是MeshMatObject的成员,并且在我看来,应该在类外部定义一次,然后在所有棋子中使用。我的意思是:例如,所有兵都具有相同的网格和纹理,因此我不认为每次制作兵时都需要将模型作为参数。


2
抽象类需要以何种方式访问模型? - dtb
2
你应该考虑将一个Model实例传递到子类的构造函数中,而不是使用如此静态的字段。 - Trillian
我同意Trillian的观点。在这里使用静态模型确实违反了封装的精神。 - Kirk Woll
@dtb:抽象类实际上不需要访问模型。子类需要在它们的构造函数中访问它。@Trillian:是的,那将是一个解决方案,实际上这是我的第一个实现,但由于该类的所有对象都是基于完全相同的模型构建的,因此我认为最好只在类内部定义一次模型并使用静态字段来构建新实例。 - cantrem
为什么需要静态的?你是否在所有类之间共享状态? - Jordão
@Jordão:我将模型在所有相同类型的对象之间共享。 - cantrem
3个回答

22

您可以通过使抽象类成为泛型来避免共享静态字段。每个泛型类将获得自己的静态字段副本。

abstract class AbstractClass<T>
{
   static public ModelObject Model;
   ...
}

然后每个子类将使用静态字段的不同实例。

class Child : AbstractClass<Child>
{
    ...
    public Child()
    {
        this.someField = Model.someField;
    }
}

AbstractClass没有引用泛型参数并不重要。你只是用它来给每个子类一个独特的基类实例。


1
感谢您的输入,已经完成了一半。另一半来自Justin R. 如果我只使用了您的解决方案,我将无法仅使用AbstractClass对象进行操作。例如,我将难以布置一个由抽象棋子组成的2D数组。无论如何,现在很好知道,使用泛型类,每个子类都会收到静态字段的副本。 - cantrem

9

我倾向于使用类似于@shf301的解决方案。根据您的需求,设置基类可能会很有用:

abstract class AbstractClass
{
}

abstract class AbstractClass<TModel> : AbstractClass
    where TModel : ModelObject 
{
   static public TModel Model;
   ...
}

这使我可以在非泛型函数中使用一个通用的基类。这也允许派生类型选择精确的模型类型并减少强制转换。


1
它完美运行!只是 "..." 在 "AbstractClass" 上。一个不错且简单的实现,谢谢。还有一件事:这个实现是否存在性能损失或其他问题?我没有看到任何理由应该有,特别是使用 VS 的 "优化代码" 功能,但只是确认一下。 - cantrem
编辑:在我的情况下,类型约束应该是AbstractClass;然后子类就像shf301指出的那样进行声明。这是因为我需要实现仅适用于AbstractClass的子类。类似于:AbstractClass <T>:其中T:AbstractClass和子类:ChildClass:AbstractClass <ChildClass> - cantrem

3
如何使用工厂将类与继承模型解耦:
public static class ModelObjectFactory
{
    public static ModelObject GetModel<T>(T obj)
    {
        // return ModelObject according to type of parameter
    }
}

class Child
{
    public Child()
    {
        ModelObject mo = ModelObjectFactory(this);
        this.someField = mo.someField;
    }
}

工厂模式在其他情况下可能更适用。但在这种特定情况下,我认为我会使情况变得过于复杂;但还是感谢您的建议! - cantrem
拥有单一职责的对象永远不会使事情复杂化。请查看SOLID原则。如果这是可能的,请将评论标记为-1 :) - Ignacio Soler Garcia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接