2009-10-22 6 views
20

(dejando de lado la cuestión de por si los tienen en absoluto.)captadores y definidores de estilo

que siempre han preferido la sobrecarga de funciones para darle el mismo nombre para getter y setters sólo tiene que utilizar.

int rate() { return _rate; }  
void rate(int value) { _rate = value; } 

// instead of  
int getRate() { return _rate; }  
void setRate(int value) { _rate = value; } 

// mainly because it allows me to write the much cleaner  
total(period() * rate());  
// instead of  
setTotal(getPeriod() * getRate()); 

Naturalmente, estoy en lo cierto, pero me pregunto si los escritores de la biblioteca tienen alguna buena razón?

+26

"Naturalmente, estoy en lo cierto" Eso es bastante gracioso, espero que haya sido una broma. –

Respuesta

30

Preferiría las versiones get/set porque es más claro en cuanto a lo que está sucediendo. Si vi rate() y rate (10), ¿cómo sé que rate (10) no está usando simplemente 10 en el cálculo para devolver la tasa? Yo no, así que ahora tengo que empezar a buscar para descubrir qué está pasando. Un solo nombre de función debería hacer una cosa, no dos cosas opuestas.

También, como otros han señalado, algunos prefieren omitir el 'get' y dejar el 'set', es decir,

int Rate(); 
void SetRate(int value); 

Esa convención es bastante claro, así, no tendría ningún problema leyendo eso.

+2

Buen punto. ¡Asuma que la persona que usa su código no es solo un maníaco homicida que sabe dónde vive, sino que también está un poco confundido! –

1

Mientras que el comentario de Ed es cierto, prefiero las propiedades reales sobre el antipatrón setter/getter. Cuando 1/3 de los métodos en su gráfico de dominio son métodos ficticios que han sido generados por eclipse, hay algo mal.

Sin propiedades de primera clase, sin embargo, creo que el antipatrón tiene más sentido.

Además, facilita la finalización del código.

obj.set (control shift space) para los emisores
obj.get (control shift space) de captadores

+0

¿Por qué es un "antipatrón" cuando las propiedades de primera clase son simplemente azúcar sintáctico para la misma cosa? el concepto es el mismo, es simplemente la implementación que difiere. –

+0

Es un antipatrón en el sentido de que podría ser un trazador de líneas. propiedad privada int valor; // ahora funciona con contenedores IoC; Hurra. "Repito 30 líneas de código en la parte superior de todas mis funciones. ¿Cómo es esto un antipatrón? ¡El código funciona!" –

+0

Creo que quiere decir que tener getters/setters en absoluto es un patrón anti -que no es necesariamente cierto- vea mi comentario a jmucchiello –

5

siempre he preferido omitir el 'conseguir' en mis captadores, como lo hace, con rate() en lugar de getRate(). Pero la sobrecarga para el colocador no me parece una muy buena idea, ya que el nombre rate no indica que el objeto está siendo mutado. Considere:

total(period() * rate()); // awesome, very clear 

rate(20); // Looks like it computes a rate, using '20'...but for what? And why ignore the return value? 
+0

este es el estilo de Qt y java. http://qt.gitorious.org/qt/pages/ApiDesignPrinciples ---> goto "el arte de nombrar" –

6

¿Qué tal int rate(); y void setRate(int value);? Esto tiene la virtud de no tener dos funciones del mismo nombre haciendo cosas diferentes, y todavía permite period() * rate().

+1

Probablemente lleve a la confusión con las personas que buscan getXXX –

+0

este es el estilo de Qt y Java. http://qt.gitorious.org/qt/pages/ApiDesignPrinciples ---> goto "el arte de nombrar" –

5

Hace unos años, habría estado de acuerdo por completo. Más recientemente, una duda comenzó a abrirse camino, porque eso hace que tomar la dirección de un getter o setter sea ambiguo. Con herramientas como tr1 :: bind, esto es realmente molesto.

Por ejemplo:

struct A 
{ 
    void Foo(int); 
    int Foo()const; 
}; 

std::vector<A> v = ....; 
std::vector<int> foos; 
// Extract Foo 
std::transform(
    v.begin(), v.end(), 
    std::back_inserter(foos), 
    //Ambiguous 
    // std::tr1::bind(&A::Foo) 
    //must write this instead. Yuck! 
    std::tr1::bind(static_cast<int(Foo::*)()>(&A::Foo)); 
); 

Dejando de lado la cuestión de por si los tienen en absoluto ;-)

+0

bind() y aún peor bind2nd() son las cosas que me hacen pensar que C++ está irremediablemente roto. ¡No se puede esperar razonablemente que un ser humano pueda analizar, y mucho menos escribir, esa línea de código correctamente! –

+1

Buen punto. La sobrecarga es buena por sí misma, pero se interpone cuando quiere comenzar a tomar direcciones de funciones. - @mgb: No subestimes a otros humanos. También se podría usar 'std :: mem_fun_ref', pero nuevamente debido a las sobrecargas, los tipos deben ser especificados:' std :: mem_fun_ref (& A :: Foo) '. – UncleBens

4

Voy a seguir adelante y menciono esto debería ser una pregunta wiki de la comunidad.

