2009-04-09 20 views
6

Estoy trabajando en C# 2.0, pero esto se aplicaría a la mayoría de los lenguajes orientados a objetos. Cuando creo clases con propiedades públicas que envuelven campos privados, vuelvo a & entre si debo usar la propiedad o el campo internamente. Por supuesto, C# 3.0 hace que esto sea más fácil con propiedades automáticas, pero aún podría aplicarse.OO Design: ¿utiliza internamente propiedades públicas o campos privados?

¿Importa?

public class Person 
{ 
    private string _name = ""; 

    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public Person(string name) 
    { 
     _name = name; //should I use the property or field here? 
    } 
} 

Respuesta

2

sobre todo es como un código de preferencia, pero yo' prefieren utilizar las propiedades públicas o privadas jamás propiedades, simplemente puede añadir un poco de lógica a la propiedad sin ningún cambio en el código de llamada. También en 3.5 .NET tienes código útil sugar como autopropiedad.

2

Recomendaría utilizar la propiedad, nunca se sabe cuándo podría estar haciendo algo dentro de su propiedad, es decir. carga lenta, conversión, formateo, cálculo, etc. que introduciría un error si usó el miembro privado ...

0

Normalmente utilizo las propiedades públicas con algunas excepciones en las que es posible que desee evitar cualquier código adicional escrito en el acceso a la propiedad. Con propiedades automáticas en C# 3.0, raramente creo campos de respaldo a mano; normalmente solo cuando el valor predeterminado del campo de respaldo automático no es apropiado para mi propiedad.

0

Al menos en Java, no hay forma de que use los campos públicos porque las buenas convenciones de javabeans, que todo el mundo parece usar. Supongo que C# tiene propiedades como construcciones del primer idioma. Yo iría por ese

+1

Sí, es un gran beneficio de C#. – Randolpho

+0

¿De qué estás hablando para aquellos de nosotros que no conocemos estas cosas de javabeaner? –

+1

No debe seguir las convenciones simplemente porque "todo el mundo parece usarlas", especialmente si no puede justificarlo usted mismo. La convención no implica ni prueba que sea una buena idea. ¡Cuestión! :) – JoshJordan

0

Debería usar "Nombre" (propiedad), porque si quiere algunos controles para este valor, puede colocarlo en el setter de la propiedad "Nombre" y luego será utilizado para el constructor y para últimamente valor de configuración también.

1

Utilice la propiedad. O mejor aún, si usted está usando C# 3.0 o superior utilización Propiedades automática de este modo:

public class Person 
{ 
    public string Name { get; set; } 

    public Person(string name) 
    { 
     Name = name; //should I use the property or field here? 
    } 
} 

Si se utiliza la propiedad ahora usted estará listo cuando se modifica el código para utilizar Propiedades automáticas.

14

Básicamente, como puede implementar su validación y otra lógica en la propiedad, debe acceder a través de la propiedad a menos que tenga un motivo específico para no hacerlo.

Ayuda con la coherencia dentro de su objeto, porque de esa manera usted sabe que los valores de sus campos privados han pasado por los rigores que elija poner en su acceso o métodos de configuración.

Por otro lado, el constructor puede ser una excepción a esto, porque es posible que desee establecer los valores iniciales.

Pero, en general, yo diría que el acceso a través de la propiedad.

EDITAR

A (artificial/trivial) ejemplo

public class Person 
{ 
    private string _name = ""; 
    private List<String> oldnames = new ArrayList(); 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      oldnames.Add(_name); 
      _name = value; 
     } 
    } 

    public Person(string name) 
    { 
     _name = name; //should I use the property or field here? 
    } 
} 

lo tanto, en este caso, le gustaría que el constructor para omitir la propiedad, pero si uso cada vez más el campo se le estar causando un error en su código porque se está saltando el 'nombre de archivo'.La razón para validar su propiedad es para no tener que duplicar el código de validación en cada lugar al que acceda al campo, por lo que no debe omitirlo ni siquiera en métodos privados.

+0

Creo que debería señalar que Java y C# son idiomas diferentes. C# tiene propiedades, Java no. – epochwolf

+0

¿Cómo puedo editar mi respuesta para incorporar esta información? – DevinB

+0

Oh, ya veo, sí, por alguna razón, pensé que la pregunta estaba relacionada con Java. – DevinB

0

Depende. A veces, escribirá getters/setters que hacen preprocesamiento importante para cualquier interacción realista con el campo. Por ejemplo, si un campo de cadena tiene una restricción que siempre debe estar en minúscula, entonces al menos uno de sus métodos getter/setter debe hacer una llamada a .ToLower() o .ToLowerInvariant(), y en su código de clase, usted probablemente quiero usar esto para asegurarme de que la restricción se aplique.

