none
Question Rgarding a "Best Practice" Approach RRS feed

  • Question

  • I am working on a very large tiered application.  In my business tier, I have a library for all my business objects, and a library for facade objects to provide access to functions on my business objects.  Because of this design, I want my business object classes to be definitions (constructors, properties, events) only, and any actions (adding, updating, deleteing, etc) to be done through the facades, where I can concentrate my business logic.

    Most of my business objects have a static event called "Action" which is to be fired whenever an object is added, edited, deleted.  The event is static, because I want controls to be able to subscribe to the event without an instance (i.e. a listbox can update itself when a new class x object is added).

    Due to the fact that the events needs to actually be fired from the facades, because that's where the action actually happens, what is the best way to handle this?  What I have done, is created a "IBusinessObjectEvent" interface that defines one method "Fire".  Any business object that implements this interface defines the Fire method as simply a call to my private "OnX" event firer.  Then, in my facade (while adding for example) I cast the object I am adding as a IBusinessObjectEvent and call the Fire method.  Is there a better way to do this?  This method works, but I have this nagging feeling that I may as well of just made my "OnX" method public.

    Thanks,
    Scott
    Tuesday, September 4, 2007 2:40 PM

Answers

  • Hammy,

     

    Correct me if I'm wrong but it sounds as though you have a set of business entities (domain model) that require persistence - CRUD operations, you have decided to place this responsiblity externally from the business entity classes inside helper classes (using the visitor pattern) this functionalityis then contained in a facade that is exposed to the outside world.

     

    If this is the case I then ask why would you want to put an event on the business classes to represent a persistence change? Why not place this on the persistence layer and have the facade capture this and then re-broadcast as another event?

     

    Also some people will say that placing the persistence of the business classes outside of the class implementation makes them 'domain anaemic', and does not implement the unit of work pattern.

    I personally prefer the method you have outlined above as I see persistence as more generally 'everyday' kind of business requirement that can be viewed as a infrastracture requirement for business classes.

     

    HTH

     

    Ollie Riches

     

    Wednesday, September 5, 2007 8:55 AM
  • Hi hammy,

     

    No your not using the Visitor pattern here, your using the Model View Presenter pattern where you raise an event to indicate to your views (controls) to update themselves, very clever that is. My original assumptions were wrong, I though you meant you have seperated out all an objects methods from it's data, rather that just Add, Update and Delete, etc methods.

     

    I think Ollie was suggesting something along this line... which does seem a reasonable alternative.

     

    public class CustomerFacade
    {

    public bool AddCompany(Company company)
    {
    // add the company to the database by calling Datalayer here

    // if the insert was successful, fire comapny add event
    if (success)
    {
    //fire a event in here
    RaiseEvent OnAddCompanyAction()
    }
    }

    }

     

    ....and then with your control handle that event like this.....

     

    public class CompanyListBox : ObjectListBox<Company>
    {

    public CompanyListBox()
    {
    CompanyFacade.OnAddCompanyAction += new EventHandler<BusinessObjectActionEventHandler> (ObjectAction);
    }
    }
     
     
    Hopefully that was what Ollie was suggesting.
    Wednesday, September 5, 2007 4:38 PM

