Autómatas celulares, Aplicación WinCA IV
Una vez revisado el funcionamiento de la aplicación WinCA, dedicada a los autómatas celulares, vamos a ver cómo está organizado el código fuente de la misma. En este artículo voy a explicar las propiedades de los estados de las celdas, y como se pueden extender para añadir nuevas funcionalidades implementando nuevas clases con los interfaces correspondientes.
Aquí puedes encontrar el primer artículo de la serie sobre la aplicación WinCA.
En este enlace puedes descargar los ejecutables de la aplicación WinCA, y en este otro puedes descargar el código fuente de la solución WinCA, escrita en csharp con Visual Studio 2015.
Propiedades
Los interfaces y las clases con las que se implementan las propiedades de los estados de las celdas están definidas en la librería de clases CommonObjects, en los espacios de nombres Interfaces y Data. El interfaz IVariantValue se utiliza para implementar los valores de las propiedades, de manera que se puedan utilizar indiferentemente con cualquiera de los tipos de datos int, double, bool, string o Color.
public interface IVariantValue
{
bool Mutable { get; }
int AsInt { get; set; }
double AsDouble { get; set; }
Color AsColor { get; set; }
string AsString { get; set; }
bool AsBool { get; set; }
object AsObject { get; set; }
Type NativeType { get; }
IVariantValue FromObject(object value);
IVariantValue ConvertFrom(IVariantValue value);
IVariantValue Clone();
}
Este interfaz define las siguientes propiedades y funciones:
- Mutable: Devuelve el valor true si está permitido cambiar el valor una vez creada la clase mediante las propiedades As<tipo de datos>.
- AsInt, AsDouble, AsColor, AsString, AsBool: Devuelven el valor convertido al tipo de datos correspondiente o lo establecen a partir de un objeto del tipo correspondiente.
- AsObject: Devuelve o establece el valor con el tipo object genérico.
- NativeType: Devuelve el tipo de datos con el que se creó originalmente el objeto.
- FromObject: Devuelve un nuevo objeto IVariantValue creado a partir del objeto pasado como parámetro. Este objeto debe tener uno de los tipos indicado anteriormente.
- ConvertFrom: Devuelve un nuevo objeto IVariantValue a partir del que se le pasa como parámetro pero con el tipo convertido al tipo nativo de la clase.
- Clone: Devuelve un nuevo objeto IVariantValue que es una copia exacta del actual.
Este interfaz lo implementa la clase VariantValue, en el espacio de nombres Data. Se trata de una clase abstracta que sirve como base para otras clases especializadas en un tipo de valor determinado. La idea de tener estas clases especializadas es la de optimizar algunas de las operaciones sin tener que realizar conversiones de tipo. Estas clases especializadas son IntVariantValue, DoubleVariantValue, ColorVariantValue, StringVariantValue y BoolVariantValue.
Las propiedades implementan el interfaz IObjectProperty, definido de la siguiente manera:
public interface IObjectProperty
{
string Name { get; set; }
IVariantValue Value { get; }
Type DefaultValueType { get; set; }
IVariantValue CreateValue(object value);
}
Name permite obtener o cambiar el nombre de la propiedad, mientras que Value devuelve su valor. DefaultValueType se utiliza para obtener o modificar el tipo de datos por defecto y CreateValue permite cambiar el valor y el tipo por defecto a partir del objeto pasado como parámetro.
Las propiedades también implementan los interfaces estándar IEquatable e IComparable. El dato que se utiliza para comparar es el nombre de la propiedad. Básicamente se utilizan para gestionar las listas de propiedades.
Existen dos tipos de propiedades, las variables, a las que se les puede cambiar el valor durante la ejecución del autómata, y las constantes, que no permiten dicho cambio y generan una excepción si se intenta. Están implementadas en las clases Variable y Constant, del espacio de nombres Data.
Para administrar un conjunto de propiedades, se debe implementar el interfaz IPropertyProvider, definido en el espacio de nombres Interfaces:
public interface IPropertyProvider
{
string UID { get; }
string Name { get; set; }
IEnumerable<IObjectProperty> Properties { get; }
Type DefaultPropertyType { get; set; }
IObjectProperty GetProperty(string name);
IObjectProperty GetProperty(int index);
int IndexOf(IObjectProperty p);
int IndexOf(string name);
bool ExistsProperty(string name);
void AddProperty(IObjectProperty cons);
void AddProperties(IEnumerable<IObjectProperty> ps);
void RemoveProperty(string name);
void RemoveProperty(IObjectProperty p);
void ChangeProperty(string name, IObjectProperty p);
IObjectProperty CreateProperty(string name, object value);
}
Los miembros del interfaz se utilizan de la siguiente manera:
- UID: Devuelve un identificador único para el conjunto de propiedades.
- Name: Devuelve o establece el nombre del conjunto de propiedades.
- Properties: Se utiliza para enumerar todas las propiedades del conjunto.
- DefaultPropertyType: Devuelve o establece el tipo por defecto de las nuevas propiedades creadas por el objeto.
- GetProperty: Devuelve una propiedad a partir de su nombre o su índice dentro del conjunto.
- ExistsProperty: Devuelve true si existe una propiedad con el nombre dado.
- AddProperty: Añade una nueva propiedad al conjunto.
- AddProperties: Añade una lista de propiedades al conjunto.
- RemoveProperty: Elimina una propiedad del conjunto, identificada por su nombre o por la propiedad misma.
- ChangeProperty: Cambia la propiedad con el nombre dado por una nueva propiedad.
- CreateProperty: Genera una nueva propiedad con el nombre y el valor proporcionados.
Existe una implementación por defecto de este interfaz en la clase BasicPropertyProvider, en el espacio de nombres Data.
En la aplicación WinCA se define el proveedor de propiedades por defecto en el archivo de configuración, en la sección appSettings, con la clave defaultpropertyProvider. Esta clase se utiliza en el formulario frmProperties, del espacio de nombres Forms. Este formulario utiliza el control VariantValueListEditor, definido en el espacio de nombres Controls de la aplicación WinCA, para gestionar las listas de propiedades variables y constantes.
El formulario frmProperties implementa el interfaz IPropertyManager, definido en el espacio de nombres Interfaces de la aplicación WinCA de la siguiente manera:
public interface IPropertyManager
{
event PropertyChangeEventHandler PropertyChanged;
IPropertyProvider ConstantProvider { get; set; }
IPropertyProvider VariableProvider { get; set; }
IMainForm MainForm { get; set; }
}
Este interfaz permite enlazar este editor de propiedades con otros formularios de la aplicación, como el editor de estados. El evento PropertyChanged se suscribe para recibir notificaciones cuando el conjunto de propiedades cambia, porque se añadan o eliminen propiedades o se cambie el nombre o el tipo de alguna de ellas, según se indica con la enumeración Change.
Mediante las propiedades ConstantProvider y VariableProvider se obtienen los objetos IPropertyProvider encargados de gestionar las listas de constantes y variables.
Por último, MainForm permite la interacción del formulario con el formulario principal de la aplicación, en forma de interfaz IMainForm, implementado en el formulario MainForm y definido de la siguiente manera:
public interface IMainForm
{
event PropertyManagerChangedEventHandler OnPropertyManagerChanged;
event StateManagerChangedEventHandler OnStateManagerChanged;
IEnumerable<IPropertyManager> PropertyManagers { get; }
IEnumerable<ICAStateManager> StateManagers { get; }
IPropertyManager CreatePropertyManager(PropertySerializationContainer pms,
string filename);
ICAStateManager CreateStateManager(StateSerializationContainer sms,
string filename);
ITransitionManager CreateTransitionManager(ICAStateManager mgr,
string filename);
ICAManager CreateCAManger(ICAStateManager mgr);
ICAManager CreateCAManger(ICANetwork ca, string filename);
}
Este interfaz permite suscribirse al evento OnPropertyManagerChanged para recibir notificaciones cuando se cambia alguna de las propiedades, y enumera los objetos IPropertyManager que se encuentran abiertos en un momento dado con la propiedad PropertyManagers.
La función CreatePropertyManager se utiliza para crear un nuevo objeto IPropertyManager, que será un formulario frmProperties, a menos que se modifique la implementación. Como parámetro se puede pasar null, para crear un editor vacío, o bien un objeto PropertySerializacionContainer para recuperar un conjunto de propiedades almacenado en un archivo. Se trata de una clase simple, cuya única misión es permitir la serialización del conjunto de propiedades, definida en el espacio de nombres Utils de la aplicación WinCA de la siguiente manera:
public class PropertySerializationContainer
{
public PropertySerializationContainer()
{
}
public IPropertyProvider ConstantProvider { get; set; }
public IPropertyProvider VariableProvider { get; set; }
}
El resto de miembros del interfaz se utilizan con el resto de editores y los veremos en sucesivos artículos. En el próximo artículo explicaré cómo se implementan los estados de las celdas del autómata.