4

我经常使用类工厂模式,其中一个类有一个私有构造函数和一个静态方法来创建类。这允许由于某种原因无法构造类并返回 null 的情况 - 非常方便。

我希望能够将其扩展到工厂方法,该方法根据条件从派生类的层次结构中创建特定类。但是我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。如果工厂方法在基类中,则它不再有权访问派生类的私有构造函数。在每个派生类中放置工厂方法是行不通的,因为必须事先知道所需的类型。如果一个类可以访问嵌套类的私有成员,则嵌套类可能是一种方式,但遗憾的是,嵌套类似乎可以访问封闭类的私有成员,但反之则不行。

有谁知道这样做的方法?

4

4 回答 4

4

有几种可能性,其中两种是:

  1. 将所有这些类放在一个项目中并制作构造函数internal。其他项目将无法调用这些构造函数,但该项目中的代码可以。
  2. 创建这些类的构造函数protected(而不是private),并在包含工厂方法的类中创建一个私有派生类。创建该私有类的实例并返回它。

第二个选项的示例:

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() { }
}
于 2013-02-20T10:23:16.920 回答
1

这是丹尼尔发布答案时我正在处理的示例代码。看起来它正在按照他的建议做:

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);
    }
}

[编辑] 对于丹尼尔的第二个建议:

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);
    }
}

请注意,不幸的是,第二种方法意味着无法密封类。

于 2013-02-20T10:24:24.077 回答
0

不是将类本身内部的方法用作工厂,而是通过静态类(“工厂”)实现工厂模式,该类根据您编写的逻辑返回正确的实例。

于 2013-02-20T10:21:26.617 回答
0

您可以在基类构造器中拦截派生类型的创建,并使用 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
        }
    }
于 2013-02-20T10:26:02.143 回答