C# 如何创建类工厂来创建所需的派生类
我经常使用类工厂模式,其中类有一个私有构造函数和一个静态方法来创建类。这允许出现由于某种原因无法构造类,并且返回null的情况—非常方便 我希望能够将其扩展到工厂方法,该方法根据条件从派生类的层次结构创建特定的类。但是,我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。如果工厂方法位于基类中,则它不再有权访问派生类的私有构造函数。在每个派生类中放置工厂方法并不起作用,因为必须事先知道所需的类型。如果类可以访问嵌套类的私有成员,则嵌套类可能是一种方法,但遗憾的是,嵌套类似乎可以访问封闭类的私有成员,而不是相反C# 如何创建类工厂来创建所需的派生类,c#,inheritance,nested-class,class-factory,C#,Inheritance,Nested Class,Class Factory,我经常使用类工厂模式,其中类有一个私有构造函数和一个静态方法来创建类。这允许出现由于某种原因无法构造类,并且返回null的情况—非常方便 我希望能够将其扩展到工厂方法,该方法根据条件从派生类的层次结构创建特定的类。但是,我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。如果工厂方法位于基类中,则它不再有权访问派生类的私有构造函数。在每个派生类中放置工厂方法并不起作用,因为必须事先知道所需的类型。如果类可以访问嵌套类的私有成员,则嵌套类可能是一种方法,但遗憾的是,嵌套类似乎可以访问封闭类的私有
有人知道这样做的方法吗?不使用类本身内部的方法作为工厂,而是通过静态类(“工厂”)实现工厂模式,该静态类根据您编写的逻辑返回正确的实例。有几种可能性,其中两种是:
受保护
(而不是私有
),并在包含工厂方法的类中创建私有派生类。创建该私有类的实例并返回它public static class AnimalFactory
{
public static Animal Create(int parameter)
{
switch(parameter)
{
case 0:
return new DogProxy();
case 1:
return new CatProxy();
default:
throw new ArgumentOutOfRangeException("parameter");
}
}
private class DogProxy : Dog { }
private class CatProxy : Cat { }
}
public abstract class Animal { }
public class Dog : Animal
{
protected Dog() { }
}
public class Cat : Animal
{
protected Cat() { }
}
这是丹尼尔发布答案时我正在编写的示例代码。看起来它在做他建议的事情:
public static class BaseFactory
{
public static Base Create(bool condition)
{
if (condition)
{
return Derived1.Create(1, "TEST");
}
else
{
return Derived2.Create(1, DateTime.Now);
}
}
}
public class Base
{
protected Base(int value)
{
}
protected static Base Create(int value)
{
return new Base(value);
}
}
public sealed class Derived1: Base
{
private Derived1(int value, string text): base(value)
{
}
internal static Derived1 Create(int value, string text)
{
return new Derived1(value, text);
}
}
public sealed class Derived2: Base
{
private Derived2(int value, DateTime time): base(value)
{
}
internal static Derived2 Create(int value, DateTime time)
{
return new Derived2(value, time);
}
}
[编辑]对于Daniel的第二个建议:
public static class BaseFactory
{
public static Base Create(bool condition)
{
if (condition)
{
return new Derived1Creator(1, "TEST");
}
else
{
return new Derived2Creator(1, DateTime.Now);
}
}
private sealed class Derived1Creator: Derived1
{
public Derived1Creator(int value, string text): base(value, text)
{
}
}
private sealed class Derived2Creator: Derived2
{
public Derived2Creator(int value, DateTime time): base(value, time)
{
}
}
}
public class Base
{
protected Base(int value)
{
}
protected static Base Create(int value)
{
return new Base(value);
}
}
public class Derived1: Base
{
protected Derived1(int value, string text): base(value)
{
}
protected static Derived1 Create(int value, string text)
{
return new Derived1(value, text);
}
}
public class Derived2: Base
{
protected Derived2(int value, DateTime time): base(value)
{
}
protected static Derived2 Create(int value, DateTime time)
{
return new Derived2(value, time);
}
}
请注意,不幸的是,第二种方法意味着类无法密封。您可以在基类构造函数中拦截派生类型创建,并使用StackFrames检查调用方是否是您的工厂:
protected Class1() //base class ctor
{
StackFrame[] stackFrames = new StackTrace().GetFrames();
foreach (var frame in stackFrames)
{
//check caller and throw an exception if not satisfied
}
}
这并不能解决问题,即“阻止用户通过
new
”创建实例”。但我同意把建筑留给第三类。基类不应该知道从它派生的类。@DanielHilgarth你是对的,因为他应该将另一个项目中的类型作为内部类型分开,并通过接口公开它们。请重新阅读问题。我引述:“然而,我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。”Daniel和Mathew。真聪明。它工作并满足所有要求。我喜欢。我只是不知道谁的答案被接受:-)@Dave:你必须自己决定。通常你会接受对你帮助最大的答案。如果有多个答案对你有帮助,你要么不接受,要么不接受你更喜欢的答案,要么先发布的答案。丹尼尔和马修。真聪明。它工作并满足所有要求。我喜欢。我只是不知道谁的答案被接受:-)马修,第一个代码不是我第一个选项的意思。正如我所说的,将构造函数设置为内部。你们用额外的工厂方法绕道并没有增加任何好处。是的,这很公平。它只是用来演示工厂方法的使用——尽管工厂方法在本例中非常简单,它不会隐藏任何东西。在一般情况下,它可以。@Dave:丹尼尔是第一个发布代码的人,所以如果其他因素相同,你应该勾选他的。:)