On Nov 17, 12:20*am, Chris Stankevitz <chrisstankev...@gmail.com>
wrote:
> On Nov 16, 2:12 pm, Ian Collins <ian-n...@hotmail.com> wrote:
>
> > So how would a generic drawing class be expected to know this?
>
> This is basically the question I am asking this group.
>
> Below is a pseudocode answer to the question that
> *- leaves Shape, Circle, and Square untouched (good)
> *- places no drawing dependency on the shapes (good)
> *- leaves drawing code entirely in the Drawer classes (good)
> *- does not have switch or if statements (good)
> ** does use a dynamic cast (BAD)
>
> Can you (or anyone else) come up with some c++ pseudocode that
> *- leaves Shape, Circle, and Square untouched (good)
> *- places no drawing dependency on the shapes (good)
> *- leaves drawing code entirely in the Drawer classes (good)
> *- does not have switch or if statements (good)
> *- does not use a dynamic cast (good)
>
> Chris
>
> =====
>
> //----------
> struct Drawer
> {
> * virtual void Draw(Shape* shape) = 0;
>
> };
>
> //----------
> struct CircleDrawer : public Drawer
> {
> * void Draw(Shape* shape)
> * {
> * * // dynamic_cast<Circle*>(shape)
> * * // draw the circle
> * }
>
> };
>
> //----------
> struct SquareDrawer : public Drawer
> {
> * void Draw(Shape* shape)
> * {
> * * // dynamic_cast<Square*>(shape)
> * * // draw the square
> * }
>
> };
>
> //----------
> struct DrawerCreator
> {
> * virtual Drawer* GetNewDrawer() = 0;
> * virtual bool CanDraw(Shape* shape) = 0;
>
> };
>
> //----------
> struct CircleDrawerCreator : public DrawerCreator
> {
> * Drawer* GetNewDrawer() { return new CircleDrawer; }
> * bool CanDraw(Shape* shape) { return dynamic_cast<Circle*>(shape); }
>
> };
>
> //----------
> struct SqareDrawerCreator : public DrawerCreator
> {
> * Drawer* GetNewDrawer() { return new SquareDrawer; }
> * bool CanDraw(Shape* shape) { return dynamic_cast<Square*>(shape); }
>
> };
>
> //----------
> struct DrawerManager
> {
> * void RegisterDrawerCreator(DrawerCreator* dc)
> * {
> * * drawers.push_back(dc);
> * }
>
> * void Draw(Shape* shape)
> * {
> * * if (Drawer* drawer = GetDrawer(shape))
> * * {
> * * * drawer->Draw(shape);
> * * }
> * }
>
> * Drawer* GetDrawer(Shape* shape)
> * {
> * * for (int i = 0; i < drawers.size(); ++i)
> * * {
> * * * if (drawers[i]->CanDraw(shape))
> * * * {
> * * * * return drawers[i]->GetNewDrawer();
> * * * }
> * * }
>
> * * return 0;
> * }
>
> * vector<Drawer*> drawers;
>
> };
>
> //----------
> int main()
> {
> * DrawerManager drawer_manager;
>
> * drawer_manager.RegisterDrawerCreator(new CircleDrawerCreator);
> * drawer_manager.RegisterDrawerCreator(new SquareDrawerCreator);
>
> * Shape* shape1 = new Circle;
> * Shape* shape2 = new Square;
>
> * drawer_manager.Draw(shape1);
> * drawer_manager.Draw(shape2);
>
>
>
>
>
>
>
> }
What you seem to be showing here is the adapter pattern. The way you
went about it seems backwards, though. When you create your adapter
(Drawer), you should strive to do it using the correct adaptee type.
But what you did is to throw said type back to base (by passing Shape*
to DrawerManager) and reached for dynamic_cast.
So how about this:
int main()
{
Canvas c;
Circle shape1;
Square shape2;
Draw(c, CircleDrawer(shape1));
Draw(c, SquareDrawer(shape2));
}
class Canvas { /*Driving primitives here*/ };
class Drawer
{
public: virtual void Draw(Canvas& c) const = 0;
};
void Draw(Canvas& c, Drawer& d)
{
d.Draw(c);
}
// Trivial intermediary: drawer for Shapes.
class ShapeDrawer
{
const Shape& s_;
public:
ShapeDrawer(Shape& s) : s_(s) {}
};
// Implementation starts here
class CircleDrawer : public ShapeDrawer
{
public:
CircleDrawer(const Circle& s) : ShapeDrawer(c) {}
virtual void Draw(Canvas& c) const {knock yourself out}
};
class SquareDrawer {you get the picture};
IOW... __Don't__ use generic Shapes in lib B logic. __Adapt__ them as
soon as you get them (because then you should know their types, and
that's the only way to avoid casting) and use adapters. Added bonus:
adapters will let you mix your own stuff with lib A stuff.
Goran.
P.S. You didn't want dynamic_cast, but rather static_cast, there.