views:

238

answers:

5

I am trying to make a C++ implementation of the board game Carcassonne. I am trying to make a tile object which has four sides and one of three basic terrains(field, road, city).

The best interface for tile creation I could think of was of the form:

City city;
city_city_city_city = new Tile(city, city, city, city);

Where a Tile class is defined somewhat as follows...

class Tile
{
 public:
  Tile(Terrain& top_terrain,
       Terrain& right_terrain, 
       Terrain& bottom_terrain,
       Terrain& left_terrain)
    {   
      top_side_.reset(top_terrain.Decorate(new TopSide()));
      right_side_.reset(right_terrain.Decorate(new RightSide());
      bottom_side_.reset(bottom_terrain.Decorate(new BottomSide()));
      left_side_.reset(left_terrain.Decorate(new LeftSide()));
    }

 private:
 boost::scoped_ptr<TopSide> top_side_;
 boost::scoped_ptr<RightSide> right_side_;
 boost::scoped_ptr<BottomSide> bottom_side_;
 boost::scoped_ptr<LeftSide> left_side_;
};

I wanted the constructor to initialize each specific Side(TopSide, RightSide, BottomSide, LeftSide) that inherits from the base class Side. The idea was to define a virtual Decorate method in the Terrain class that would return an instance of a SideDecorator for the specific type of Terrain.

Depending on the Type of terrain the side has, it will have a different number/type of TerrainSegments. For example: A Side with a Field has the need for only one FieldSegment, whereas a Side with a Road needs three Segments: a RoadSegment and two FieldSegments. Thus the adding of a tile to the board will need Sides with different implementations and members.

I could make concrete classes like TopFieldSide, BottomRoadSide, etc, but I figured the decorator pattern would be cleaner. The thing I am not sure about however is whether or not the polymorphic use of the Decorate() method is a misuse.

Certainly I could create Tiles of the form:

Tile(CityDecorator(new TopSide), 
     CityDecorator(new RightSide),
     FieldDecorator(new BottomSide),
     RoadDecorator(new LeftSide));

But the previous version seems much cleaner.

My question being... Is this an acceptable approach or is there a simplier/cleaner way that I am missing?

My use of this approach is running me into coupling problems because I have to include the path to SideDecorator in Terrain and Terrain is used in SideDecorator and in derived classes. The simple directive #include "side_decorator.h" in the terrain.h causes many compile errors making it hard to tell if it is a forward declaration problem or what something else unoticed in my code...

+1  A: 

What about having the Side produce the decorated result based on the Terrain argument, rather than viceversa? Then Terrain would only need a method to indicate the Segments it needs and their orientation might be arranged by the Side. Maybe that would ease the coupling?

Unrelated to coupling, but consider using generic programming more widely in your design -- it's not obvious that sides, terrains and/or segments shouldn't use genericity instead of, or as well as, inheritance. In a sense that's more of an implementation than a design issue, but it does influence design. Unfortunately I don't think I understand the application domain deeply enough to offer more specific suggestions (I did play Carcassonne once, quite a while ago, but besides it being fun I don't recall much;-).

Alex Martelli
A: 

A note about your circular dependencies problem: you could use the PImpl idiom, as explained in this Guru Of The Week article (another simple example here).

Paolo Tedesco
A: 

a Tile HAS 4 Sides, each of which IS one of Field, Road, City

class Side {
// things common to all sides
};

class Field : public Side {
// things only found in a field
};

class Road : public Side {
// things only found in a road
};

class City : public Side {
// things only in a city
};

class Tile {
collection of 4 Sides;
Tile(Side *top, Side *left, Side *right, Side *bottom);
};

// ex. usage:
Tile myTile( new Road, new City, new City, new Field );

Why does this not do all you would want? Note: references, pointers, whatever, that's implementation detail not important for the design question. I think the design pattern is overkill

A: 

Another possibility would be to use templates

template <class Top, class Right, class Bottom, class Left>
class Tile
{
  TopSide top;
  RightSide right;
  BottomSide bottom;
  LeftSide left;
  Tile()
  {
     // imaginary syntax to "decorate" a side
     top.type = new Top();
     right.type = new Right();
     bottom.type = new Bottom();
     left.type = new Left();
  }
}

Tile<City, Road, City, Field> tile();

The syntax would be very clean, especially with the aid of typedefs that you could automatically generate, such as:

typedef Tile<Field, Road, City, Road> Tile_F_R_C_R;

On the other hand, this could lead to a large amount of generated code.

UncleZeiv
A: 

I think your solution is fine. Effectively you require a virtual constructor, to create the right type of decorator based on the type it is decorating. This requires a factory method, which Decorate is. It hides the details of which decorator to create for a Tile, but your Terrain classes have to know they can be decorated.

I would only have a problem with this design if other classes required their own special type of decorators. Then adding new types and decorator would become a pain. But for one or two well defined cases your design is fine.

iain