C#如何使工厂方法返回子类类型

时间:2014-07-11 19:22:27

标签: c#

[主要编辑,我的第一篇文章有​​点误导。我的抱歉]

给出如下课程:

public class DatabaseResult{
    public bool Successful;
    public string ErrorMessage;     

    //Database operation failed
    public static DatabaseResult Failed(string message) {
         return new DatabaseResult{
             Successful = true,
             ErrorMessage = message
         };
    }
}

如何实现子类,以便我可以添加其他属性来表示与特定操作相关的数据(例如在SELECT类型查询的情况下为MatchedResult),而无需实现该静态失败函数?如果我尝试使用普通继承,则返回类型将是父类。例如:

DoThingDatabaseResult : DatabaseResult {
     public IEnumerable<object> SomeResultSet;
     public static Successful(IEnumerable<object> theResults){
          return new DoThingDatabaseResult {
               Successful = true,
               ErrorMessage = "",
               SomeResultSet = theResults
          };
     }
     //public static DatabaseResult Failed exists, but it's the parent type!
}

目标是避免需要为每个子类实现复制Failed静态函数。

4 个答案:

答案 0 :(得分:4)

递归通用:

public class BankAccount<T> where T : BankAccount<T>, new()
{
    public T SomeFactoryMethod() { return new T(); }
}

public class SavingsAccount: BankAccount<SavingsAccount>{}

您注意到我使工厂方法非静态,因为静态方法不会被继承。

答案 1 :(得分:2)

您无法完全按照定义问题的方式执行此操作。解决这个问题的最佳方法是将您的工厂完全赶出课堂:

public class BankAccount
{
}

public class SavingsAccount : BankAccount
{
}

public static class BankAccountFactory
{
    public static T Create<T>() where T : BankAccount, new()
    {
        return new T();
    }
}

现在Factory不依赖于实际类型。您可以传递BankAccount的任何派生类并在不做任何额外工作的情况下将其取回,或者担心继承您的工厂方法。

答案 2 :(得分:1)

如果可以,我想扩展StriplingWarrior。实际上,您可以为工厂使用静态。以下代码显示a和c是预期的对象类型。限制是您不能在基类本身上使用工厂。

 private void Testit()
    {
        var a = SavingsAccount.Factory();
        var c = CheckingAccount.Factory();
        //var b = BankAccount.Factory(); //can't do this
    }


public class BankAccount<T> where T : BankAccount<T>, new()
{
    public static T Factory()
    {
        return new T();
    }
}

public class SavingsAccount : BankAccount<SavingsAccount>
{
}

public class CheckingAccount : BankAccount<CheckingAccount>
{
}

答案 3 :(得分:0)

为了使用继承,您需要一个对象的实例和该对象的成员。在这种情况下,对于对象我们不能使用BankAccount/SavingsAccount,因为那时我们已经拥有了我们想要得到的东西。这意味着我们需要一个实际的工厂对象,这是大多数人在谈论工厂时所谈论的内容。因此,如果我们将其拉入工厂并使用继承......

public class BankAccountFactory { public virtual GetAccount() { return new BankAccount(); } }
public class SavingsAccountFactory : BankAccountFactory { public override GetAccount() { return new SavingsAccount(); } }

但是现在我们如何获得正确类型的实例?我们刚刚将问题推到了一层。

相反,您可能想要做的是使用某种配置来确定类型,或者将您想要的类型传递给方法。

public BankAccount GetAccount(AccountType type) { /* */ }

public BankAccount GetAccount() { /* Access config */ }

对于你的问题的简单回答:你不需要使用泛型或类似的东西,你只需要你的方法不是静态的......