Algo en lo que realmente no había pensado antes (sintaxis AS3):
private var m_obj:Object;
protected function get obj():Object
{
return m_obj;
}
private var m_str:String;
protected function get str():String
{
return m_str;
}
Al menos las subclases no podrán establecer m_obj o m_str (aunque aún podrían modificar m_obj).
Mi pregunta: ¿Es esto simplemente una exageración descarada?
La pregunta de este Programador: ¿ Cuándo o por qué debería uno usar getters / setters para propiedades de clase en lugar de simplemente hacerlas públicas? ha sido sugerido como un duplicado.
Esa pregunta es diferente porque solo aborda las propiedades públicas y privadas y si una propiedad debe envolverse con captadores y establecedores. Para mi pregunta, me estoy centrando en variables protegidas y cómo las clases heredadas interactuarían con esas variables.
Entonces la implementación alternativa sería:
protected var m_obj:Object; //more accessible than a private variable with a protected getter
protected var m_str:String; //more accessible than a private variable with a protected getter
Mi pregunta es similar porque estoy hablando sobre el uso de getters triviales protegidos para evitar que las subclases escriban en las variables, pero para permitirles el acceso a todos los demás.
En lenguajes como AS3, esto incluso les permitirá realizar cambios en las variables de objeto mutable, siempre que las referencias mismas no se modifiquen.
fuente
Respuestas:
Muchas veces lo es, a veces no lo es.
Mantenerse
m_obj
en un buen estado conocido ayuda a proteger el Principio de sustitución de Liskov, manteniendo su código más resistente y de mayor calidad. A veces puede confiar en los herederos para respetar ese comportamiento, a veces no puede hacerlo (ya sea debido al patrón de uso o la sutileza del contrato que implementa). Aunque este código / pregunta también tropieza con algunas de las razones de "¿Por qué Clean Code sugiere evitar las variables protegidas?"fuente
Los captadores protegidos triviales tienen al menos dos ventajas prácticas sobre una variable expuesta:
Para la depuración, son un lugar perfecto para poner un punto de interrupción condicional que se activa cuando "ese valor divertido entra en su programa". Es mucho más difícil obtener el mismo control si accede directamente al valor.
Para burlarse de un objeto, si está utilizando este método para probar descendientes.
El costo de usar getters es prácticamente cero, por lo que no hay una razón real para no usarlos. ¿Esta ahí?
fuente
public
oprotected
del getter! :-)get x() ... { return _y; }
nadie escribiría eso, pero podría suceder debido a un corte y pegado incorrecto.No importa si usa getters o acceso de campo, cualquier revisor experimentado descubrirá el problema en su diseño y se quejará de que sus objetos exponen datos en lugar de comportamiento.
Tenga en cuenta que apelar a "protegido" no ayudará, ya que el propósito de la herencia es permitir que las subclases ajusten / sintonicen el comportamiento del padre ( LSP ), no justificar el desorden indiscriminado con los datos del padre. Como Bertrand Meyer lo dice,
El razonamiento de "los captores son malvados" se aplica independientemente de si lo deletreas
get
explícitamente o lo enmascaras detrás del acceso al campo.Si está seriamente preocupado por el problema, lo primero que debe considerar es el rediseño del código para deshacerse de los captadores y el acceso de campo no privado , en lugar de jugar juegos mentales infructuosos para elegir cuál es la forma menos inapropiada .
Vale la pena enfatizar una vez más, esconder un diseño problemático detrás de una cortina de humo "protegida" no hará que el problema desaparezca, la herencia no justifica trucos como ese. Parafraseando su pregunta, esfuércese por diseñar las cosas de una manera que evite que las clases heredadas interactúen con esas variables , ni a través de getters ni a través del acceso de campo. Dile, no preguntes :
Dedicar tiempo y esfuerzo a decidir qué forma preferiría obtener información, contra el principio clásico que recomienda evitar esto por completo, ahora eso me parece una exageración descarada .
fuente
En el caso de una implementación de clase inmutable, proteger sus variables internas rompería el contrato que ha establecido, en cuyo caso los captadores protegidos no serían excesivos y necesarios (aunque tendría que devolver copias de su variable, no un puntero) )
En las clases mutables, sigo prefiriendo getters / setters a otorgar acceso directo a mis variables internas. Esto asegura que pueda cambiar la forma en que maneja sus variables internas como lo desee, sin temor a romper ningún código de cliente. Por ejemplo, imagine que tiene una clase Java de la siguiente manera:
La extensión de la clase del cliente
SomeClass
accedería directamentesomeVariable
, manipulándola como mejor les parezca. Ahora, esto puede crear todo tipo de problemas si estas clases no salensomeVariable
en un estado aceptable. Además, si decide en una versión posterior cambiar la definición deSomeClass
usar un enList<Integers>
lugar de una matriz, romperá la compatibilidad con la base de código existente, que esperaSomeClass
tener una matriz interna deint
s, no una lista deint
s.El uso de captadores protegidos en este caso le permitiría realizar este cambio sin romper ningún contrato preestablecido.
fuente