2009-12-29 23 views
8

Una pequeña introducción:Programación y transacciones orientadas a objetos

La clase contiene campos y métodos (permítanme omitir propiedades esta vez).
Los campos representan un estado de la clase.
Los métodos describen comportamiento de la clase.

En una clase bien diseñada, un método no cambiará el estado de la clase si arroja una excepción, ¿verdad? (En otras palabras, pase lo que pase, el estado de la clase no debe ser dañado)

Pregunta:

¿Existe un marco, un patrón de diseño, mejores prácticas o un lenguaje de programación para llamar a una secuencia de métodos en una transaccional estilo, para que el estado de cualquiera de las clases no se modifique (en caso de excepción), o todo tenga éxito?

ej .:

// the class foo is now in the state S1 
foo.MoveToState2(); 
// it is now (supposed to be) in the state S2 
foo.MoveToFinalState(); 
// it is now (supposed to be) in the state, namely, S3 

Sin duda, una excepción podría ocurrir tanto en MoveToState2() y MoveToFinalState(). Pero desde este bloque de código, quiero que la clase foo esté en el estado S1 o S3.

Este es un escenario simple con una sola clase involucrada, no if, no while, sin efectos secundarios, pero espero que la idea sea clara.

Respuesta

3

No es el método más eficiente, pero podría tener un objeto que represente sus datos transaccionales. Cuando inicie una transacción, haga una copia de los datos y realice todas las operaciones sobre eso. Cuando la transacción finaliza exitosamente, mueva la copia a sus datos reales; esto se puede hacer usando punteros, por lo tanto, no es necesario que sea demasiado ineficiente.

1

Esto sería bastante feo para implementar en todas partes, pero solo guardar el estado localmente, restaurarlo en el caso de una excepción funcionaría en escenarios simples. Tendría que atrapar y volver a lanzar la excepción, que puede perder contexto en algunos idiomas. Sería mejor envolverlo si es posible para mantener el contexto.

try { 
    save state in local variables 
    move to new state 
} catch (innerException) { 
    restore state from local variables 
    throw new exception(innerException) 
} 
5

Tome un vistazo a la Memento pattern

El patrón memento es un patrón de diseño de software que proporciona la capacidad de restaurar un objeto a su estado anterior (deshacer a través de rollback).

+1

Como digo en mi publicación, el recuerdo se usa más en un entorno de interfaz gráfica de usuario, para persistencia y deshacer/rehacer. Aunque el concepto básico es el mismo (crear otra clase que represente el estado) no debe transitar al nuevo estado hasta que sea completamente seguro hacerlo. Eso sugiere intentar crear el nuevo estado, y solo si este paso tiene éxito, cambiar el estado en el nuevo. – fabrizioM

2

La programación funcional es un paradigma que parece ajustarse bien a los cálculos transaccionales. Como no se permiten efectos secundarios sin declaración explícita, usted tiene control total de todo el flujo de datos.

Por lo tanto el software memoria transaccional puede expresarse fácilmente en términos funcionales - Ver STM for F#

La idea clave es el concepto de monads.Se puede usar una mónada para modelar un cálculo arbitrario a través de dos primitivas: Devolver para devolver un valor y Enlazar para secuenciar dos cálculos. Usando estos dos, puede modelar una mónada transaccional que controla y guarda todo el estado en forma de continuaciones.

Se podría tratar de modelar estos en una forma orientada a objetos a través de un patrón de State + Memento, pero en general, las operaciones en los lenguajes imperativos (como los OO-ones comunes) son mucho más difíciles de implementar ya que se puede realizar lado arbitraria -efectos. Pero, por supuesto, puede pensar en un objeto que define un alcance de transacción, que guarda, valida y restaura datos según sea necesario, dado que exponen una interfaz adecuada para esto (los patrones que mencioné anteriormente).

1

.) La memoria transaccional encaja aquí de la mejor manera.

.) Una opción podría ser un almacenamiento transaccional. implementación de ejemplo se puede encontrar aquí:.. http://www.codeproject.com/KB/dotnet/Transactional_Repository.aspx

) Memento patrón

) También permítanme describir un posible patrón en la forma de aplicar este tipo de comportamiento: definir una clase base TransactionalEntity. Esta clase contiene diccionario de propiedades. Todas sus clases transaccionales heredan del TransactionalEntity y deben operar sobre algún tipo de Propiedades/Campos de dependencia, es decir, propiedades (getters/setters) que almacenan sus valores no en campos de clases locales, sino en diccionario, que se almacena en la base clase. Luego se define la clase TransactionContext. La clase TransactionContext contiene internamente un conjunto de diccionarios (un diccionario para cada entidad que participa en la transacción) y cuando una entidad transaccional participa en la transacción, escribe todos los datos en el diccionario en el contexto de la transacción. Entonces todo lo que necesita es básicamente cuatro métodos:

TransactionContext.StartTransaction(); 
TransactionalEntity.JoinTransaction(TransactionContext context); //if your language/framework supports Thread Static fields, then you do not need this method 
TransactionContext.CommitTransaction(); 
TransactionContext.RollbackTransaction(); 

En resumen, es necesario almacenar el estado de la clase base TransactionalEntity y durante la transacción TransactionalEntity cooperará con TransactionContext.

Espero, lo he explicado bastante bien.

0

Al utilizar el enfoque de copia de objetos, debe tener cuidado de que las declaraciones que se van a retrotraer solo afecten a los datos del objeto o de sí mismo (y a los agregados).

Pero las cosas se ponen realmente difíciles si los efectos secundarios de las declaraciones son "más externos". Por ejemplo, operaciones de E/S, llamadas de red. Siempre debe analizar los cambios de estado generales de sus declaraciones.

También es muy complicado si toca datos estáticos (o singletons malvables mutables). La reversión de estos datos aislados es difícil, porque otros hilos podrían haberlos modificado (podría enfrentar actualizaciones perdidas).

Volviendo/rollback al pasado a menudo no es tan trivial;)

3

El "patrón" más sencilla y fiable para usar aquí es una estructura de datos inmutables.

En lugar de escribir:

foo.MoveToState2(); 
foo.MoveToFinalState(); 

Usted escribe:

MyFoo foo2 = foo.MoveToState2(); 
MyFoo finalFoo = foo2.MoveToFinalState(); 

y poner en práctica los métodos en consecuencia - es decir, MoveToState2 en realidad no cambia nada sobre MyFoo, se crea un nuevo MyFoo que es en el estado 2. De manera similar con el estado final.

Así es como funcionan las clases de cadenas en la mayoría de los lenguajes OO. Muchos lenguajes OO también están comenzando a implementar (o ya han implementado) colecciones inmutables. Una vez que tienes los bloques de construcción, es bastante sencillo crear una "entidad" inmutable completa.

0

Me sorprendió que nadie sugirió explícitamente el modelo más simple de usar .. la State Pattern

De esta manera también se puede eliminar ese método 'finalState' y sólo tiene que utilizar 'asa()'. ¿Cómo sabes qué estado final es? El patrón de memento se utiliza mejor con el patrón de Comando, y generalmente se aplica a las operaciones de GUI para implementar la función de deshacer/rehacer.

campos que representan un estado de la clase

campos que representa el estado de la objeto instanciado. Usas muchas veces definiciones incorrectas de los términos de OOP. Revisa y corrige.

Cuestiones relacionadas