【问题标题】:How to create a base class with static factory method in C#?如何在 C# 中使用静态工厂方法创建基类?
【发布时间】:2011-12-12 19:08:06
【问题描述】:

我需要使用两个自定义文件阅读器类之一;一种用于读取固定宽度的文件,另一种用于读取 CSV 文件。这些阅读器中的每一个都会具有某些属性等。我想使用工厂方法并拥有私有构造函数,这样我就可以在创建对象之前运行一些业务逻辑。

编辑:更好的例子

//simple class with it's own factory method
class Class1
{
    private Class1()
    {
        //constructor code
    }
    public static Class1 CreateClass()
    {
        //do some business logic here
        return new Class1();
    }
}

我想要做的是定义一个基类,然后覆盖工厂。我想问题是静态类属于基类,所以永远不能被覆盖,即使它们是继承的。此代码有效

public class BaseClass
{
    //some common properties / fields here
    public string SomeField;

    //some common methods here

    //empty constructor
    protected BaseClass() { }

    //cannot have a virtual static class!  
    //Would really like to make this a virtual method
    public static BaseClass CreateClass() 
    {
        throw new NotImplementedException("BaseClass is meant to be derived");
    }

    public static string DoCommonStaticThing(){
        return "I don't know why you'd ever do this"; 
    }
}

public class DerivedClass1 : BaseClass
{
    //private constructor
    private DerivedClass1() {}

    //concrete factory method
    //would really like to say "override" here
    public static BaseClass CreateClass()
    {
        DerivedClass1 d1 = new DerivedClass1();
        d1.SomeField = "I'm a derived class\r\n" + DoCommonStaticThing();
        return d1;
    }
}

编辑:为了进一步澄清,我想做的是在我的基类中添加一些通用功能,但为我的文件格式特定方法定义一个接口。其中一些方法很常见,但构造函数的业务逻辑是特定于文件格式的。我上面的代码有效,但在我看来,最好将基类工厂方法标记为虚拟,将派生类工厂方法标记为“覆盖”。

我尝试这样做,但得到“静态成员不能标记为覆盖、虚拟或抽象”。

实现我的目标的正确方法是什么?

【问题讨论】:

  • 代码,代码,给我们看一些代码!
  • 显示一些代码,但感觉您正试图在派生类中覆盖您的工厂方法?那会破坏工厂模式的目的......
  • 嗯,是的,这正是我想要做的。不过,稍微想一想,我想你说得有道理(Eric J)——无论如何,我必须在我的代码中更改那个位置才能调用继承类的工厂方法,所以我可以一次性调用工厂方法...

标签: c# static factory


【解决方案1】:

首先,解释您的具体错误消息:您不能继承静态成员,因为它们属于正在定义的类型,而不是类型的实例。 override、virtual 和 abstract 等继承修饰符不适用于静态成员。

第二个:

通常,当您遵循工厂模式时,您有一个工厂类,其工作是实例化具体类并将这些实例转换为基类或接口。关于工厂如何选择实例化哪个具体类的细节各不相同,我不会深入讨论,但从根本上讲,这就是工厂所做的。

因此,为了使用您提供的示例创建工厂模式,您至少需要四种类型,按照您的示例,可能命名为 ReaderBaseReaderFactoryCsvReader 和 @ 987654324@。而不是ReaderBase,您可以考虑IReader——选择取决于您的抽象类是否预先实现了所有Readers共享的任何功能。

CsvReaderFixedWidthReader 继承自IReaderReaderBase,并且ReaderFactory 至少有一个称为InstantiateReader 的方法,它返回IReaderReaderBaseInstantiateReader 根据一些外部标准确定是实例化CsvReader 还是FixedWidthReader

【讨论】:

  • 嗯......你所描述的听起来正是我想要做的......等等,你是说在基类中根本没有工厂方法,只有它在派生类中?
  • 工厂在自己的类上,与它实例化的类无关。
  • 嗯,是的,这是一个想法,我可以有一个单独的工厂类。我一直在考虑更多的“Object.CreateObject()”类型工厂方法(该方法属于它实例化的类)。
  • @Aerik:让基类知道它的子类是灾难的根源。仅循环引用就足以使大多数语言在编译时崩溃。使用单独的类。
  • @Randolpho - 不,不,我不希望基类知道它的孩子。我最初在考虑定义虚拟工厂方法(如接口)的基类。编辑:啊,现在,重新阅读您的答案,它确实听起来像 InstantiateReader 必须了解儿童 - 但您的建议是 ReaderFactory 是一个单独的类。现在我想我更清楚地看到了你的建议,以及混乱的根源。我想我不应该尝试在 StackOverFlow 上发帖并同时关注我参加的会议......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多