Geeks With Blogs

News

Series

Add to Technorati Favorites


An Archived Managed World This blog has moved to http://www.managed-world.com/blog

[disclaimer: this is kind of a long post. it is primarily meant as a learning experience. i might be alone here, but i enjoy reading other people's posts about problems they have and how they solved the problem. sharing knowledge is one of the reasons blogging exists, right? so why not take full advantage of that.]

[update: Sean correctly pointed out that the more correct pattern to use in this situation is the Adapter pattern. In hindsight, the key to the Decorator pattern is the *dynamic* change of behavior. However, I'm going to leave this post untouched (except for the name) to remind me how much I still have to learn.]

For anyone that has any experience with object-oriented programming, you know that there are numerous ways to skin a cat. One of the biggest challenges I believe for reasonably fresh OOP developers is remembering all the different tools you have at your disposal. Often, if you are given a problem, there will be numerous solutions to that single problem. Is there one “true” solution, probably not. However, there are solutions that are better than others.

It is best to become familiar with the saying “use the right tool for the job”. This is especially true when you are a developer. You need to do your best to make sure that you have more tools under your belt than just a hammer. Because if you have just a hammer, everything will start looking like a nail (kind of cliché, I know, for that I apologize :)). One particular area of OOP that tends to have all sorts of solutions is the area of extension (or “extending” a class to do something new).

There are three primary ways to extend the functionality of any given class: 1) Add the new functionality directly to the class, 2) Derive a new class from the original class, and implement the new functionality in the new class, or 3) Encapsulate the original class in a new class and use delegation to reach the original functionality of the original class (sometimes referred to as “decorating“ or “wrapping“ (thanks Jake :D)). Ideally, the first two options tend to be the best routes to take. However, the first option is only feasible if you have the source code (beware: it could also introduce breaking changes are introduce new bugs (which would be a bad thing!)).

If you don't have access to the source code, then you are stuck with the second and third options. The second option (deriving a new class) isn't a bad option, by any means. In fact, I would venture to guess that many of us are familiar with this. However, what if the class is “sealed” and no class can be derived from it o_O. It seems like we might be up a creek without a paddle in that case. However, there is one more option (although it can also have it's own difficulties). That is to extend functionality through encapsulation, or “decorating“ [NOTE: Usually, having to extend a “sealed“ class should throw up a red flag for you. There are times when it is an acceptable solution so make sure to keep it in your bag of tools]. I was originally exposed to decorating by the Decorator Pattern in the GoF Design Patterns book (every geek must own this book (if you are a software developer and don't own this book, SHAME ON YOU (go buy it now before your soul is reaped for eternal damnation))). This can be achieved by encapsulating the original class within your new class and duplicating it's interface. Every method or property that was duplicated simply “delegates” to the encapsulated class. The concept, I believe, is best explained through an example.

Let's say that we have a class “SealedClass” that we want to extend the functionality of. It has a pretty simple interface, just a couple of methods. The class looks like follows (although, theoretically, we don't have access to the source code :)):

     public sealed class SealedClass
     {
          public string MethodA() { return "SealedClass.MethodA"; }
          public string MethodB() { return "SealedClass.MethodB"; }
     }

Now, in order to extend this to add a MethodC, it is done via a Decorator. Our decorator would look as follows:

     public class Decorator
     {
          private SealedClass sealedClass = new SealedClass();

          public string MethodA() { return sealedClass.MethodA(); }
          public string MethodB() { return sealedClass.MethodB(); }
          public string MethodC() { return "ExtendedClass.MethodC"; }
     }

