5

我有一组继承自我创建的抽象类的类。我想将抽象类用作创建抽象类的具体实现实例的工厂。

有没有办法从除父类之外的所有代码中隐藏构造函数。

我想基本上这样做

public abstract class AbstractClass
{
    public static AbstractClass MakeAbstractClass(string args)
    {
        if (args == "a")
            return new ConcreteClassA();
        if (args == "b")
            return new ConcreteClassB();
    }
}

public class ConcreteClassA : AbstractClass
{
}

public class ConcreteClassB : AbstractClass
{
}

但我想阻止任何人直接实例化 2 个具体类。我想确保只有 MakeAbstractClass() 方法可以实例化基类。有没有办法做到这一点?

更新
我不需要从 Abstract 类之外访问 ConcreteClassA 或 B 的任何特定方法。我只需要我的 Abstract 类提供的公共方法。我真的不需要阻止具体类被实例化,我只是想避免它,因为它们没有提供新的公共接口,只是抽象类内部一些非常具体的东西的不同实现。

对我来说,最简单的解决方案是像 samjudson 提到的那样创建子类。但是我想避免这种情况,因为它会使我的抽象类文件比我希望的要大得多。我宁愿将课程分成几个文件以进行组织。

我想这没有简单的解决方案......

4

9 回答 9

6

对我来说,最简单的解决方案是像 samjudson 提到的那样创建子类。但是我想避免这种情况,因为它会使我的抽象类文件比我希望的要大得多。我宁愿将课程分成几个文件以进行组织。

没问题,只需使用partial关键字,您就可以将内部类拆分为任意数量的文件。您不必将其保存在同一个文件中。

上一个答案:

这是可能的,但只能通过反思

public abstract class AbstractClass
{
    public static AbstractClass MakeAbstractClass(string args)
    {
        if (args == "a")
            return (AbstractClass)Activator.CreateInstance(typeof(ConcreteClassA), true);
        if (args == "b")
            return (AbstractClass)Activator.CreateInstance(typeof(ConcreteClassB), true);
    }
}

public class ConcreteClassA : AbstractClass
{
    private ConcreteClassA()
    {
    }
}

public class ConcreteClassB : AbstractClass
{
    private ConcreteClassB()
    {
    }
}

这是另一种模式,没有丑陋的 MakeAbstractClass(string args)

public abstract class AbstractClass<T> where T : AbstractClass<T>
{
    public static T MakeAbstractClass()
    {
        T value = (T)Activator.CreateInstance(typeof(T), true);
        // your processing logic
        return value;
    }
}

public class ConcreteClassA : AbstractClass<ConcreteClassA>
{
    private ConcreteClassA()
    {
    }
}

public class ConcreteClassB : AbstractClass<ConcreteClassB>
{
    private ConcreteClassB()
    {
    }
}
于 2008-08-21T15:36:10.610 回答
3

如果这些类在同一个程序集中,你能不将构造函数设为内部吗?

于 2008-08-21T15:21:54.873 回答
2

您可以将子类设为子类,如下所示:

public abstract class AbstractClass
{
    public static AbstractClass MakeAbstractClass(string args)
    {
        if (args == "a")
            return new ConcreteClassA();
        if (args == "b")
            return new ConcreteClassB();
    }

    private class ConcreteClassA : AbstractClass
    {
    }

    private class ConcreteClassB : AbstractClass
    {
    }
}

@Vaibhav这确实意味着这些类也被隐藏了。但据我所知,这是完全隐藏构造函数的唯一方法。

编辑:正如其他人提到的,可以使用反射来完成同样的事情,这实际上可能更接近您想要的情况 - 例如,上述方法回复与抽象类位于同一文件内的具体类,这可能不是很方便。话虽如此,这种方式是一个很好的“Hack”,如果具体类的数量和复杂性很低,那就很好了。

于 2008-08-21T15:15:20.647 回答
1

不,我认为我们做不到。

于 2008-08-21T15:15:00.333 回答
1

接受的答案开始,如果您有一个公共接口并使私有类实现该接口,则您可以返回一个指向该接口的指针,然后您的父抽象类之外的任何人都可以使用它们(同时仍然隐藏子类)。

于 2008-09-10T12:30:08.677 回答
0

你真的要这样做吗?如果您使用某种伪工厂模式而没有真正的设计需求,那么您只会使您的代码更难理解、维护和扩展。

如果您不需要这样做,只需实现一个真正的工厂模式即可。或者,更多的 ALTy,使用 DI/IoC 框架。

于 2008-08-21T15:33:29.417 回答
0

您不能使用关键字partial将一个类的代码拆分为多个文件吗?

于 2008-08-21T15:55:08.803 回答
0

如果您在单独的服务程序集中使用此类,则可以使用 internal 关键字。

public class AbstractClass
{
    public AbstractClass ClassFactory(string args)
    {
        switch (args)
        {
            case "A":
                return new ConcreteClassA();               
            case "B":
                return new ConcreteClassB();               
            default:
                return null;
        }
    }
}

public class ConcreteClassA : AbstractClass
{
    internal ConcreteClassA(){ }
}

public class ConcreteClassB : AbstractClass
{
    internal ConcreteClassB() {}
}
于 2008-08-23T16:21:15.293 回答
-2

您需要做的是防止创建默认构造函数。如果类不在同一个程序集中,则内部可以更改为公共。

public abstract class AbstractClass{

 public static AbstractClass MakeAbstractClass(string args)
 {
    if (args == "a")
        return ConcreteClassA().GetConcreteClassA();
    if (args == "b")
        return ConcreteClassB().GetConcreteClassB();
 }
}

public class ConcreteClassA : AbstractClass
{
  private ConcreteClassA(){}

  internal static ConcreteClassA GetConcreteClassA(){
       return ConcreteClassA();
  }
}

public class ConcreteClassB : AbstractClass
{
  private ConcreteClassB(){}
  internal static ConcreteClassB Get ConcreteClassB(){
       return ConcreteClassB();
  }

}
于 2008-08-21T15:40:20.803 回答