is-keyword and Decorator Pattern
Hi everybody,
this is a bit of an annoying question once again. :) Some of you may know the is-keyword and the decorator pattern. (Short introduction below for those who don't, just to avoid strange replies to my question.)
For those who do not know the is-keyword:
I have been teached at school that it is rather bad practice to use the is-keyword, and can be avoided by using an interface IBlablabla which describes a "bool IsBlablabla()" function and implementing it all over the place. Personally I dislike this way of working, and I prefer the beauty of the is-keyword a lot.
A nice short description of what it does is available here: http://msdn2.microsoft.com/en-us/library/scekt9xw.aspx
For those who do not know the decorator pattern:
The decorator pattern can really save a lot of trouble in big complicated projects and is also sometimes used to avoid multiple inheritance problems. I will give you an example:
Let's say you want to make a car class:
public class Car{}
But you also want to add different kind of cars:
public class Truck : Car{}
public class Van : Car{}
public class Jeep : Car{}
Suddenly you notice you want to have Cars with radios:
public class CarWithRadio : Car {}
But what about a Trucks, Vans and Jeeps with a radios?:
public class TruckWithRadio : Truck {}
public class JeepWithRadio : Jeep {}
public class VanWithRadio : Van {}
Now you suddenly find out you want to have cars with headlights:
public class CarWithHeadLight : Car {}
Now what about cars with both headlights and a radio?:
public class CarWithHeadLightsAndARadio : CarWithRadio
The next thing you know also trucks and vans want to have headlights ...
in short ... to have cars, vans, jeeps and trucks with headlights, radio and a spoiler and all combinations of them you will need not just 7 classes but you will need (4.3.2+1).4 = 100 different classes :afrog: . The decorator pattern is the answer here.
To implement it you just need to define a baseclass (Car) and a class per property which derives from that class: "van, truck, jeep, radio, headlights, ..." Next let every propertyclass keeps a reference to another instance. Next you can create instances like:
Van v = new Spoiler(new Headlights(new Radio(new Van(new Car()))));
makes a van with a headlight, radio and a spoiler.
For those who know both the is keyword and the decorator pattern
Maybe you can help me out. Because the Decorator pattern does not really make subclasses the is command will not detect all "property"-classes.
Or is there a trick that I am overlooking here, to make it work either way?
Thank you in advance
Re: is-keyword and Decorator Pattern
Quote:
Because the Decorator pattern does not really make subclasses the is command will not detect all "property"-classes
Yeah, that's right. I don't believe there's a way around that. You're trying to determine one of the concrete types, and that's just not going to work. If you have code that needs uses something in the concrete type (Van, Radio etc.), then using the decorator pattern pretty much breaks that code.
Normally you'd have one abstract (MustInherit in VB) class that all classes extend from, and you can call any method in that abstract class. As long as you do that, you're fine.
Buoy
Re: is-keyword and Decorator Pattern
Yes, I can not think of any way around it neither. I am getting the impression that the good old design patterns as mentioned in literature are getting harder and harder to implement. Because of all the small new features of modern programming languages, perfect implementations do not exist anymore.
It is too bad that the is-operator is not overloadable. That would have been a reasonable workaround in my oppinion. (msdn reference: is, not overloadable)
Instead maybe I should add a function:
bool AbstractClass.Is(Type t);
Thank you once again for your oppinion.
Re: is-keyword and Decorator Pattern
Well, what are you trying to do? I mean, what's the use case? Depending on what you want to do, the decorator pattern may or may not be a good fit.
If you're just trying to determine, for example, that a car has a radio, you could have a .GetInformation() method in your base abstract class. Your decorator classes would implement this method. They'd call up the chain to .GetInformation() on their instance variable of the base class, and append their own information.
If you need to do something like radio.TurnOn(), then that's not going to work. Again, you can only call methods on the base abstract class, and not on the concrete classes, so the decorator pattern wouldn't work for you there.
If you isolate exactly what you need to do (use case), that will help determine if this pattern is what you need.
Regards,
Buoy
Re: is-keyword and Decorator Pattern
You know, I was thinking about this, and I'm not sure if it's a good idea or not. If your base class defines a collection of objects, or a collection of the base type, you could define an abstract get property in the base class.
Then, the implementing types would have to override that property. In the get property, you could add the current instance to the base collection, and return that. So you decorate away, then when you call that getter property, it will contain all the concrete objects.
Now that won't give you the "is" keyword functionality you were looking for, but it would give you a collection of concrete objects. You could iterate through the collection, seeing if it's a particular type.
I've wrote a small sample project to demonstrate. I can post it, or code snippets if you think it'd be useful.
Regards,
Buoy
Re: is-keyword and Decorator Pattern
hmm,
good idea I'll try it out as soon as I have some time.
Another idea that came to me was overriding the GetType() function. Chances are small, but maybe the is-operator uses the GetType() function indirectly. Not that likely, but still worth a try.
Re: is-keyword and Decorator Pattern
The is-operator doesn't use the GetType() after all. :) Instead I just added a function as I mentioned.
Your collection idea was interesting, but I think a little function is easier and keeps the rest of the decorator pattern intact.