Why do I bring this up? It is mostly to hopefully help some people out there that are banging their head on the wall trying to design a solution for a potentially complicated problem (although, I won't lie, the solution is also so that I remember about this since I tend to be quite scatter-brained). I was recently banging my head against the wall while designing my 2D game engine. I ran into a brick wall when I came to the point of abstracting the flexible vertex format of DirectX. I need to abstract the vertex information into my own engine because I want to be able to plug in an OpenGL renderer in the engine as well.

The problem that I ran into was how I was trying to solve this dilemma. I created my own Vertex structures in the engine, which was fine. However, how do you get from those vertex structures to the D3D vertex structures (in C# mind you). I originally took the angle of simply “translating” the vertices at runtime. So, when a request came in to the renderer to render my vertex structure, I was going to translate my structure into a D3D structure, and then pass that on to render. The problem came with how flexible vertex formats can be in DirectX. It quickly became apparent that this was going to need a solution that was too complicated for its own good.

Well, if the solution is getting too complicated, maybe the problem isn't how you're implementing the solution, maybe the problem is how you are approaching the problem in the first place. So, let's try to take another approach to solving this issue (choosing a different “tool“ for the “job“ (hehe, aren't I clever?)). Let's think about the Decorator Pattern and how we might apply it to this problem.

Instead of classes in our game engine (the abstraction), let's simply do interfaces. We will define interfaces for the various vertex types and will delegate the creation of those vertex types to the renderer itself. This creation delegation is done via a factory that we will force all renderer dlls to implement. The clients of the game engine will simply know the vertex type interfaces and the abstract vertex factory. The slight bummer is that the client won't be able to a simple “new PositionVertex()” because creation must be done through the abstract factory. They will be able to do “IPositionVertex vert = (IPositionVertex)renderer.VertexFactory.Create(typeof(IPositionVertex));”. I'm still not sure whether I like the factory through System.Type method, but I can do a simple change later if I don't like it.

Anyways, not that any of this means squat, but just remember kids, there are many solutions to a single problem. If your current solution isn't sitting right with you, than try a different approach to your problem. Sometimes all it takes is a simple paradigm shift and the architecture will snap into place. This also illustrates how important it is to verse yourself with common structural paradigms (i.e. Patterns). That's just one area where the Design Patterns book will come in quite handy. You can see here that knowing a design pattern from that book helped me out of a jam quite well :). Until then, Happy Coding!

Posted on Thursday, October 21, 2004 6:18 PM Game Development | Back to top


Comments on this post: OOP - Extension through Encapsulation (kind of ;))

# re: OOP - Extension Through Encapsulation
Requesting Gravatar...
Extension through encapsulation is almost just syntactic sugar of wrapping or decorating...

It's also not extending because your new subclass is not a true subclass of the original class. Therefore it breaks inheritence. :: shrugs ::

Though I do agree that there are tons of bags of tricks, this option might not be the best solution. Either that or it should be called something different. The purpose of having a sealed class is ensuring that your class should not be extended. You should only use sealed when you are absolutely sure you CAN'T extend the class for object reasons...

but I do like your use of the abstract factory pattern.. nice...
Left by Jake Good on Oct 21, 2004 6:47 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Jake, ah! Decorating was the term I was trying to grope for. I couldn't think of it earlier, so I used "Extension through Encapsulation". That's right. The "Decorator" pattern.

As for extending, it all depends on your definition of "extending". Extending does not have to be done strictly through subclassing. A definition of the Decorator pattern from the GoF is "Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality". I happen to think it is the perfect solution for certain problems. You are right though, you should really think twice before using a decorator to extend a sealed class. Sealed classes are sealed, well, for a reason :).

Decorating worked in my solution because I didn't want to actually inherit from the d3d vertex classes because then I would need to be dependant on d3d which would kind of forgo the whole point :).

And thanks about the abstract factory pattern :).

As for the "extension through encapsulation", I'm going to change the article a little bit. Thanks for the heads up :).
Left by Jason Olson on Oct 21, 2004 7:45 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
excellent! :) ahh the power of OOP
Left by Jake Good on Oct 21, 2004 9:06 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Yup :). The power of OOP. Is it just me or are other people instantly reminded of the book Microserfs when you hear "OOP".
Left by Jason Olson on Oct 21, 2004 10:39 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Jason,

Great! Thanks for sharing your experience.

