I’m trying to apply the Decorator Design Pattern to the following situation:
I’ve 3 different kind of forms: Green, Yellow, Red.
Now, each of those forms can have different set of attributes. They can have a minimize box disabled, a maximized box disabled and they can be always on top.
I tried to model this the following way:
Form <---------------------------------------FormDecorator
/\ /\
|---------|-----------| |----------------------|-----------------|
GreenForm YellowForm RedForm MinimizeButtonDisabled MaximizedButtonDisabled AlwaysOnTop
Here is my GreenForm code:
public class GreenForm : Form {
public GreenForm() {
this.BackColor = Color.GreenYellow;
}
public override sealed Color BackColor {
get { return base.BackColor; }
set { base.BackColor = value; }
}
}
FormDecorator:
public abstract class FormDecorator : Form {
private Form _decoratorForm;
protected FormDecorator(Form decoratorForm) {
this._decoratorForm = decoratorForm;
}
}
and finally NoMaximizeDecorator:
public class NoMaximizeDecorator : FormDecorator
{
public NoMaximizeDecorator(Form decoratorForm) : base(decoratorForm) {
this.MaximizeBox = false;
}
}
So here is the running code:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CreateForm());
}
static Form CreateForm() {
Form form = new GreenForm();
form = new NoMaximizeDecorator(form);
form = new NoMinimizeDecorator(form);
return form;
}
The problem is that I get a form that isn’t green and that still allows me to maximize it. It is only taking in consideration the NoMinimizeDecorator form. I do comprehend why this happens but I’m having trouble understanding how to make this work with this Pattern.
I know probably there are better ways of achieving what I want. I made this example as an attempt to apply the Decorator Pattern to something. Maybe this wasn’t the best pattern I could have used(if one, at all) to this kind of scenario. Is there any other pattern more suitable than the Decorator to accomplish this? Am I doing something wrong when trying to implement the Decorator Pattern?
The problem here is that you’re not actually implementing the decorator pattern. For a proper implementation of the pattern, you need to subclass
Formto create your decorator, and then intercept all operations taken on your decorator and forward them to your privateForminstance. You sort of do that, except that aside from assigning a reference in theFormDecoratorconstructor, you never again use that privateForminstance. The net result is that you create aGreenForm, then wrap it in aNoMaximizeDecorator, and then you wrap that in aNoMinimizeDecorator. But because you never forward operations taken against theNoMinimizeDecoratorto the wrappedForminstance, only theNoMinimizeDecoratorinstance actually applies any behavior to the instance that’s used. This fits with what you observe when you run your code: a standard window with a disabled Minimize button.Formis a really bad example for creating decorators in C#, because most of its properties and methods are non-virtual, meaning if you’re accessing the decorated form via aFormreference, you have no way to intercept the base class’s properties – you can’t effectively “wrap”Form.EDIT
It occurs to me that the statement “Form is a really bad example for creating decorators in C#” really begs the question of what is a good example. Typically, you’ll use the decorator pattern to provide a custom interface implementation without implementing the entire implementation from scratch. A very common example is generic collections. Most everything that wants list functionality doesn’t depend on, e.g.,
List<String>, but rather onIList<String>. So, if you for example want a custom collection that won’t accept strings shorter than 5 characters, you would use something like the following: