Click here to Skip to main content
15,914,500 members
Articles / Programming Languages / Visual Basic
Article

Refactoring to Adaptive Object Modeling: Practical Uses

Rate me:
Please Sign up or sign in to vote.
3.90/5 (10 votes)
20 Jun 200515 min read 75.9K   158   49   18
This article will deal with how to make the AOM pattern methodology useful in actual projects.

Introduction

Adaptive Object Modeling is a relatively unrealized 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. Its 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.

Adaptive solutions offer us a way to make applications more configurable (regarding workflow) to the end users. It is not a 99% solution and, to my knowledge there is no end-to-end solution that meets all needs, simply because those needs are more directly defined by the business requirements. However, since business requirements change frequently, writing immutable code flow logic leaves very short lives for code. Even the online industry is feeling the need to configure dynamically: if you are a subscriber to most web portals like Yahoo! or MSN you have a user configurable home page where you can decide which items of interest you would like to display on your page.

Most portal technologies are indirectly pointing us to a more adaptive model, simply because they are configurable by end-users or power-users. I see adaptive technologies like Adaptive Object Modeling in the same light as a web portal: some functionality is needed to be coded by developers, like database and business logic, but where and when this logic is implemented should be (following business trends) decided upon by business experts, not developers. Some adaptive models incorporate the non-meta-data into tier models tightly coupled with tier meta-data, which is one way to do it, but I prefer to let the EUD (end user developer) have the hand in how business data is handled, and simply allow the AOM framework to give the actual implementation of when and where back to business experts (which most developers don't have the bandwidth to be).

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 how to make the AOM pattern methodology useful in actual projects. I skipped ahead a bit to write this article (relationship and interpreter articles will come later) because I saw a real lack of understanding revolving around real world applications and usage of this model. This article will deal with application, implementation and conversion techniques for current application code to the AOM Model. Don't get confused. This will not be a regurgitation of the current writings on the methodology, but (I hope) a different approach to describing the methodology intended to help build competencies in the pattern. When I am done, you may think this is not AOM at all, but what I am trying to get across is some relevant ideas that the model suggests. I will pick apart different pieces of the overall model in this article, so that I can better illustrate the different ways you might use the disparate pieces in projects.

Background

Let us first put aside some common misconceptions. First, this is not the holy grail. It is a pattern, and the usefulness of a pattern is in how it can be applied to real world coding. While the pattern may appear overly complex, we will attempt in this article to only use pieces of the puzzle in different ways, in the hope that we might shed some light on the cognizant whole.

Here we see a version of the Type Square Adaptive Object Modeling class pattern UML based on the ECOOP & OOPSLA 2001 Yoder, Balaguer, Johnson model. Notice that the Entity object accepts and has specific operations (or strategies) and attributes (or properties) are associated with it. This is not the exact UML of course, for type square, but it is an accurate representation for this article of what I would like to present. We have class types called entities, entity types that include operational strategies, and attributes as properties. We have left off entity relationships at this time, so we can better illustrate some pieces that I feel hold more value. Not that the Entity-Relationship pattern should be ignored, it is just out of scope, for the time being, of this particular article.

Image 1

How to use the code?

As we saw above in the UML, we have linked operational methods and attributes to a class, and they are not part of the class itself, but exist as component parts linked through the class EntityType. This is the most useful and interesting piece of the pattern I have found, due to its unique flexibility of design. Imagine, you build a class, then your business user tells you that need to add some more functionality to the class. Well, normally you would shake your head, and go and recompile the class code with the changes. This is costly in build time, as well you have to factor in the impact to your current design. But what if you could add any attributes and/or methods you wished without the recompile? What if you could link entire assemblies together at runtime, simply by changing some configuration data? I will show you how easy it is.

First, let's look at the most poignant aspect I found of the AOM model. We will attempt to re-write classes with immutable compiled methods into Entity and EntityType patterns, and define these same methods in another assembly. We start out with the class EmployeeJob, which has two methods DoSomeWork and GoofOff.

C#
public class EmployeeJob
{

    public EmployeeJob()
    {

    }

    public void DoSomeWork(string typeOfWork)
    {
        //some functional code here

    }

    public void GoofOff()
    {
        //some functional code here

    }
}

Let's say, we wanted this class to have four new methods: GoToLunch(string restaurant), TakeABreak(), WriteAReport(string reportName) and ClockOut(). We could add them to the class itself, but we have no way of telling when we will have to add methods again, and we also need to add these methods to a new class we will create: ExecutiveJob. We could create a parent class containing the common methods and subclass EmployeeJob and ExecutiveJob, but if the code base grows very large and we have a large variety of job types, this can become unmanageable. Let's say that, at sometime in the future fifty new job types will be added, each with its own specific needs for functionality. That would mean (at least) fifty new subclasses just like EmployeeJob and ExecutiveJob. Wow! How do we deal with all those classes. AOM can help here. With the AOM model as our base we can create virtual classes at runtime with all the necessary attributes and methods we need for each class, using configuration meta-data. Meta-data, as we know is machine understandable data that describes object states (not values). Let's look at how we start.

Let's first start by providing a way to retrieve operational data from any assembly.

Below we see an interface and a collection that will hold these interfaces. The interfaces will be a link to all the possible methods in any assembly, that exists in a class that inherits from IOperation and implements the method OperationMethod. We give OperationMethod a very generic parameter list object[] parameters, which allows us to pass arguments in any number and type to the method. This gives us the flexibility to define any method strategy desired in the implementation class. We also have a collection objects which will hold these operational strategy methods inside the specific EntityType.

Note: We might replace this later with a delegate pointer in the interface to the method on the implementation class, to better type the actual method call.

C#
public interface IOperation
{
    void OperationMethod(object[] parameters);
}

//Collection of attributes

public class OperationsCollection
{
    public void Add(IOperation obj)
    {
        //.....addition code to collection

    }

}

Our meta-data is pulled for this example from a config file (XML). Notice that each operation definition has XML attributes: name, assembly and type. The assembly XML attribute defines which assembly (or .dll) you wish to pull the method from. The type XML attribute tells us which actual class to use, that inherits from IOperation and implements the method OperationMethod. We now need to build each class in its own assembly that we want as a strategy, and implement the interface method OperationMethod. The config file excerpt below shows how we want to define the classes, and their container assemblies.

XML
 <entityOperations>
    <entityOperation name="DoSomeWork"
        assembly="OperationalStrategies"
        type="OperationalStrategies.DoSomeWork" />
    <entityOperation name="GoofOff"
        assembly="OperationalStrategies"
        type="OperationalStrategies.GoofOff" />
    <entityOperation name="GoToLunch"
        assembly="OperationalStrategies"
        type="OperationalStrategies.GoToLunch" />
    <entityOperation name="TakeABreak"
        assembly="OperationalStrategies"
        type="OperationalStrategies.TakeABreak" />
    <entityOperation name="WriteAReport"
        assembly="OperationalStrategies"
        type="OperationalStrategies.WriteAReport" />
    <entityOperation name="ClockOut"
        assembly="OperationalStrategies"
        type="OperationalStrategies.ClockOut" />
</entityOperations>

Note: The above XML is considered meta-data for this application example.

Each one of these method strategies can be added dynamically to the class type via its EntityType class at runtime.

We now need to create functional method objects inheriting from IOperation, which define exact method operations we will allow to be adapted to our entity object. Having the interface allows us to tie that interface to any class method we wish, as long as that class implements IOperation.

Note: The operational methods could be contained in other assemblies, the namespace encapsulation becomes unimportant, because you can add attributes or methods via the metadata, without concern to its source at compile time. Also the operation method interface IOperation could be changed to dynamically define strongly type parameters as well, but this will be saved for either another article or your own invention. Remember, reflection is used heavily as we will see in the factory class, and is the key to dynamic representation of contractual interfaces.

C#
public class DoSomeWork : IOperation
{
    void IOperation.OperationMethod(object[] parameters)
    {
        Console.WriteLine("..." + this.GetType().Name +
                    ".OperationMethod method called.");
        foreach(object obj in parameters)
            Console.WriteLine("... parameter Type:" +
                     obj.GetType() + " Value:" + obj);
    }
}

public class GoofOff : IOperation
{
    void IOperation.OperationMethod(object[] parameters)
    {
        Console.WriteLine("..." + this.GetType().Name +
                    ".OperationMethod method called.");
        foreach(object obj in parameters)
            Console.WriteLine("... parameter Type:" +
                      obj.GetType() + " Value:" + obj);
    }
}

//.....other methods

Now that we have built out both our meta-data and the interface links to our classes, we can define our EntityTypes, which are like templates for our different class types. The EntityType classes allow us to map groupings of types to a specific entity. EntityType is part of Entity and there is a one to one relationship. Think of entities as virtual classes, and entity types virtual container definitions for all possible attribute and operational data available to a specific entity.

Consider this example. ExecutiveJobEntityType does not exist as compiled code, but gives us a relative type template for defining an entity's relationships, methods and data. It contains mappings to a number of attributes and methods, so when we add our fifty more classes, we can now map them to a specific type, giving us a generalized template, without the need for sub classing or inheritance. The XML excerpt below shows how the relationships merge. We have attributes and methods, all tied into a nice generalized template. We have two types, based on job level, and from these types we can further define the classes, or entities.

Notice the two XML attributes in the diagram below, attributes and operations. These two attributes contain the name keys to distinguish which operations and attributes are to be associated with the entity types. This is how we link up the different classes and their assemblies, and build our 'parent' definitions. Just think of the meta-data that builds entity type as a template.

XML
<entityTypes>
  <entityType name="ExecutiveJobEntityType"
     attributes="FullName,HireDate,IsActive,JobLevel"
     operations="DoSomeWork,GoToLunch,TakeABreak,WriteAReport,ClockOut" />
 <entityType name="EmployeeJobEntityType"
     attributes="FullName,HireDate,IsActive,JobLevel"
     operations="DoSomeWork,GoToLunch,TakeABreak,WriteAReport,ClockOut,GoofOff"/>
</entityTypes>

The actual EntityType class is defined below. The class itself is considered a meta class. It basically acts as a holder for all the relationships, attributes and operational methods we want for a specific template.

C#
public abstract class EntityType
{
    private string _typeName;
    private Type _type;
    private EntityAttributeCollection _attributes =
                              new EntityAttributeCollection();
    private OperationsCollection _operations =
                              new OperationsCollection();

    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;}
    }

    public OperationsCollection Operations
    {
        get{return _operations;}
        set{_operations = value;}
    }

}

