Skip to content

0027: Design patterns in OLGAtherer – brief

25/12/2010

Hello there!

I’ve changed OLGAtherer structutre recently. To be specific, I’ve introduced Command pattern and underscored (played up? – I don’t know correct word) MVC pattern that had been already implemented. First, I’d like to start with MVC. It isn’t design pattern, but rather architectural pattern, due to it’s purpose – it describes structure of the whole program, not only one piece of it. There are many kinds of MVC, many different implementations and “subdesigns”. I chose one that is depicted below:

I can only imagine how many mistakes I’ve made while drawing this, but I hope that you can see what I wanted to show. There are three parts that application has been splitted to.

Controller is the main (“core”) part of it and it is responsible for any action that is taken (for now it’s OLGAtherer.Controller executable). When program starts it instantiates windows, displays them, hides when necessary, and, what is most important, listens for messages from them (events). I think that is good, because when I will try to design new user interface (using WPF), I will need just to change View library, and rest of the application will be intact (I hope). For now Controller isn’t necessary, I think – now structure of the OLGAtherer would be described as MV only. It’s separated only for the future use. Controller would be good if application have a state (like drawing programs for example). I don’t plan that feature in OLGAtherer, but who knows? For sure Controller isn’t wrong here and I think that it will stay.

View is the part of the program that is contained in OLGAtherer.GUI.Forms. It is a set of the windows to be displayed to the user. Main goal that I aim to is that windows should contain no logic code. I mean – when user clicks a button, there is only event rising and rest of the action is executed elsewhere (controller or model) – Command pattern to the rescue πŸ™‚ (will be described later). View also listens from the Model. When model is changed, it rises OnChanged event and View takes an action as a reply (not implemented yet, but it probably will notice user that data model has been changed – somehow, I don’t know the way yet).

Model is contained in the OLGAtherer.Model, and has been described many times since now. Shortly, it is responsible for exchange data with database.

This short description above shows that separation of the application allows us to treat all three parts independently and changes in one of the part don’t affect rest of the parts. This is great idea and I very glad that I learned about it, implemented it and, hopefully, will take benefit from it.

