LasaterConsulting.com

Design Patterns
Type-Object | Properties | Strategy | Entity Relationship | Interpreter | Ghost Loading, Data Mapping... | Project Usage | AOM UI

Refactoring to Adaptive Object Modeling: Property (Attribute)

Introduction

Adaptive Object Modeling is a relatively new concept in object oriented design that has found some roots in advanced development processes. It allows that applications are in continual flux (or their requirements are) from adjustments to business rules, environments and user requirements. It's precepts are that using metadata for business objects, rules and process flows, instead of hard coded, static method code, makes the application more flexible to user/client needs. The AOM design model also requires that certain domain 'facts' are maintained, i.e. that there are controlled interpretations of the effects of the 'immediate' changes from user-generated metadata.

To better understand and practice the techniques of AOM design, I am writing this and several other articles that explain the usage and conversion (or refactoring effort) from a static code model to AOM design.

This article will deal with Property methodology of Adaptive Object Modeling. Property pattern methodology maintains that the attributes of a class should be held as a collection of properties, as opposed to single instance variables, which can changed at runtime.

BackGround

Using a Property design method is an interesting way to extend the configuration possibilities of simple class/object methodology. It gives a way to define a class's attributes dynamically, or at runtime, from a database, configuration file or user interface. Virtually any meta-data source can define the attributes for a given AOM class structure.

Here we see the exact Adaptive Object Modeling UML for the Property class. Notice that the Entity object accepts and has specific attributes associated with it from Property. The value of the attribute could be a primitive type, like a string or boolean, or another entity. If the property attribute contains an entity object this is said to become an association, and the encapsulated entity should know it's cardinality. We will for this exercise only deal with primitive types, not associations, which will be part of another article.

How to use the code

We start this refactoring example where we left off from our other example article TypeObject. We still have the same Entity and EntityTypes, and now we would like to dynamically add some attributes or Properties. To accomplish this we need to create a class to hold our dynamic attributes that are loaded during runtime. This takes the form of a simple container (or entity-attribute type) object that holds the name, object value and type of the attribute. This is loaded with metadata at runtime for the specific object attribute that we wish to implement. Notice we have added also a collection object EntityAttributeCollection, which contains the shared attributes between the entity and the entity type.

NOTE: The 'value' accessor is added in this example, although not meta-data, it serves to illustrate for our console test the way the attributes are dynamically created from runtime data.

                
     public class EntityAttribute
        {
            private string _attributeName;
            private object _attributeObject;
            private Type _attributeType;
                    
            public EntityAttribute(string name, object obj, Type type)
            {
                _attributeName = name;
                _attributeObject = obj;
                _attributeType = type;    
            }   
                    
            public string Name
            {
                get{return _attributeName;}
                set{_attributeName = value;}                    
            }
                    
            public object Value
            {
                get{return _attributeObject;}
                set{_attributeObject = value;}                    
            }
                    
            public Type TypeOf
            {
                get{return _attributeType;}
                set{_attributeType = value;}                    
            }
        }


        
        //Collection of attributes

        public class EntityAttributeCollection
        {
            public void Add(EntityAttribute obj)
            {
                //.....addition code to collection
            
            }
        
        }

Here we see that the EntityType object from our last example has an added parameter of type EntityAttributeCollection. This attribute collection will allow the Entity object to have dynamically loaded meta-data driven parameters associated with it at runtime.

                
        public abstract class EntityType
        {                    
            private string _typeName;
            private Type _type;
            private EntityAttributeCollection _attributes = new EntityAttributeCollection();
            
            public EntityType(string name, Type type)
            {
                _typeName = name;            
                _type = type;    
            }   
                    
            public string Name
            {
                get{return _typeName;}
                set{_typeName = value;}                    
            }        
                    
            public Type TypeOf
            {
                get{return _type;}
                set{_type = value;}                    
            }
                    
            public EntityAttributeCollection Attributes
            {
                get{return _attributes;}
                set{_attributes = value;}                    
            }
                    
        }
            

We now are ready to focus on the AOMFactory class, which is a static factory implementation loosely based on Deyan Petrov's DataSourceFactory. The factory is where we actually will load our runtime data for this example and is considered the Interpreter model of the AOM pattern. Our example code will use an xml config file for the actual meta-data, but in actual project code, as I stated above a variety of sources are available, not in the least, the client or user interface. Remember, this factory class is only for this example, and while I would recommend a factory or builder pattern for this piece, it is up to you the developer to find the suitable method for loading your classes from meta-data.

