2008-08-21 18 views
5

Tengo una colección de clases que heredan de una clase abstracta que creé. Me gustaría utilizar la clase abstracta como una fábrica para crear instancias de implementaciones concretas de mi clase abstracta.¿Hay alguna manera de hacer que un constructor solo sea visible para una clase padre en C#?

¿Hay alguna manera de ocultar un constructor de todos los códigos, excepto una clase principal.

me gustaría hacer esto básicamente

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 
{ 
} 

Pero quiero que nadie pueda crear instancias directamente a las 2 clases concretas. Quiero asegurarme de que solo el método MakeAbstractClass() pueda instanciar las clases base. ¿Hay alguna manera de hacer esto?

ACTUALIZACIÓN
No necesito acceder a cualquiera de los métodos específicos de ConcreteClassA o B desde fuera de la clase abstracta. Solo necesito los métodos públicos que ofrece mi clase de Abstract. Realmente no necesito evitar que se creen instancias de las clases concretas, solo trato de evitarlo ya que no proporcionan nuevas interfaces públicas, solo implementaciones diferentes de algunas cosas muy específicas internas de la clase abstracta.

Para mí, la solución más simple es make child classes as samjudson mentioned. Sin embargo, me gustaría evitar esto, ya que haría que el archivo de mi clase abstracta fuera mucho más grande de lo que me gustaría. Prefiero mantener las clases divididas en unos pocos archivos para la organización.

supongo que no hay una solución fácil a este ...

Respuesta

2

Puede hacer que las clases sub clases hijas, algo como esto:

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 Esto significa de hecho que las clases también están ocultos. Pero hasta donde sé, es la única forma de ocultar completamente el constructor.

Editar: Como otros lo han mencionado, lo mismo se puede lograr usando Reflection, que en realidad podría ser más parecido a lo que le gustaría: por ejemplo, el método anterior responde que las clases concretas están dentro del mismo archivo la clase Abstracta, que probablemente no sea muy conveniente. Habiendo dicho eso de esta manera es un buen 'Hack', y es bueno si el número y la complejidad de las clases concretas es bajo.

+0

Buen ejemplo, pero haga que el nombre sea un poco más .NETy y llámelo "CreateAbstractClass (string args)" para sake de estándares de codificación :) –

1

No, no creo que podamos hacer eso.

3

Si las clases están en el mismo conjunto, ¿no puede hacer que los constructores sean internos?

0

¿De verdad necesita para hacer esto? Si está utilizando algún tipo de patrón de pseudo fábrica sin una verdadera necesidad de diseño, solo hará que su código sea más difícil de comprender, mantener y ampliar.

Si no necesita hacer esto, solo implemente un patrón de fábrica verdadero. O, más ALTAMENTE, use un marco DI/IoC.

6

Para mí, la solución más sencilla consiste en clases hijas tomamos como samjudson mencionado. Me gustaría evitar esto sin embargo, ya que haría que mi clase abstracta 'archivo mucho más grande que Me gustaría que fuera.Prefiero mantener clases divididas en unos pocos archivos para la organización .

No hay problema, sólo tiene que utilizar parcial palabra clave y se puede dividir sus clases internas en tantos archivos como desee. No es necesario que lo guarde en el mismo archivo.

respuesta anterior:

es posible, pero sólo con la reflexión

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() 
    { 
    } 
} 

y aquí es otro patrón, sin fea MakeAbstractClass (args de cadena)

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() 
    { 
    } 
} 
-2

Lo que hacer esto es para evitar que se cree el constructor predeterminado. El interno se puede cambiar a público si las clases no están en el mismo conjunto.

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

} 
0

No se puede utilizar la palabra clave partial para dividir el código de una clase en muchos archivos?

0

Si está utilizando esta clase en un conjunto de servicios independiente, puede utilizar la palabra clave interna.

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() {} 
} 
1

A raíz de la accepted answer, si tuviera una interfaz pública e hizo las clases privadas implementan la interfaz, se puede entonces devolver un puntero a la interfaz y cualquier persona fuera de su progenitor clase abstracta podría utilizar ellos (mientras aún se esconden las clases de niños).

Cuestiones relacionadas