All replies

  • Hey hammy,

     

    Interesting. I'm not 100% behind the idea of seperating the data (in the business object) and the methods that act on that data (in the facades) seperate, however, I'm basing that on three paragraphs of text so you know, and besides it's whats what you have and how you want to work it.

     

    I think your doing the correct thing with implementing the IBusinessObjectEvent interface. Doing this will mean any business objects you create can subscribe to this "Action" event / "Fire" method approach, regardless of the type of Business Object, might not even be a Business Object.

     

    If you didn't use Interfaces the alternative would be to derive all business types (now and in the future) from one main base class that implemented a default "Fire" method that, like you say, you'd make public.

     

    I was reading this book the other day on component orientated development and it stated that you should work towards using interfaces more while keeping class inheritance shallow. Thats not the correct words, can't find the exact text, but it was completely for the interface approach.

     

    I don't think there is a better way to do it.

    Tuesday, September 4, 2007 4:51 PM
  • Thanks for the feedback!

    I am realizing that if your business objects have events (static or instance), there is a drawback to using facades due to the access to the method that fires the event.  However, I think the benefits of the facades in acting removing the complexities of business rules from the objects themselves, and the GUI and acting as a "meedium" between the two, are still pretty big.

    However, that's why I am trying to figure out a good way of handling the event shortcoming.
    Tuesday, September 4, 2007 5:09 PM
  • Hammy,

     

    Correct me if I'm wrong but it sounds as though you have a set of business entities (domain model) that require persistence - CRUD operations, you have decided to place this responsiblity externally from the business entity classes inside helper classes (using the visitor pattern) this functionalityis then contained in a facade that is exposed to the outside world.

     

    If this is the case I then ask why would you want to put an event on the business classes to represent a persistence change? Why not place this on the persistence layer and have the facade capture this and then re-broadcast as another event?

     

    Also some people will say that placing the persistence of the business classes outside of the class implementation makes them 'domain anaemic', and does not implement the unit of work pattern.

    I personally prefer the method you have outlined above as I see persistence as more generally 'everyday' kind of business requirement that can be viewed as a infrastracture requirement for business classes.

     

    HTH

     

    Ollie Riches

     

    Wednesday, September 5, 2007 8:55 AM
  • Your assumptions are correct.  However, I don't know that I am using the visitor pattern (though it is very likely I am, and not realizing it).  Let me lay it out exactly....

    Business Layer:

    Business Objects...

    Code Snippet

    interface IBusinessObjectAction
    {
    void Fire(object sender, BusinessObjectActionEventArgs args)
    // note: BusinessObjectActionEventArgs has a property that defines the action type (add, edit, delete)
    }

    public sealed class Company : IBusinessObjectAction
    {
    // Events
    private static event EventHandler<BusinessObjectActionEventArgs> _companyAction;

    public static event EventHandler<BusinessObjectActionEventArgs> CompanyAction
    {
    add { Company._companyAction += value; }
    remove { Company._companyAction -= value; }
    }

    private void OnCompanyAction(object sender, BusinessObjectActionEventArgs e)
    {
    if (Company._companyAction != null)
    Company._companyAction(sender, e);
    }

    // Constructors, Properties go here

    // IBusinessObjectAction implentation
    public void Fire(object sender, BusinessObjectActionEventArgs args)
    {
    OnCompanyAction(sender, args)
    }
    }

    I have the same thing for Contacts, Properties that a company owns, etc

    Facade Objects...

    public class CustomerFacade
    {
    public bool AddCompany(Company company)
    {
    // add the company to the database by calling Datalayer here

    // if the insert was successful, fire comapny add event
    if (success)
    {
    IBusinessObjectAction item = company as IBusinessObjectAction;

    item.Fire(company, new BusinessObjectActionEventArgs(BusinessObjectActionType.Added);
    }
    }

    // similar code for update and delete methods in the facade

    public bool AddContact(Contact contact)
    {
    // same as above
    }
    }

    Interface Layer:

    Here I have built a generic user control that has Add, Remove, ObjectAction Event handler, etc methods....

    Code Snippet

    public abstract class ObjectListBox<T> : ListBox
    {
    // contructors, properties, blah, blah

    public void Add(T item)
    {
    // add item to my list
    }

    public void Remove(T item)
    {
    // remove item from my list
    }

    internal void ObjectAction(object sender, BusinessObjectActionEventArgs e)
    {
    if (e.Action type == BusinessObjectActionType.Added)
    Add((T)sender);

    // if edit, find correct item and replace it with the new version
    // if delete, remove the item
    }
    }

    Now I have concrete implentations, and these concrete implementations subscribe to my business object events

    Code Snippet

    public class CompanyListBox : ObjectListBox<Company>
    {
    public CompanyListBox()
    {
    Company.CompanyAction += new EventHandler<BusinessObjectActionEventHandler> (ObjectAction);
    }
    }


    Now, lets say a user opens up a data entry form to add a new company.  They click 'Save', which then creates an instance of a customer facade, and then calls the AddCompany() method.  Which in turn fires the event that a company has been added.  All company lists the user has open (in other forms for example) are subscribed to this event, and they add the new company to themselves.  Down the road, the back end is actually going to be stored on a server, and these events are going to be fired via remoting, allowing multiple users to update their company lists when one user adds a new company.

    That's it in a very quick nutshell.  Going back to your post, I am not sure if the visitor pattern is actually implemeted in that.  However, you are suggesting I strip the event out of my business obects completely, and move them to my facades?  I would define the CompanyAction event in the facade, fire it from the facade, and subscribe to it with my listbox through the facade?  Or, after seeing it are you going "My goodness no", and thinking I need an entire relook at my flow ?

    I'll also be honest with you, I don't see a "persistence layer" in this setup that needs to first capture the event, to have the facade rebroadcast it.  Then again, I'm not sure I'm handling this correctly, hence my post
    Wednesday, September 5, 2007 2:24 PM
  • Hi hammy,

     

    No your not using the Visitor pattern here, your using the Model View Presenter pattern where you raise an event to indicate to your views (controls) to update themselves, very clever that is. My original assumptions were wrong, I though you meant you have seperated out all an objects methods from it's data, rather that just Add, Update and Delete, etc methods.

     

    I think Ollie was suggesting something along this line... which does seem a reasonable alternative.

     

    public class CustomerFacade
    {

    public bool AddCompany(Company company)
    {
    // add the company to the database by calling Datalayer here

    // if the insert was successful, fire comapny add event
    if (success)
    {
    //fire a event in here
    RaiseEvent OnAddCompanyAction()
    }
    }

    }

     

    ....and then with your control handle that event like this.....

     

    public class CompanyListBox : ObjectListBox<Company>
    {

    public CompanyListBox()
    {
    CompanyFacade.OnAddCompanyAction += new EventHandler<BusinessObjectActionEventHandler> (ObjectAction);
    }
    }
     
     
    Hopefully that was what Ollie was suggesting.
    Wednesday, September 5, 2007 4:38 PM
  • Thanks again for your feedback!  You wrote....


    public class CustomerFacade
    {

    public bool AddCompany(Company company)
    {
    // add the company to the database by calling Datalayer here

    // if the insert was successful, fire comapny add event
    if (success)
    {
    //fire a event in here
    RaiseEvent OnAddCompanyAction()
    }
    }

    }



    You've lost me here.  Where are OnAddCompanyAction() and the underlying event defined?  RaiseEvent....does c# have this, thought that was only VB.NET.  I have never taken any coarses or anything, so teaching myself via books, here, etc I sometimes lose intent in the technical jargon that I never really learned.



    Are you saying?...



    public class CustomerFacade
    {

    public static event EventHandler<BusinessObjectActionEventArgs> OnCompanyAction;

    private void OnCompanyAction(object sender, BusinessObjectEventArgs e)
    {
    if (CustomerFacade.OnCompanyAction !=  null)
    CustomerFacade.OnCompanyAction(sender, e);
    }

    public bool AddCompany(Company company)
    {
    // add the company to the database by calling Datalayer here

    // if the insert was successful, fire comapny add event
    if (success)
    {
    //fire a event in here
    OnCompanyAction(company, new BusinessObjectActionEventArgs(BusinessObjectActionType.Added));
    }
    }

    }

    Wednesday, September 5, 2007 5:16 PM
  • Hi Derek,

     

    yes that is what I am suggesting and yes I suppose this is basic implementation of the MVP pattern which is good Smile

     

    When I mentioned the visitor pattern I meant that seperating of the algorithm from the classes is an implementation of the pattern, the obvious advantage of this is the ability to add new algorthims without change the class definition.

     

    HTH

     

    Ollie Riches

    Wednesday, September 5, 2007 5:23 PM
  • Hammy,

     

    That is what I am saying Smile

     

    Ollie Riches

     

    Wednesday, September 5, 2007 5:25 PM
  • hey hammy,

     

    Yes thats it, I've got my VB head on today. Sorry to confuse you like that, I just wanted to identify the point where the event was raised.

     

    Ollie, that was a nice idea you had, you imagined that one out very well without seeing the code.

     

    Got to say this post was a refreshing change from the usual "how to I" and "how to fix" post that usually appears in the forums. Here's to architecture.

    Wednesday, September 5, 2007 6:09 PM
  • Thank you both for your feedback.  I think I am going to go ahead and move the event declarations from my business objects to my facades.  The more I think about it, the more it alleviates that nagging "something doesn't feel right" that has been sticking in my gut.

    My original thought in putting them in the business object class was that they belong to that class.  However, after thinking about it in terms of your suggestions, they really are events describing actions takling place in the facade....not the business object, so having them in the facade make perfect sense.  It also allows me to remove what was nagging me as a "patchwork" interface, simplifying desgin somewhat.

    Scott
    Wednesday, September 5, 2007 6:51 PM