The Entity class is defined below. The class itself is considered a meta class. This is the class that virtually replaces your EmployeeJob and ExecutiveJob and all fifty class types we mentioned above. It holds a composite of the EntityType class, and has a one to one relationship with that class.

C#
public class Entity
{
    private EntityType _entityType;

    public Entity(EntityType entityType)
    {
        _entityType = entityType;
        Console.WriteLine("..." + this.GetType().Name +
                      " initialized with EntityType " +
                      _entityType.Name);

    }

    public EntityType EntityTypeOf
    {
        get{return _entityType;}
    }
}

The actual classes are not compiled, but instead exist at runtime as virtual meta-classes built from the configuration meta-data. Below we see the XML excerpt that allows us to define how to build this class. If you look at the XML, you will see a type definition, so we know from where we want to grab our particular entity definition, and entity type identifier, and two other XML attributes: extendedAttributes and extendedOperations. These two attributes lets us define specific class definitions based on the entity type template. This replaces the need for inheritance and sub classing, by allowing the meta-data to extend the entity. To the two XML attributes let us add on specific extra attributes and operational strategies (or subtract ones from the current entity, which is out of scope for this example, but perfectly viable for this model).

XML
 <entities>
    <entity name="ExecutiveJob"
        type="AOMImpl.EntityImpl.Entity"
        entityType="ExecutiveJobEntityType"
        extendedAttributes="JobLevel"
        extendedOperations="WriteAReport" />
    <entity name="EmployeeJob"
        type="AOMImpl.EntityImpl.Entity"
        entityType="EmployeeJobEntityType"
        extendedAttributes=""
        extendedOperations="WriteAReport,GoofOff" />
