The decorator pattern is a great design pattern enabling developers to add additional behaviour to a particular object. Below is a UML Diagram (from Wikipedia) showing the design pattern. To start, you have a interface that specifies all the methods that you wish to be able to extend. Then you have the concrete component or base class. This is the original class that will be running. The decorators then contain the additional logic that you wish to add the to base object. In this guide, we look at how we can do this at runtime.
Using this pattern, we can enable runtime behavioural variations of classes within an Android application by adding and removing decorators from the decorator stack. One problem with Android (and probably other frameworks), this pattern makes use of Object-Oriented concepts like object construction. On Android, many of the essential classes you work with e.g. Activities and Services, you have no control or ability to construct these objects. Other problems can be attributed to the fact that you do not have real (if I am wrong, then it probably is not the recommended way) control of the activity in terms of updating its reference to another (needed for decorator methods to be invoked). In other languages like C++ it is possible to do pointer manipulation, and therefore get around this problem, but in Java, you can’t.
While this method may not be ideal or perfect, it is a workaround that I am using. With that in mind lets have a look at my example code.
Firstly, we have the interface MainActivityInterface. In this class we have a single method signature pushMeClick(View V); . This method corresponds to the touch event for the button named “Push Me” (Not very imaginative I know, but you get the point).
Next, we have the core Activity MainActivity, and this class obviously extends Activity, but also implements MainActivityInterface. Within this class we have decorator class MainActivityDecorator member named toplevel. This reference is needed to direct an invocation to the top of the decorator stack. Also we have a TextView object named txtMe, used to show a piece of text in the Window. In the OnCreate(Bundle) method we get the TextView object from the View.
The method pushMeClick(View v) as declared in the interface checks to see if the class is decorated, if it is not, then a core version of that method is invoked (the base behaviour). If the class is decorated, then the decorator version of that method is invoked. We also have a method named toggleClick(View v). When the button named “ToggleDecorator” is clicked, it checks if it the activity has been decorated. If it hasn’t, then the first decorator is added to the stack. If it has been decorated once, then the second is added to the stack. And if the second has been added, it is removed, leaving only the first.
Next we the add the base decorator class named MainActivityDecorator. In this class we add the base activity MainActivity naming it activity (I know, I really do pick great names). We also add another class member, of the type MainActivityInterface named parent. This member is used in a decorator chain that is more than 1, with the parent object pointing to the next decorator in the chain/stack. In the decorator we have two constructors whereby the activity is used as a parameter and in one of the constructors allow for the parent decorator to be added.
Next we have the method pushMeClick(View v), to which if there is a parent decorator, the parents version of the method is invoked, if there is no parent, the core version in the base activity MainActivity is invoked. Normally in the decorator pattern you do not need this, can just run the super version. But if you do in this, you will get caught up in a recursive loop and cause a Stack Overflow. The reason this is different, is because like we said before, we can’t update the reference of an activity, and therefore the base activity has to handle the method call at first.
We also add a method to the decorator called removeSelf(). This method removes the reference to the activity (to help cut any ties that will not allow it being collected by gc), and return the decorators parent (so the activity updates its toplevel decorator reference).
Each Specific Decorator
Next we add specific decorators which extend MainActivityDecorator, and in example we just call them MainActivity_decorator_one and MainActivity_decorator_two for simplicity. In these classes I have to add a constructor which just calls its super version. I then add a pushMeClick(View v) method in each. In these methods I firstly call the super version first, I then get the TextView from the activity (package protected) and append either “, decorator1” or “, decorator2”.
Obviously, because of the extra instructions needed, this pattern is not computationally free. When I have time, I will try and profile the effect, and update this entry with its effect
You can find this code at https://deansserver.co.uk/gitweb/?p=codeExamples/AndroidDecorator.git;a=summary where you can view and download (click on snapshot on which revision you want).