¿Por qué utilizar attr_accessor, attr_reader y attr_writer de Ruby?

Ruby tiene esta práctica y conveniente forma de compartir variables de instancia utilizando claves como

attr_accessor :var
attr_reader :var
attr_writer :var

¿Por qué elegiría attr_reader o attr_writer si podría usar simplemente attr_accessor? ¿Hay algo como el rendimiento (que lo dudo)? Supongo que hay una razón, de lo contrario no habrían hecho tales claves.

Solución

Puede utilizar los diferentes accesores para comunicar su intención a alguien que lea su código, y facilitar la escritura de clases que funcionarán correctamente independientemente de cómo se llame a su API pública.

class Person
  attr_accessor :age
  ...
end

Aquí, puedo ver que puedo tanto leer como escribir la edad.

class Person
  attr_reader :age
  ...
end

Aquí, puedo ver que sólo puedo leer la edad. Imagina que se establece por el constructor de esta clase y después se mantiene constante. Si hubiera un mutador (escritor) para la edad y la clase se escribiera asumiendo que la edad, una vez fijada, no cambia, entonces se podría producir un error en el código que llamara a ese mutador.

Pero, ¿qué ocurre entre bastidores?

Si se escribe:

attr_writer :age

Eso se traduce en:

def age=(value)
  @age = value
end

Si escribes:

attr_reader :age

Eso se traduce en:

def age
  @age
end

Si escribes:

attr_accessor :age

Eso se traduce en:

def age=(value)
  @age = value
end

def age
  @age
end

Sabiendo eso, aquí'hay otra manera de pensar en ello: Si no tuvieras los ayudantes attr_..., y tuvieras que escribir tú mismo los accesores, ¿escribirías más accesores de los que necesita tu clase? Por ejemplo, si la edad sólo necesitara ser leída, ¿escribirías también un método que permitiera escribirla?

Comentarios (10)

No todos los atributos de un objeto están pensados para ser establecidos directamente desde fuera de la clase. Tener escritores para todas tus variables de instancia es generalmente un signo de encapsulación débil y una advertencia de que estás introduciendo demasiado acoplamiento entre tus clases.

Como ejemplo práctico: Escribí un programa de diseño en el que se ponían elementos dentro de contenedores. El elemento tenía attr_reader :container, pero no tenía sentido ofrecer un escritor, ya que la única vez que el elemento's contenedor debe cambiar es cuando se coloca en uno nuevo, que también requiere información de posicionamiento.

Comentarios (0)

No siempre se quiere que las variables de instancia sean totalmente accesibles desde fuera de la clase. Hay muchos casos en los que permitir el acceso de lectura a una variable de instancia tiene sentido, pero escribir en ella podría no tenerlo (por ejemplo, un modelo que recupera datos de una fuente de sólo lectura). Hay casos en los que se quiere lo contrario, pero no se me ocurre ninguno que no sea artificial.

Comentarios (0)