Cuando empecé a aprender C++ que buscaban guías de estilo, y Google, estaba bien para algunos puntos:

  • Métodos en mayúsculas (es sólo más bonita).
  • captadores claramente y lowecase (rate).
  • setters explícitamente y minúsculas (setRate).
+0

bien - fue solo una especie de pausa para tomar un café. –

2

Ser conciso es importante, pero no a costa de ser incompleto o engañoso. Por esa razón, prefiero GetFoo() y SetFoo() a Foo() y Foo (int foo).

1

Personalmente, creo que los getters y setters que se encuentran por parejas son un olor a código heredado de los lenguajes "visuales" y sus "propiedades". En una clase "buena", los miembros de los datos son de solo lectura o de solo lectura, pero no de lectura/escritura.

Creo que la causa más común de getters y setters no es llevar el modelo de objetos lo suficientemente profundo. En su ejemplo, ¿por qué se pasa el total del período y la tasa? ¿No son miembros de la clase? Por lo tanto, solo debe establecer el período y la frecuencia, y solo debería obtener un total.

Probablemente haya excepciones pero odio ver una clase y encontrar "getX/setX, getY/setY, etc." Simplemente parece que no se pensó lo suficiente en cómo DEBERÍA usarse la clase y más bien el autor hizo que la clase FUERA fácil de obtener con los datos para que no tuviera que considerar cómo debería usarse la clase.

Naturalmente, estoy en lo cierto.

+0

Piense en un tipo de punto 3d. Tendrá muchas funciones internas para hacer varias cosas matemáticas, pero finalmente necesitará las 6 funciones get/set x/y/z. –

+0

@mgb: personalmente, no creo que un tipo de punto 3d deba ocultar los miembros en primer lugar (excepto tal vez porque es posible que desee utilizar una matriz como representación interna). – UncleBens

2

Hay varios niveles para "obtener" y "Configuración"

  • utilizo para obtener y establecer operaciones "rápidos".
  • Si algo tardará más tiempo en ejecutarse, a menudo será un Calc, ya que estos nombres implican que se debe realizar algún trabajo para recuperar el resultado.
  • para operaciones más largas, que empiezan a entrar en prefijos como Cargar/Guardar, Consulta/tienda, lectura/escritura, Buscar/Buscar etc.

Así get/set se puede atribuir un significado útil, y ser parte de una estrategia de nombres más grande y consistente.

0

Exijo la convención en la que un método siempre debe ser un verbo y una clase siempre debe ser un sustantivo (excepto por funtores, por razones obvias). En cuyo caso, se debe usar un prefijo get/set para coherencia. Dicho eso, también estoy de acuerdo con Ed Swangren. Esto me parece que usar esos prefijos no es pan comido.

1

Otro problema que nadie más ha mencionado es el caso de la sobrecarga de funciones. Tome este ejemplo (artificial e incompleto):

class Employee { 
    virtual int salary() { return salary_; } 
    virtual void salary(int newSalary) { salary_ = newSalary; } 
}; 

class Contractor : public Employee { 
    virtual void salary(int newSalary) { 
     validateSalaryCap(newSalary); 
     Employee::salary(newSalary); 
    } 
    using Employee::salary; // Most developers will forget this 
}; 

Sin esa using cláusula, los usuarios de Contractor no pueden consultar el sueldo debido a la sobrecarga. Recientemente agregué -Woverloaded-virtual al conjunto de advertencia de un proyecto en el que trabajo, y he aquí, esto apareció por todos lados.

+0

¿No sabes el equivalente a -Woverloaded-virtual for MSVC? –

+1

@Greg lo siento, no lo hago. De hecho, me parece que las advertencias de MSVC (a partir del VC8) son en su mayoría contraproducentes (advertencia de rendimiento para la conversión entre bool e int? Struct previamente declarada como clase?) Como construyo en dos plataformas, generalmente confío en gcc para todo mi advertencias necesitadas – Tom

0

Prefiero evitar las etiquetas get y set, la información no es necesaria para que el compilador haga su trabajo para la mayoría de estas propiedades simples.

puede tener problemas:

class Stuff { 
    void widget(int something); // 'special' setter 
    const Widget& widget(int somethingelse) const; // getter 
} 
Stuff a; 
a.widget(1); // compiler won't know which widget you mean, not enough info 
+2

No escribe nombres significativos para el compilador, lo hace para el otro programador que tiene que usar su código. – Triskeldeian

+0

Por favor, no crea que escribir código corto/inteligente/conciso de alguna manera es automáticamente mejor. Escriba el código para que usted y sus compañeros sepan lo que está sucediendo 6 meses después sin tirarse del pelo. – nenchev

0

Si el captador es simplemente rate(), el compilador se queja de que es una redefinición de la otra rate símbolo, siempre le dio a su campo de un buen nombre significativo de esa manera. En ese caso, debe hacer algo tonto, como nombrar a su miembro _rate o algún otro enfoque similar. Personalmente odio ver/escribir esos guiones bajos, por lo que tienden a ir con el enfoque getRate().

Esto es obviamente subjetivo y esta simplemente es mi preferencia personal.

Cuestiones relacionadas