Sin embargo, también habrá ocasiones en las que necesite eludir esa lógica de preprocesamiento. De hecho, he visto momentos en que los desarrolladores crean inadvertidamente bucles infinitos al usar la propiedad pública en lugar del campo privado (no puedo pensar en un ejemplo fuera de lo común, lo siento).

Linq Las clases generadas en SQL son un buen ejemplo, creo, porque muestran la cantidad de lógica que puede existir en una propiedad. Intente escribir algunos métodos de extensión y comenzará a entender la diferencia.

Creo que la conclusión es que depende del tipo de lógica que esté utilizando en un punto determinado de la clase y del tipo de preprocesamiento existente en los getters/setters. Si alguna vez no está seguro o parece que no le importa, probablemente sea mejor usar la propiedad getters/setters/public para que escriba más código de mantenimiento que seguirá las restricciones agregadas más adelante.

1

Puede haber una situación en la que tendrá que acceder al campo internamente. Por ejemplo, cuando solo se ofrece públicamente el acceso de solo lectura a una propiedad y no se permite el cambio del valor después de que se crea una instancia de un objeto.

public class MyClass 
{ 
    private string _MyProperty; 

    public MyProperty { get { return _MyProperty; } } 

    public MyClass() 
    { 
     _MyProperty = SomeVeryComplexPropertyInitializationLogic(); 
    } 
} 
1

Si utiliza el nombre del campo, no obtiene la encapsulación. La encapsulación se aplica no solo entre clases, sino también dentro de una clase.

Si en algún momento futuro redefine el campo pero deja las firmas de la función de acceso/configuración iguales, no solo las clases externas que usan su clase no se romperán, sino que las rutinas internas de su propia clase tampoco se romperán .

Tomemos por ejemplo el código, basado libremente en el código que aparece en el marco de Apache Wicket (aunque el marco no sufre este problema, yo sólo estoy usando ilustrar):

Digamos que esto fuera la clase original:

class RadioChoice { 
    private String prefix; 

    RadioChoice(String prefix) { 
    this.prefix = prefix ; 

    setPrefix(String prefix) { 
    this.prefix = prefix ; 
    } 
} 

Aquí ya podemos ver un problema: la misma operación this.prefix = prefix ocurre en lugares de remolque. Tiene la intención de hacer exactamente lo mismo, pero dado que ocurre en dos lugares, esa "misma cosa" puede dividirse en dos cosas diferentes. (Compare esto con la normalización de la base de datos, una práctica diseñada para evitar exactamente eso.)

Ahora, Apache Wicket tiene un concepto de grabación de cambios en la forma en que procesa las páginas web, para que esos cambios puedan deshacerse. Lo hace almacenando una lista de objetos "deshacer". prefijo de un RadioChoice es una de esas cosas que se pueden deshacer, por lo que el colocador 'prefijo' debe registrar el cambio:

class RadioChoice { 
    private String prefix; 

    RadioChoice(String prefix) { 
    this.prefix = prefix ; 

    setPrefix(String prefix) { 
    // save the old prefix 
    this.getPage().addChange(new PrefixChange(this.prefix)); 
    // set the new one 
    this.prefix = prefix ; 
    } 
} 

Ahora mira lo que pasa: porque el constructor establece el prefijo directamente, ningún cambio es salvado por el ctor. Si hubiéramos usado el colocador, el ctor automáticamente "haría lo correcto" después de una refactorización. En su lugar, tenemos que refactorizar el setter y el ctor.

Por supuesto, nuestro código sigue siendo inferior a la óptima, en realidad, debería ser esta:

setPrefix(String prefix) { 
    // save the old prefix 
    this.getPage().addChange(new PrefixChange(this.getPrefix())); 
    // set the new one 
    this.prefix = prefix ; 
    } 
} 

Scott Meyers tenía una serie de artículos sobre este, donde abogó que (en C++, que tiene funciones libres) una clase exponer solo funciones primitivas (funciones primitivas: funciones no posibles excepto por la clase iteslf) y que todas las funciones que podrían estar compuestas de funciones primitivas se hagan funciones libres. Esto lo convierte en una interfaz más delgada, una interfaz más estable.

De la misma manera, en la medida en que puede considerar que las funciones de la clase dependen solo de su interfaz primitiva, tendrá más flexibilidad; en particular, esas funciones son candidatas para ser retiradas de la clase. De manera más general, usar setters y getters lo aísla de los cambios.

Cuestiones relacionadas