2010-09-08 33 views
6

¿Cómo me aseguro de que cierta clase solo sea instanciada por una fábrica y no llamando al nuevo directamente?asegúrese de que el objeto solo se haya creado de fábrica (C#)

EDIT: necesito la fábrica para que sea una clase separada (para fines de inyección de dependencia) por lo que no puede hacer que sea un método estático de la clase para crear una instancia, y por eso no se puede hacer nueva privado.

Respuesta

5

Si, por alguna razón, necesita que la fábrica y la clase construida estén en ensamblajes separados (lo que significa que simplemente usando internal no funcionará), y puede asegurarse de que su fábrica tenga la oportunidad de funcionar primero, usted puede hacer esto:

// In factory assembly: 

public class Factory 
{ 
    public Factory() 
    { 
     token = new object(); 
     MyClass.StoreCreateToken(token); 
    } 

    public MyClass Create() 
    { 
     return new MyClass(token); 
    } 

    private object token; 
} 

// In other assembly: 

public class MyClass 
{ 
    public static void StoreCreateToken(object token) 
    { 
     if (token != null) throw new InvalidOperationException(
      "Only one factory can create MyClass."); 

     this.token = token; 
    } 

    public MyClass(object token) 
    { 
     if (this.token != token) throw new InvalidOperationException(
      "Need an appropriate token to create MyClass."); 
    } 

    private static object token; 
} 

Sí, es engorroso e incómodo. Pero puede haber situaciones extrañas donde esta es realmente una buena solución.

+0

Me gusta esto, excepto que hay 2 problemas ... (1) Su ejemplo parece permitirme usar solo 1 fábrica. Me gustaría permitir que se creen muchas fábricas (tal vez hay diferentes sabores de fábrica) el único requisito es que un objeto de MyClass se debe crear utilizando un objeto de fábrica. (2) ¿Qué ocurre si uso genéricos con una nueva restricción() y, por lo tanto, MyClass necesita tener un constructor sin parámetros? Tu ejemplo no funcionaría en ese escenario. – JoelFan

+0

"Tu ejemplo parece permitirme usar solo 1 fábrica". Convierta 'token' estático o compártalo entre las diferentes instancias de fábrica de otra manera. Cualquier cosa que tenga acceso al token puede crear instancias de 'MyClass'" ¿Qué sucede si estoy usando genéricos con una restricción new() y, por lo tanto, MyClass necesita tener un constructor sin parámetros? " Entonces tampoco necesitas una fábrica. – munificent

11

Haga sus constructores privados y proporcione el método de fábrica como método estático en la clase misma.

En la mayoría de los casos puede hacer que los constructores sean internos, lo que le permite dividir la fábrica en su propia clase. He descubierto que a menudo no vale la pena evitar que mi equipo use new para crear instancias dentro de la clase 'ensamblaje.

5

Haga que el constructor sea interno y aloje la fábrica en el mismo ensamblaje.

public MyClass 
{ 
    internal MyClass() 
    { 
    } 
} 

en mismo conjunto

public MyClassGenerator 
{ 
    public static CreateMyClass() 
    { 
     return new MyClass(); 
    } 
} 

Si la fábrica no puede estar en el mismo montaje o este método no funciona para usted, busque a Dan's answer

22

Si la fábrica se encuentra en el mismo ensamblaje y solo necesita protección contra ensamblajes externos creando una instancia de la clase, puede hacer que el constructor sea interno. La única forma que conozco de evitar esto para todas las demás clases (incluidas las del mismo ensamblaje) es convertir la clase instanciada en una clase privada anidada de la fábrica y solo exponerla como una interfaz. Si la clase es su propia fábrica (un método de fábrica estático), puede hacer que el constructor sea privado, como han mencionado otros.

+0

1 - si realmente necesita esto, eso es cómo lograr que se haga. –

1

Siempre se creará llamando al en algún lugar, pero si solo quiere que eso suceda en su clase de fábrica, puede establecer todos los constructores en Interno (o Privado, y usar un método de fábrica Estático público en el misma clase).

0

No me gusta tener la fábrica en el tipo en sí, especialmente si se trata de un objeto de dominio. Tenga interna si tiene una clase separada como fábrica (que creo que debería). Use el atributo InternalVisible si la fábrica está en el ensamblaje diferente.

1

Muchas personas han mencionado el uso interno, pero también puede proteger sus constructores y derivar una clase que solo tiene el método de fábrica estático en ella. Esto no impide que otros hagan lo mismo, pero hace un buen trabajo al restringir el acceso directo a sus constructores.

2

Puede hacer sus clases concretas como clases privadas anidadas con constructores públicos dentro de su clase de fábrica: de esta manera su fábrica puede crearlas, otras ni siquiera pueden verlas. De todos modos, regresas de fábrica con alguna clase de interfaz/resumen, no de tipo concreto. Por supuesto que no podrá convertir su tipo de devolución a un tipo concreto en algún lugar de un código de cliente pero primero es un signo de mal diseño, segundo siempre puede solucionarlo con una clase de interfaz/abstracta más concreta hereda su clase privada anidada .

puede hacer referencia a la respuesta de la Eric Lippert aquí (para un problema similar): Why Would I Ever Need to Use C# Nested Classes

Cuestiones relacionadas