Great to hear you consider GoF as essential. I recommended the following work as well http://www.amazon.com/exec/obidos/ASIN/0471606952/qid%3D1097611204/sr%3D2-2/ref%3Dpd%5Fka%5F2%5F2/103-8009609-8417452. It is a great resource for concurrency and synchronization patterns which you might apply to your game engine.

Whether a class is sealed or not, in general, I prefer composition over class inheritance.

Jake, Nothing wrong with encapsulating and calling methods on a sealed class. What's the probelm?

I do not consider it to be "powerful" to think about inheritance in terms of extending the functionality or any kind of reuse of the functionality. Inheritance is a mechanism for conceptualizing the variations.

Sometimes not only is it not so "powerful" or "elegant" to think about inheritance as merely means of reuse, it is also a mistake and might lead to many incorrect designs. [I cannot think of a better example to support this idea but this absolutely absurd one will do to elucidate what I am talking about: he designed and implemented a Door type. He moved on to designing a House type. He discovered that the House will need a functionality similar to the Door, too. Ok, he will reuse the implemented functionality of the Door by deriving the House from the Door.]
Left by Roman T. Fakhrazeyev (Karenin) on Oct 22, 2004 12:48 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Roman,

Thanks for the link! It's kind of funny. This book is on Amazon wish list and I've been saving money for it. And now that I think about it, I think I already have the book! It is a book that I bought a while ago before I knew about the GoF book and I just filed it away in my library. Well, time for some reading :).

As for the other issues :).....

I mostly agree with you on the conceptualization of inheritance. I find now that when I think about it, I don't really use inheritance for "extending" functionality, per se. It seems that I use inheritance more when I need or would like polymorphic behavior. Like if I have a common base class who contains virtual functions that are called polymorphically into the derived class. Like you said, it's more of a mechanism for conceptualizing the variations. To me, polymorphic virtual functions are a way to vary the type of behavior a class may have. Not too much mind you, because it is usually bad to violate the Liskov Substitution Principle.

I must admit, I've never really subscribed to the whole OOP approach of "is-a"s and "like-a"s and stuff. I can't really explain my approach because I've never had to think about it. It's almost like it is more based on Patterns and roles. Perhaps it's just my growth as an OOP developer.

But when you start realizing how good of a tool composition is, you realize you have another tool to add to your bag. I suppose it's just the growth progress of an OOP developer. It seems like its common for developers to abuse the use of inheritance at first. Perhaps this just means that I'm actually becoming a better OOP developer :D.
Left by Jason Olson on Oct 22, 2004 1:41 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Great, right on on the inheritance!

Yes, based on the patterns and responsibilities [roles as you said].

Your mentioning the Liskov substitution reminded me of another work I have in my library: http://www.amazon.com/exec/obidos/tg/detail/-/0135974445/qid=1098476018/sr=8-4/ref=pd_csp_4/103-8009609-8417452?v=glance&s=books&n=507846.

What do you think about Agility?
Left by Roman T. Fakhrazeyev (Karenin) on Oct 22, 2004 4:18 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
[Or Agility deserves a thread of its own?]
Left by Roman T. Fakhrazeyev (Karenin) on Oct 22, 2004 4:21 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Roman,

That book is great! That is the book that I actually learned LSP from (and all the other principles therein). It is a profoundly good book. Every developer writing code in an OOP environment should read that book (even if for the principles alone!).

The jury is still out on how I feel about agile development as a process. Truth is, I don't know much about the "agile" process, except for the extremes, like XP. I know that I'm not a big fan of XP. However, there are certain parts or tenets of XP which I do agree with. I'm just unsure about using die-hard XP as a whole.

As for XP, one thing is for sure. I believe that whoever uses XP needs to be extremely versed in the ways of unit testing, refactoring, and using design patterns. Without a solid understanding of design patterns and refactoring, it's much more difficult to develop that common "language" used to communicate between software developers. If I am working with another developer who knows design patterns and refactoring inside and out, I think I would be comfortable using XP.

I feel the problem is that a lot of developers jump on the XP bandwagon without realizing how much discipline it takes. XP is not the same thing as "code and fix". You don't just sit down and start writing code without thinking about design. It takes a lot of discipline and knowledge to make an XP project successful. You can't just dive in and go. You need to stop and communicate what the general design of your solution is going to be. And knowing patterns in and out makes that extremely easy. If I say to another developer that I think we can extend the functionality of ClassA by using a Decorator, he will know exactly what I mean. Let alone being able to communicate how to get from the current design to the target design through refactorings.

Anyways, yes, I love that book. If I could recommend any four books to an aspiring OOP developer that wants to take the next step, they would probably be:

Design Patterns by GoF
Refactoring by Martin Fowler
Agile Software Development by Robert C. Martin
and
UML Distilled by Martin Fowler

There are numerous others that I would recommend next. Actually, the more I think about it, the more I realize how difficult it would really be to recommend just four books. But the four above would definitely give anyone a really good start :).
Left by Jason Olson on Oct 22, 2004 4:57 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Nothing is wrong with that... but if you look at it from a inheritence standpoint to which you want to be able to use those objects in scenerios the same as your base objects in which it wraps.. then there comes the problem.

It breaks inheritence to have one to one mapping delegated methods explicitly in a subclass...

Left by Jake Good on Oct 22, 2004 6:30 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
whoops.. i posted before refreshing with the comments.. sorry guys :)
Left by Jake Good on Oct 22, 2004 6:30 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
That's true. The absolute prerequisite of applying the Agile practices is a solid knowledge/experience in and fluency with OOP/Patterns/Refactoring.
Left by Roman T. Fakhrazeyev (Karenin) on Oct 23, 2004 1:35 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Unfortunately, I think there are quite a number of development teams that don't realize this though. I feel a lot of budding developers treat XP exactly like the usual "code and fix" development. It's a bummer, really. I think agile practices can be extremely successful when implemented correctly. I think the main reason for failed agile projects is primary because of a lack of understanding on what the true prereqs for the process are.
Left by Jason Olson on Oct 23, 2004 4:15 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
I think the pattern you are wanting to use is the Adapter pattern

define a vertex interface

IVertex { }

then have

Direct3DVertexAdapter : IVertex

OpenGLVertexAdapter : IVertex

abstract ObjectFactory { IVertext CreateVertex(); }

concrete Direct3DFactory : ObjectFactory { override IVertex CreateVertext() { return new Direct3DVertexAdapter(); }


Direct3DVertexAdapter actually wraps and adapts calls from your IVertex, to its internal Direct3DVertex instance

Decorator is the wrong pattern to be using.
Left by Sean Malloy on Jan 15, 2005 7:08 PM

# re: OOP - The Decorator Pattern Applied (kind of ;))
Requesting Gravatar...
Sean, you are right. It seems obvious now in hindsight. All I can say is that I'm obviously still learning at when and how to properly apply patterns at times. The key that I missed originally about the Decorator pattern is that it *dynamically* changes the behavior of an object, which obviously isn't happening in the Vertex example above.

The mildly funny part is that the original un-altered post was actually called "Extension through Encapsulation" instead of the Decorator Pattern applied. My main point I was trying to emphasize is that often extending the functionality of a class through encapsulation is better than through inheritance.

On the other hand, this is a good example of how important it is to know *many* patterns *well*. I'm not going to change the actual post now because I think it is important for me to leave it up as a reminder that I still have a lot to learn. I will put an update up though. Thanks Sean.
Left by Jason Olson on Jan 15, 2005 7:36 PM

# re: OOP - Extension through Encapsulation (kind of ;))
Requesting Gravatar...
i want to find out
data abstraction through encapsulation but could not find
Left by anny on Feb 25, 2005 1:23 PM

# re: OOP - Extension through Encapsulation (kind of ;))
Requesting Gravatar...
As an experienced c# programmer I can't help but think of Peter North when I read about this pattern.
Left by bloodgroove on Jun 06, 2005 11:36 AM

Your comment:
 (will show your gravatar)


Copyright © Jason Olson | Powered by: GeeksWithBlogs.net