The first piece of data we get after this revision to our TypeObject example is the meta-data for the entityattribute. We will use this data to build and define all the possible types of attributes we can load to our entity types, making them available as needed to specific entities. We are pulling in name, full type name (and value, which is not meta-data).

                
        string name = Convert.ToString(hash["name"]);
        //the name of this attribute
        if(name == null || name == string.Empty)
            throw new FactoryException("No attribute name specified.");
        
        //get the attribute type
        string strAttributeType = Convert.ToString(hash["attributeType"]);
        if(strAttributeType == null || strAttributeType == string.Empty)
            throw new FactoryException("No Attribute Type specified for attribute " + name);
        //get the type for a strongly typed parameter
        Type attributeType = Type.GetType(strAttributeType);
        if(attributeType == null)
            throw new FactoryException("Could not load class Type for type " + strAttributeType + " for  attribute " + name);
                        
        object attributeValue = Convert.ChangeType(hash["attributeValue"],attributeType);
                                

The meta-data from the config file appears thus:

 <entityAttributes>
        <entityAttribute name="Attribute1" 
            attributeType="System.String" 
            attributeValue="This is a Adaptive Object Model Attribute" />
        <entityAttribute name="Attribute2" 
            attributeType="System.Int32" 
            attributeValue="1" />
        <entityAttribute name="Attribute3" 
            attributeType="System.Boolean" 
            attributeValue="True" />
        <entityAttribute name="Attribute4" 
            attributeType="System.DateTime" 
            attributeValue="03/01/2005" />
    </entityAttributes>

Next we see we check to see if the hashtable that will hold our EntityAttribute classes exists and contains the current data. If not we will build the new attribute passing in the appropriate parameters.

                
        if(_entityAttributes == null)
            _entityAttributes = new Hashtable();
        
        EntityAttribute attribute = new EntityAttribute(name,attributeValue,attributeType);
    
        if(!_entityAttributes.Contains(name))
            _entityAttributes.Add(name,attribute);

Next we are going to load the actual EntityType class with the attributes specified in the meta-data from the config file. We parse a comma delimited string to get the various attribute names for each EntityType, and load each type.

 
        //get the entity type attributes
        string[] attributes = Convert.ToString(hash["attributes"]).Split(new char[]{','});
        
        .......
            
        EntityType entityType = (EntityType)Activator.CreateInstance( entityTypeOf,new object[]{name,entityTypeOf});
                
        foreach(string attribute in attributes)
         if(!entityType.Attributes.Contains((EntityAttribute)_entityAttributes[attribute]))
            entityType.Attributes.Add((EntityAttribute)_entityAttributes[attribute]);
    

The meta-data from the config file appears as below. Notice the attributes xml node. This is where we put all the possible attribute types by name for each EntityType instance. The attribute names are comma delimited.

 
    <entityTypes>
        <entityType name="ExecutiveJobEntityType" 
            type="Properties.ImplClasses.ExecutiveJobEntityType" 
            attributes="Attribute1,Attribute3" />
        <entityType name="EmployeeJobEntityType" 
            type="Properties.ImplClasses.EmployeeJobEntityType" 
            attributes="Attribute2,Attribute4" />
    </entityTypes>    

We now are at a point where we can test our code.

Here we see that the entity is first established from the entity type and it's attributes have been loaded.

Expanding the Example

How can we expand this example to functional code? Next we need to add operational methods in a collection object as an instance on EntityType. Next we could apply relationship and business rules objects, as well as strategy classes. These items we will cover in the next article. What can we do with this example? Lets say you wanted to allow power users to change the attributes for different class types in your AOM model. A better example would be allowing a user to dynamically configure his default page for a website. Each object attribute that is displayed could be held in meta-data and changed as the client saw fit. We will cover more practical project uses in a later article.

Points of Interest

This is the first installment in the series I am writing on real world adaptive object modeling. All examples and the bulk of this article are taken from my professional experience as an architect. The examples given are templates only, and the designer must keep in mind that they are the ones who must decide where different patterns, if any, may be best used in their code.

Deciding to perform a refactoring effort from existing code to a pattern or enhanced design model must be weighed on the necessity and need of the code itself. Patterns and Adaptive Models are only design templates, helpers to accommodate better overall design. I might stress that making the effort to use advanced design methodologies will strengthen your overall design ability, but like your basic coding skills, it is something learned and cultivated.

Related Articles

Other articles in this series include:

  1. Type-Object
  2. Properties
  3. Strategies
  4. Entity-Relationships and Accountability/Cardinality
  5. Ghost Loading, Data Mapping...
  6. Interpreter methodologies
  7. Discussions on Practical Project usefulness of design.
  8. Discussions on the AOM framework, UI, and Advanced Concepts

History

This is the second revision and is the first installment in a series.

Credits

Thanks to: Joe Yoder, Ralph Johnson, for their various articles on the AOM pattern, Martin Fowler for his interest in my articles and his work on the Accountability pattern, and Doga Oztuzun, for his insight and sharing of his relevant project data. Also to anyone else I have forgotten.

| Make a Donation to Help Build/Maintain our site! |©2004 Lasater Consulting

1