2009-11-10 14 views
13

Clase A y B son idénticos:modelos de Refactoring ActiveRecord con una clase base frente a un módulo base

class A < ActiveRecord::Base 
def foo 
    puts "foo" 
end 
end 

class B < ActiveRecord::Base 
def foo 
    puts "foo" 
end 
end 

¿Cuál es la diferencia entre la refactorización como este con una clase base de:

class Base < ActiveRecord::Base 
def foo 
    puts "foo" 
end 
end 

class A < Base 
end 

class B < Base 
end 

frente así utilizando un módulo base :

module Base 
def foo 
    puts "foo" 
end 
end 

class A < ActiveRecord::Base 
include Base 
end 

class B < ActiveRecord::Base 
include Base 
end 

¿Es preferible una forma a otra?

+0

¿Quiso incluir la definición de foo en las subclases en el ejemplo de la clase base? –

+0

No, no lo hice. Gracias. Lo quité. –

Respuesta

24

Hay una diferencia fundamental entre estos dos métodos que todas las otras respuestas están perdiendo, y eso es la aplicación rieles de las ITS (Herencia de tablas individual):

http://api.rubyonrails.org/classes/ActiveRecord/Base.html (Busque la sección 'Single herencia de tabla')

Básicamente, si usted refactorizar la clase base como esto:

class Base < ActiveRecord::Base 
    def foo 
    puts "foo" 
    end 
end 

class A < Base 
end 

class B < Base 
end 

a continuación, se supone que tiene una tabla de base de datos llamada "bases", con una columna denominada "tipo", que debe tener un valor de " Un "o" SEGUNDO". Las columnas de esta tabla serán las mismas en todos sus modelos, y si tiene una columna que pertenece a solo uno de los modelos, su tabla de "bases" se desnormalizará.

Mientras que, si refactoriza su clase base como esto:

Module Base 
    def foo 
    puts "foo" 
end 
end 

class A < ActiveRecord::Base 
include Base 
end 

class B < ActiveRecord::Base 
include Base 
end 

Entonces no habrá "bases" de mesa. En cambio, habrá una tabla "como" y una tabla "bs". Si tienen los mismos atributos, las columnas deberán duplicarse en ambas tablas, pero si hay diferencias, no se denomarán.

Por lo tanto, si uno es preferible sobre el otro, sí, pero eso es específico para su aplicación. Como regla general, si tienen exactamente las mismas propiedades o una gran superposición, use STI (primer ejemplo), sino, use Módulos (segundo ejemplo).

+0

Me pillaron jugando con este ejemplo, "Módulo" debería ser "módulo" – Rtype

5

Ambos métodos funcionarán. Al decidir usar un módulo o una clase, la pregunta que tengo es si la clase encaja en la jerarquía de objetos, o son solo métodos que estoy tratando de reutilizar. Si solo estoy tratando de factorizar un código común por razones DRY, eso suena como un módulo. Si realmente hay una clase que se ajusta a la jerarquía que tiene sentido por sí misma, uso una clase.

Procedente de un fondo Java, es refrescante. Puedo elegir tomar estas decisiones.

+0

Explicación realmente buena y concisa. – ifightcrime

1

El módulo le da más flexibilidad en que 1) solo puede heredar de una clase, pero puede incluir varios módulos, y 2) no puede heredar de una clase base sin heredar sus superclases, pero puede incluir un módulo en sí mismo (por ejemplo, es posible que desee agregar el método "foo" a otra clase que no sea un modelo de registro activo).

Otra diferencia es que dentro de los métodos de la clase Base se pueden llamar elementos desde ActiveRecord :: Base, pero no se puede hacer eso desde el módulo.

1

Depende de lo que realmente está tratando de hacer.

  1. Anulación o añadir métodos a ActiveRecord :: Base: hacer esto si desea que cada modelo de ActiveRecord en su aplicación a respond_tofoo.
  2. Subclase ActiveRecord :: Base, y hereda cada modelo de su subclase: Logra lo mismo que 1, pero cada modelo de su aplicación necesita extender una clase no convencional, entonces ¿por qué pasar por la molestia?
  3. incluyen módulo: Esto funciona muy bien si solo algunos modelos necesitan acceso a foo. Esto es más o menos lo que hacen todos esos complementos acts_as_<whatever>.

En pocas palabras, si desea que cada modelo tenga un comportamiento diferente al que ya proporciona ActiveRecord :: Base, use la opción 1. Si solo un puñado de sus modelos requiere el comportamiento, cree un módulo e inclúyalo en tus modelos (opción 3).

4

Tiene más flexibilidad con el módulo. La intención del módulo es abarcar diferentes tipos de clases. Con el otro método te estás encerrando en la Base. Aparte de eso, no hay mucha diferencia.

La respuesta de Ruby a la herencia múltiple es mixins. Dado que sus clases ya heredan de las clases específicas de Rails, ya no pueden heredar de sus clases personalizadas.

Así que su elección es encadenarse en una cadena larga, o usar una mezcla que es mucho más limpia y más fácil de entender.

Cuestiones relacionadas