In this post I’d like also to describe Command pattern. Here (http://dofactory.com/Patterns/PatternCommand.aspx) is a nice UML diagram of the pattern and brief description of it. I think that it’s pointless to repeat it. Instead, I will show code that I put into OLGAtherer to implement this pattern. Let’s start from the ICommand interface:

public interface ICommand
    {
        void Execute();
    }

Simple, isn’t it? πŸ™‚ This interface will be implemented by any command that user can choose. For example:

class CommandAddNewItem : ICommand 
    {
	#region Initialization of the command
        private Book book;
        private BookCollection bookCollection;

        public CommandAddNewItem(BookCollection books, Book book)
        {
            this.bookCollection = books;
            this.book = book;
        }
	#endregion

        public void Execute()
        {
            this.bookCollection.Add(new Book[] { book });
        }        
    }

Take a look at the command above. It will be used when user click Add New Item button on the main window. Command will be instantiated then with the current book collection and book item to be add. Execute method only adds new book to the collection. At the first glance it looks like more complicated way to do something. Advantages of this approach will be shown later.

In the main window’s code I added new lines:

#region Command pattern

        public delegate void CommandSelectedHook(ICommand command);
        public event CommandSelectedHook CommandSelected;

        private void tsbNewItem_Click(object sender, EventArgs e)
        {
            RaiseCommandSelected(new CommandAddNewItem(this.collection, new Book()));
        }

        private void RaiseCommandSelected(ICommand command)
        {
            if (this.CommandSelected != null)
                this.CommandSelected(command);
        }
#endregion

As you can see there is a delegate and event that are responsible for notifying clients that new command has been picked by user. Method called tsbNewItem_Click() invokes common method that raises the event. For now there is new Book() as a parameter, but of course there will be a book selected at the moment. This CommandSelected event is subscribed by a controller right after MainWindow is instantiated. This code do this:

form.CommandSelected += new MainWindow.CommandSelectedHook(form_CommandSelected);

void form_CommandSelected(ICommand command)
        {
            command.Execute();
        }

Hah – that’s the clue! Sending parameter isn’t of the class CommandAddNewItem, but only must implement ICommand interface. Handler in the Controller invokes Execute() method of any command has been sent. In the “standard” approach we could do here switch like this:

if(command is CommandAddNewItem)
	then ...
else if(command is CommandDeleteNewItem)
	then ...
else if...

For every of the circa 50 commands we would have to add new “else if” – horror. Command pattern makes the code nice and clean. But we can go further. Let’s add in the Model new interface:

   public interface ITransaction
    {
        void Execute();
        void Undo();
    }

πŸ™‚ I know that you know what is going on πŸ™‚ We try to add Undo/Redo πŸ™‚ But wait a moment and you will see how simple it is with the design patterns πŸ™‚

Next, we have to add new class:

public abstract class Transaction : ITransaction
    {
        protected BookCollection collection;

        public Transaction(BookCollection collection)
        {
            this.collection = collection;
        }

        public abstract void Execute();

        public abstract void Undo();        
    }

For now, it’s valid for BookCollection only, but it should be easy to make this code generic (this is marked as TODO). This abstract class adds only constructor and protected field, that will be used by the descendants:

   public class TransactionAddEntity : Transaction
    {
        private Book book;
        public TransactionAddEntity(BookCollection collection, Book book) : base(collection)
        {
            this.book = book;            
        }

        public override void Execute()
        {
            this.collection.Add(new Book[]{this.book});
        }

        public override void Undo()
        {
            this.collection.Delete(new Book[] { this.book });
        }
    }

It’s a transaction to AddEntity (book). There are other – TransactionDeleteEntity and TransactionUpdateEntity, but their construction is similar, so I explain only this one. So we have new transaction class that contains method responsible for action Execute and another one – oppositive to it – Undo, responsible for withdrawing the Execute action.

Next step is to create quite meaningful class called DbUndoManager

public class DbUndoManager
    {
        private Stack<ITransaction> history;
        private Stack<ITransaction> undoHistory;

        public DbUndoManager()
        {
            history = new Stack<ITransaction>();
            undoHistory = new Stack<ITransaction>();
        }

	public void Register(ITransaction transaction)
        {
            undoHistory.Clear(); 
            history.Push(transaction);
        }


        public void Undo()
        {
            if (history.Count > 0)
            {
                ITransaction tr = history.Pop();
                tr.Undo();
                undoHistory.Push(tr);
            }
        }

        public void Redo()
        {
            if (undoHistory.Count > 0)
            {
                ITransaction tr = undoHistory.Pop();
                tr.Execute();
                history.Push(tr);
            }
        }
    }

Whooa, what’s this πŸ™‚ Two stacks that record history of executed (or withdrawed) commands, two methods responsible for Undo/Redo features (it’s a simple stack handling) that’s it πŸ™‚ How to use it? In the EntityCollection class we add new region:

#region Commanding

        private DbUndoManager undoManager = new DbUndoManager();

        public DbUndoManager UndoManager
        {
            get { return this.undoManager; }
        }

        public void DoTransaction(ITransaction transaction)
        {
            transaction.Execute();
            undoManager.Register(transaction);
        }


        #endregion

And we call DoTransaction any time when we want to do something with this collection (database). That’s it. Let’s say we want to handle click on the button “Delete Item From The Collection”:

class CommandDeleteItem : ICommand 
    {
        private Book book;
        private BookCollection bookCollection;

        public CommandDeleteItem(BookCollection books, Book book)
        {
            this.bookCollection = books;
            this.book = book;
        }

        public void Execute()
        {            
            this.bookCollection.DoTransaction(new TransactionAddEntity(this.bookCollection, this.book));
        }        
    }

Nothing more to say about it. Of course, there will be some trouble with another commands, but this pattern is quite clear and easy once implemented and I think that small adjustments won’t take too much effort. In case of any questions, please write.

Best regards,
Pawel

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: