Using decorator pattern is polymorphic and communication problems in C ++

I am trying to create a C ++ version of the Carcassonne board game. I am trying to make a tile object that has four sides and one of the three main landscapes (field, road, city).

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

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

If the 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), which inherits from the base side of Side. The idea was to define a virtual Decorate method in the Terrain class that would return a SideDecorator instance for a specific Terrain type.

Depending on the type of terrain that has a side, it will have a different amount / type of TerrainSegments. For example: A side with a field requires only one FieldSegment, while a side with a road needs three segments: RoadSegment and two FieldSegments. Thus, adding tiles to a board will require parties with different implementations and members.

I could create specific classes like TopFieldSide, BottomRoadSide, etc., but I decided that the decorator pattern would be cleaner. However, I am not sure if the polymorphic use of the Decorate () method is a misnomer.

Of course, I could create Tiles forms:

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

But the previous version looks a lot cleaner.

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

My use of this approach leads me to communication problems, because I have to include the path to SideDecorator in Terrain, and Terrain is used in SideDecorator and in derived classes. The simple #include directive "side_decorator.h" in terrain.h causes a lot of compilation errors, making it difficult to determine if this is a direct declaration problem or something else invisible in my code ...

+4
source share
6 answers

How about a Party producing a decorated result based on the Terrain argument, and not vice versa? Then Terrain will only need a method to indicate the segments that it needs, and their orientation can be organized by the party. Maybe it makes the grip easier?

It doesnโ€™t apply to binding, but weโ€™ll take a closer look at the use of universal programming in your design - itโ€™s not obvious that parties, landscapes and / or segments should not use commonality, not inheritance, not inheritance. In a sense, this is more of an implementation than a design problem, but it affects the design. Unfortunately, I do not think that I am deeply versed in the field of applications to offer more specific offers (I really played in Carcassonne once, recently, but besides being fun, I donโ€™t remember very much;).

+1
source

A note about your circular dependency problem: you can use the PImpl idiom as described in this Lesson of the Week article (another simple example here ).

0
source

a HAS tile 4 Parties, each of which is one of the fields, roads, 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 doesn't this do everything you need? Note: links, pointers, whatever it is, this implementation detail is not important for the design issue. I think the design template is full.

0
source

Another option is 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 will be very clean, especially with typedefs that you could automatically generate, for example:

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

On the other hand, this can lead to a lot of generated code.

0
source

I think your decision is in order. Effectively, you need a virtual constructor to create the right type of decorator based on what it decorates. This requires the Decorate factory method. It hides the decorator design details for Tile , but your Terrain classes should know that they can be decorated.

I would have a problem with this design if other classes needed their own special type of decorators. Then adding new types and decorators will be a pain. But for one or two well-defined cases, your design is fine.

0
source

I could create specific classes like TopFieldSide, BottomRoadSide, etc., but I decided that the decorator pattern would be cleaner.

Figure Decorator adds complexity, which really pays off if you are going to add new decorators, but do not want to change the main application. If the rules of your game are fixed (there can never be anything but the specific classes that you mentioned), then I would say that the difficulty will not pay off.

If you want to use Decorator to learn or master a pattern, then go for it. But be careful that the problem that it solves may not actually be present in your design requirements.

0
source

All Articles