ventajas patron implementar explicacion ejercicios ejemplos diseño desventajas consecuencias como ruby-on-rails singleton

ruby on rails - patron - Cómo implementar un modelo singleton



singleton c# (10)

Las probabilidades son buenas, no necesitas un singleton. Es desafortunado que uno de los peores hábitos de diseño para salir de la locura de los patrones sea también uno de los más comúnmente adoptados. Culpo a la desafortunada apariencia de simplicidad, pero estoy divagando. Si lo hubieran llamado el patrón "Global estático", estoy seguro de que la gente habría sido más tímida al usarlo.

Sugiero usar una clase contenedora con una instancia privada estática de la clase que desea usar para el singleton. No introducirás una pareja estrecha en todo tu código como lo harás con el singleton.

Algunas personas lo llaman un patrón monostate. Tiendo a pensar que es simplemente otro giro en el concepto de estrategia / agente ya que puede permitir una mayor flexibilidad mediante la implementación de diferentes interfaces para exponer / ocultar la funcionalidad.

Tengo un sitio en rieles y quiero tener una configuración para todo el sitio. Una parte de mi aplicación puede notificar al administrador por SMS si ocurre un evento específico. Este es un ejemplo de una característica que quiero configurable a través de la configuración de todo el sitio.

Así que estaba pensando que debería tener un modelo de configuración o algo así. Tiene que ser un modelo porque quiero poder has_many: contactos para la notificación por SMS.

El problema es que solo puede haber una publicación en la base de datos para el modelo de configuración. Entonces, estaba pensando en usar un modelo de Singleton, pero eso solo evita que se creen nuevos objetos, ¿verdad?

¿Debo seguir necesitando crear métodos getter y setter para cada atributo así:

def self.attribute=(param) Model.first.attribute = param end def self.attribute Model.first.attribute end

¿Acaso no es la mejor práctica usar el atributo Modelo directamente, pero siempre crear una instancia y usar eso?

¿Qué debería hacer aquí?


No estoy seguro de que desperdicie la base de datos / gastos generales de ActiveRecord / Model para una necesidad tan básica. Estos datos son relativamente estáticos (supongo) y sobre la marcha los cálculos no son necesarios (incluidas las búsquedas en la base de datos).

Habiendo dicho eso, recomiendo que defina un archivo YAML con la configuración de su sitio y defina un archivo de inicializador que cargue las configuraciones en una constante. No tendrá casi tantas partes móviles innecesarias.

No hay ninguna razón por la que los datos no puedan simplemente quedarse en la memoria y ahorrarle una tonelada de complejidad. Las constantes están disponibles en todas partes, y no es necesario inicializarlas ni crear instancias. Si es absolutamente crítico que utilices una clase como singleton, te recomendaría hacer estas dos cosas:

  1. undef el método initialize / new
  2. definir solo los métodos self. * de esa manera no es posible para usted mantener un estado

Usar has_many :contacts no significa que necesites un modelo. has_many hace algo de magia, pero al final solo agrega un método con un contrato específico. No hay ninguna razón por la que no pueda implementar esos métodos (o algún subconjunto que necesite) para hacer que su modelo se comporte como si has_many :contacts pero que realmente no utilizara un modelo (o modelo) ActiveRecord para el Contacto.


También puede consultar Configatron:

http://configatron.mackframework.com/

Configatron hace que la configuración de sus aplicaciones y scripts sea increíblemente fácil. Ya no es necesario utilizar constantes o variables globales. Ahora puede usar un sistema simple e indoloro para configurar su vida. Y, como es todo Ruby, ¡puedes hacer cualquier cosa loca que quieras!


No estoy de acuerdo con la opinión común: no hay nada de malo en leer una propiedad fuera de la base de datos. Puede leer el valor de la base de datos y congelarlo si lo desea, sin embargo, podría haber alternativas más flexibles a la congelación simple.

¿En qué se diferencia YAML de la base de datos? .. mismo ejercicio: externo a la configuración persistente del código de la aplicación.

Lo bueno del enfoque de la base de datos es que se puede cambiar sobre la marcha de forma más o menos segura (sin abrir y sobrescribir archivos directamente). Otra cosa agradable es que se puede compartir a través de la red entre los nodos del clúster (si se implementa correctamente).

Sin embargo, la pregunta sigue siendo cuál sería la forma correcta de implementar dicha configuración utilizando ActiveRecord.


Sé que este es un hilo viejo, pero solo necesitaba lo mismo y descubrí que hay una joya para esto: acts_as_singleton .

Las instrucciones de instalación son para Rails 2, pero también funciona muy bien con Rails 3.


También podría aplicar un máximo de un registro de la siguiente manera:

class AppConfig < ActiveRecord::Base before_create :confirm_singularity private def confirm_singularity raise Exception.new("There can be only one.") if AppConfig.count > 0 end end

Esto anula el método ActiveRecord para que explote si intenta crear una nueva instancia de la clase cuando ya existe.

A continuación, puede definir solo los métodos de clase que actúan en un registro:

class AppConfig < ActiveRecord::Base attr_accessible :some_boolean before_create :confirm_singularity def self.some_boolean? settings.some_boolean end private def confirm_singularity raise Exception.new("There can be only one.") if AppConfig.count > 0 end def self.settings first end end


class Constant < ActiveRecord::Base after_initialize :readonly! def self.const_missing(name) first[name.to_s.downcase] end end

Constant :: FIELD_NAME


(Estoy de acuerdo con @ user43685 y no estoy de acuerdo con @Derek P; existen muchas buenas razones para mantener los datos de todo el sitio en la base de datos en lugar de un archivo yaml. Por ejemplo, su configuración estará disponible en todos los servidores web (si tener varios servidores web), los cambios a su configuración serán ACID, no tiene que perder tiempo implementando un contenedor YAML, etc.

En los rieles, esto es bastante fácil de implementar, solo tiene que recordar que su modelo debe ser un "singleton" en términos de base de datos, no en términos de objetos ruby.

La forma más fácil de implementar esto es:

  1. Agregue un nuevo modelo, con una columna por cada propiedad que necesite
  2. Agregue una columna especial llamada "singleton_guard" y valide que siempre es igual a "0", y márquela como única (esto exigirá que haya solo una fila en la base de datos para esta tabla)
  3. Agregue un método de ayuda estático a la clase de modelo para cargar la fila singleton

Entonces, la migración debería verse más o menos así:

create_table :app_settings do |t| t.integer :singleton_guard t.datetime :config_property1 t.datetime :config_property2 ... t.timestamps end add_index(:app_settings, :singleton_guard, :unique => true)

Y la clase de modelo debería verse más o menos así:

class AppSettings < ActiveRecord::Base # The "singleton_guard" column is a unique column which must always be set to ''0'' # This ensures that only one AppSettings row is created validates_inclusion_of :singleton_guard, :in => [0] def self.instance # there will be only one row, and its ID must be ''1'' begin find(1) rescue ActiveRecord::RecordNotFound # slight race condition here, but it will only happen once row = AppSettings.new row.singleton_guard = 0 row.save! row end end end

En Rails> = 3.2.1 deberías poder reemplazar el cuerpo del getter "instancia" con una llamada a " first_or_create! "


Sencillo:

class AppSettings < ActiveRecord::Base before_create do self.errors.add(:base, "already one setting object existing") and return false if AppSettings.exists? end def self.instance AppSettings.first_or_create!(...) end end