…Which still seems kind of ugly to me. Less so than before now that I’ve thought about it. But I’ve also had the problem of making a better design in my mental background space for a few days. I’m not entirely sure precisely what my growing sense of program design takes offense to about the pattern–although I have a general idea and a few guesses–or where it’s going with how to fix the issue.
Note: If you’re not familiar with program patterns, this will probably be an incomprehensible blog post. My own understanding of this topic is almost nonexistent, so I can’t explain what I’m talking about, and you wouldn’t want to learn from me anyway. I’m writing mainly for my own mental clarity, and to flesh out the ideas that have been nagging me.
The only hint of a solution I’ve posed on here is that I would use more of a Strategy-shaped pattern.
Issues with Decorator that I can point out: It’s big and clunky. You can’t see everything that’s going on with your objects, and you can’t rely on being able to test for all their characteristics if you need to–which means that if a future feature needed to go back and see that information, you’d have to restructure the whole program or implement a klugey hack that would be even messier. So it’s brittle.
Probably for simple stuff it’s fine, and even in special “big” cases, but… I had a similar reaction to reading about it as when my Intro to Programming Logic class taught us about bubble sort algorithms. Roughly: “Ick.”
In the book’s example, you’re using decorators to customize coffee orders with different toppings: mocha, whipped cream, soy, steamed milk, whatever. I’ve been thinking about how you could use implementations in this scenario, or maybe put in special dedicated methods to add toppings.
Personally, I would use arrays for–
Aw, man… am I venturing into LISP territory, using arrays for stuff that probably doesn’t need arrays?
Whatever.
My first impulse is to give each individual drink object a toppingList array to work with (perhaps inherited from a superclass), and let it call different methods which would append toppings to toppingList, which could be evaluated later–for the purposes of charging extra for each topping and so on.
But I don’t like that idea much either.
Using arrays is a good start, but there has to be a way to use an interface or an abstract superclass to standardize things.
All the drinks have toppings (or lack thereof). Even if there’s another drink which would be awful combined with certain toppings, it won’t hurt to have the potential for toppings in general to exist, even if there aren’t any appealing ones right now.
Like I said, Strategy pattern would be a good one to take a hint from. You could implement an interface for toppings, and then methods for each topping that add the topping to the drink’s toppingList array. If you need to, you can probably increment price at this time too.
The problem would be if permissions didn’t let you edit the drink’s variables (toppingList, drinkPrice, etc)? I don’t think that’s an issue, but I haven’t seen the code. Flowcharts like this book is littered with are really helpful to understand the design patterns, but they just don’t give you (me, anyway) the whole picture.
But if you did implement new toppings, you would have to go back and add support for them wherever the toppingList array is evaluated (near the end of the program, I think), which is something you’re supposed to avoid. Maybe you could hack around that, though. It would still leave your objects in a more usable state regarding how much information you can access from them.
Again, I’m still on my first, light run-through of this book, so there’s a lot I don’t know. If you’re not already familiar with design patterns and what is good practice, don’t let my speculative discussion teach you bad practice.