Pregunta

Supongamos que tengo una clase 'Aplicación'. Para ser inicializado se requieren ciertas configuraciones en el constructor. Supongamos también que la cantidad de configuraciones es tanta que es convincente ubicarlas en una clase propia.

Compare las siguientes dos implementaciones de este escenario.

Implementación 1:

class Application 
{
   Application(ApplicationSettings settings) 
   {
       //Do initialisation here
   }
}

class ApplicationSettings 
{
   //Settings related methods and properties here
}

Implementación 2:

class Application 
{
   Application(Application.Settings settings) 
   {
       //Do initialisation here
   }

   class Settings 
   {
      //Settings related methods and properties here
   }
}

Para mí, el segundo enfoque es muy preferible. Es más legible porque enfatiza fuertemente la relación entre las dos clases. Cuando escribo código para instanciar la clase de aplicación en cualquier lugar, el segundo enfoque se verá más bonito.

Ahora imagínense que la clase Settings en sí misma a su vez tenía algo similar "relacionado". clase y esa clase a su vez también lo hicieron. Ir solo en tres de esos niveles y el nombre de la clase se sale de control en el caso 'no anidado'. Sin embargo, si anidas, las cosas siguen siendo elegantes.

A pesar de lo anterior, he leído personas que dicen en StackOverflow que las clases anidadas se justifican solo si no son visibles para el mundo exterior; es decir, si se usan solo para la implementación interna de la clase contenedor. La objeción comúnmente citada es hinchar el tamaño de contener el archivo fuente de la clase, pero las clases parciales son la solución perfecta para ese problema.

Mi pregunta es, ¿por qué desconfiamos de los "expuestos públicamente"? uso de clases anidadas? ¿Hay algún otro argumento en contra de dicho uso?

¿Fue útil?

Solución

Creo que está bien. Este es básicamente el patrón de construcción, y el uso de clases anidadas funciona bastante bien. También permite que el constructor acceda a miembros privados de la clase externa, lo que puede ser muy útil. Por ejemplo, puede tener un método Build en el generador que llama a un constructor privado en la clase externa que toma una instancia del generador:

public class Outer
{
    private Outer(Builder builder)
    {
        // Copy stuff
    }

    public class Builder
    {
        public Outer Build()
        {
            return new Outer(this);
        }
    }
}

Eso asegura que la única forma de construir una instancia de la clase externa es a través del constructor.

Utilizo un patrón muy similar a este en mi puerto C # de Protocol Buffers.

Otros consejos

Puede usar espacios de nombres para relacionar cosas que están ... relacionadas.

Por ejemplo:

namespace Diner
{
    public class Sandwich
    {
        public Sandwich(Filling filling) { }
    }

    public class Filling { }
}

La ventaja de esto sobre el uso de clases como si fueran espacios de nombres es que opcionalmente puede usar usando en el lado de la llamada para abreviar cosas:

using Diner;

...

var sandwich = new Sandwich(new Filling());

Si usa la clase Sandwich como si fuera un espacio de nombres para Filling , debe usar el nombre completo Sandwich.Filling para consulte Relleno .

¿Y cómo vas a dormir por la noche sabiendo eso?

Es posible que desee comprobar lo que Microsoft tiene que decir sobre el tema. Básicamente es una cuestión de estilo, diría.

Otro ejemplo práctico que tengo para un uso válido de clases públicas anidadas está en el patrón MVC cuando uso un modelo de vista con una propiedad IEnumerable. por ejemplo:

public class OrderViewModel
{
public int OrderId{ get; set; }
public IEnumerable<Product> Products{ get; set; }

public class Product {
public string ProductName{ get; set; }
public decimal ProductPrice{ get; set; }
}

}

Lo uso porque no quiero que la clase Product se reutilice en el exterior porque está personalizado solo para ese modelo de vista específico que lo contiene. Pero no puedo hacerlo privado porque la propiedad de Productos es pública.

Utilizo principalmente clases anidadas para ajustar el acceso a la clase anidada y / o al contenedor.

Una cosa para recordar es que una definición de clase anidada es básicamente un miembro de la clase y tendrá acceso a todas las variables privadas del contenedor.

También puede usar esto para controlar el uso de una clase específica.

Ejemplo:

public abstract class Outer
{
  protected class Inner
  {
  }
}

Ahora, en este caso, el usuario (de su clase) solo puede acceder a la clase Inner, si implementa Outer.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top