</entities>

The attributes for the entity types and entities work exactly the same way, as far as their grouping goes.

Below we see the definition for EntityAttribute. We see it holds data for its name, the object for the attribute or value, and its Type. This class is also a meta-class, and its actual object data can be loaded from any source, probably a database. But the definition of its type is set up in meta-data.

C#
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;}
    }
}

The meta-data from the configuration file shows us the key name (XML attribute 'name'), the type of the attribute value (XML attribute 'attributeType') and the actual object value (XML attribute attributeValue'), which is not meta-data, and should not be included in your project as such, but is done for this example.

XML
 <entityAttributes>
    <entityAttribute name="FullName"
        attributeType="System.String"
        attributeValue="(This is Not META-DATA)" />
    <entityAttribute name="JobLevel"
        attributeType="System.Int32"
        attributeValue="1" />
    <entityAttribute name="IsActive"
        attributeType="System.Boolean"
        attributeValue="True" />
    <entityAttribute name="HireDate"
        attributeType="System.DateTime"
        attributeValue="03/01/2005" />
</entityAttributes>

Now let's take a look at how the example runs, and go through the flow. When we run the example, we first see that we load up our specific entities loaded with their entity types. This is done in any order in your Interpreter pattern (for this example the order is different than is displayed) that works best to allow the dynamic creation of your classes. Our interpreter is the AOMFactory, which creates and loads our different relationships from the meta-data.

Image 2

Next we see the specific entities and their operational methods and attribute calls displayed. We do this to illustrate as a test that the expected operations and attributes are part of each class definition. Below we define the EmployeeJob class, and see the methods and attributes we defined in the meta-data for its entity type, as well as its specific methods and attributes are displayed. Notice methods WriteAReport and GoffOff are added to its method definition.

Image 3

Next we see that ExecutiveJob class, also has the methods and attributes we defined in the meta-data for its entity type, as well as its specific methods and attributes are displayed. Notice method WriteAReport is added to its method definition.

Image 4

Next we see the ContractorJob class, also the methods and attributes we defined in the meta-data for its entity type, as well as its specific methods and attributes. Since this is a contractor job type it gets only the basic methods.

Image 5

Meta-Data and Configuration

Now let's talk about who gets to configure the meta-data, and build the applications process flow. Depending on your usages for the code, you might want to allow a power-user, who has some advanced knowledge of the business processes, to modify the meta-data. However you might allow certain pieces of meta-data to be modified by ordinary users. For example, a user might have the ability to build a process flow for his piece of the application, for his particular profile. Suppose one of your business users was a manager, and he needed to build a process that allowed his subordinates to only have certain functionality, and see certain data of an application. He could be allowed to modify the meta-data for his process and build certain methods and attribute types to be displayed on a Web page. He might display data, buttons to certain functions, or other links to the background functionality of the operations, based on his settings in the meta-data.

Project Suggestions

Well, now hopefully I have explained some functional flows and usages of the AOM model, so how does this apply to your projects? The AOM model may not make sense for all projects, but it is a very interesting model nonetheless. Several design types come to mind, including a dynamic content generated web site, a process engine for approvals, etc. The first thing you need to do is to find relevant uses in your project is analyze your current structure and see if it suggests usage of the AOM model. You can do this by seeing if you have any excessive class structures, or maybe some algorithms that are duplicated in several places. Also if you have excessive subclassing, or just want to have an application that is more flexible and responsive to ever changing business requirements.

Another aspect to consider is that the competency level of your development team needs to be rather high for this model to work, and a strong design patterns methodology and mindset needs to be in place in your development group. To use this model, you need to have some knowledge of design pattern methodology, a good understanding of reflection and object typing, and a general knowledge of high level architecture and design. Remember, this is not rocket science, just a model based on reflection, so don't get intimidated. Focus on the pieces, not the whole and you should do fine.

Points of Interest

This is the fourth 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.

Other articles in this series include:

  1. TypeObject
  2. Properties
  3. Strategies
  4. Entity-Relationships and Accountability/Cardinality.
  5. Ghost Loading, Data Mapping and more...
  6. Interpreter methodologies (coming soon).
  7. Discussions on Practical Project usefulness of design.
  8. Final Discussions and MVC.

History

This is the first revision and is the fourth 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.
  • Doga Oztuzun, for his insight and sharing of his relevant project data.

    Also to anyone else I have forgotten.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Christopher G. Lasater

I am also a published author, please check out my book:
ISBN: 1-59822-031-4
Title: Design Patterns
Author:Christopher G. Lasater
More from my web site
Amazon.com


Comments and Discussions

 
GeneralRun-time performance Pin
BryFa1-May-05 2:48
BryFa1-May-05 2:48 
GeneralRe: Run-time performance Pin
Anonymous2-May-05 3:23
Anonymous2-May-05 3:23 
GeneralRe: Run-time performance Pin
BryFa2-May-05 8:13
BryFa2-May-05 8:13 
GeneralRe: Run-time performance Pin
Christopher G. Lasater3-Jun-05 9:05
Christopher G. Lasater3-Jun-05 9:05 
GeneralRe: Run-time performance Pin
Christopher G. Lasater3-Jun-05 9:19
Christopher G. Lasater3-Jun-05 9:19 
GeneralThank you Pin
UnquaLeX25-Apr-05 5:21
UnquaLeX25-Apr-05 5:21 
GeneralRe: Thank you Pin
Christopher G. Lasater25-Apr-05 6:02
Christopher G. Lasater25-Apr-05 6:02 
GeneralRe: Thank you Pin
UnquaLeX25-Apr-05 8:20
UnquaLeX25-Apr-05 8:20 
GeneralIs the complexity worth it Pin
Edwin Pajemola25-Apr-05 3:15
Edwin Pajemola25-Apr-05 3:15 
GeneralRe: Is the complexity worth it Pin
Anonymous23-Jun-05 15:48
Anonymous23-Jun-05 15:48 
GeneralVery Good, but... Pin
David Kemp20-Apr-05 5:08
David Kemp20-Apr-05 5:08 
GeneralRe: Very Good, but... Pin
Anonymous20-Apr-05 6:35
Anonymous20-Apr-05 6:35 
GeneralRe: Very Good, but... Pin
Sean McCormack20-Apr-05 10:33
Sean McCormack20-Apr-05 10:33 
GeneralRe: Very Good, but... Pin
Christopher G. Lasater20-Apr-05 11:15
Christopher G. Lasater20-Apr-05 11:15 
Good Questions all Sean.
1. Dealing with complex objects, such as entity types in a relationship, can be dealt with in a similiar matter (my article on Entity Relationships will be out later this year, when I get some more time), no matter what object you have, either primitive or a class object, is still an object. So declaring the type of the entityattribute is paramount to using non-primitives, but works the same way.
2.Model-View-Controller (MVC) is a godd subject to review, but a good example is hard to explain in a few sentences. Ok lets consider what a web form is in .Net. It is simply a page (class), with a collection of controls in it. Each control is a class. So it stands to reason that these controls can be created and added to the page at runtime. There are several models of this type of code, including struts and any controller-view pattern for dynamic display of a user control. I am working on a example solution for this very purpose, for the next article.
3. I am a little less familiar with all the AOP methodologies than I would like to be, but the concept is frightnely similiar to AOM. Both use reflection heavily and configuration data or meta-data. I think AOP is a more developed and specific concept. I may look into what is offered, like aspectJ and Jboss AOP in the near future.
4. I didn't cover sequence in the article, but a very good point to make. You could easily chain the processes in your meta-data, mabey even having a cause-and-effect (or transactional) sequence. Chain of Responsibility pattern might be an option, using the meta-data to link the different processes at run time.
5. This also affects how you deal with the other situation. If you need to link some processes or pass data between them, you need to code for that in your interfaces.You might have to pass in a referenced object or pass back generic or wrapper objects holding data.
6.There are a lot of pattern methodologies out there that are being formed, that will take a while to see thier direction, but are a lot like the AOM model or vica-versa. AOM only states one way or aspect of how to establish loose cohesion between code bases and define a flow of processes, as opposed to the traditional static ones. I would not think that AOM is the only way to do something, nor necessarily the right one. For me, personally, it is a great way to get started on the path to understanding how a 'thinking machine' might code. It (and patterns like it)preserves flexibility in the process flow and allows interpreters to manage this flow, which is a 'better' way for machines to deal with people, by interpreting thier ever changing needs directly, instead of staticly. I think that the programmers of the future will be a lot smarter design wise, and a lot dumber process wise, simply because they can leave that up to business 'power users' who manipulate the code bases they create. Business is looking for a better reflective model as well, that allows business owners (owners of specific aspects of a business) to install and configure components together to make a whole, instead of relying on developers to create whole systems based on requirements. Computers should be smart enough (meaning they are designed to be intuitive enough) to help average BO's to decide what thier business process flow is and to help them make changes to that flow based on thier needs.
7. Please expand this question....I didn't get your entire meaning, sorry.

I am glad you got something out of the articles. They are crude examples at best, but articles like them got me excited to, so I am doing my best to regurgitate what I learned to the community in return. More to come....
GeneralRe: Very Good, but... Pin
Edwin Pajemola25-Apr-05 3:26
Edwin Pajemola25-Apr-05 3:26 
GeneralRe: Very Good, but... Pin
Christopher G. Lasater25-Apr-05 4:13
Christopher G. Lasater25-Apr-05 4:13 
GeneralRe: Very Good, but... Pin
Christopher G. Lasater17-May-05 9:10
Christopher G. Lasater17-May-05 9:10 
GeneralRe: Very Good, but... Pin
Christopher G. Lasater17-May-05 9:07
Christopher G. Lasater17-May-05 9:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.