繁体   English   中英

多态地应用装饰器模式并在C ++中耦合问题

[英]Applying the decorator pattern polymorphically and coupling problems in C++

我正在尝试制作卡尔卡松棋盘游戏的C ++实现。 我正在尝试制作一个具有四个边和三个基本地形之一(田地,道路,城市)的瓷砖对象。

我能想到的最好的瓷砖创建界面是:

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

Tile类的定义如下......

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_;
};

我希望构造函数初始化从基类Side继承的每个特定Side(TopSide,RightSide,BottomSide,LeftSide)。 我们的想法是在Terrain类中定义一个虚拟Decorate方法,该方法将返回特定类型Terrain的SideDecorator实例。

根据边的地形类型,它将具有不同数量/类型的TerrainSegments。 例如:带有Field的Side只需要一个FieldSegment,而带Road的Side需要三个Segments:RoadSegment和两个FieldSegments。 因此,向板添加块将需要具有不同实现和成员的Sides。

我可以制作像TopFieldSide,BottomRoadSide等具体的类,但我认为装饰器模式会更清晰。 然而,我不确定的是,Decorate()方法的多态使用是否是滥用。

当然我可以创建形式的Tiles:

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

但以前的版本似乎更清洁。

我的问题是......这是一种可接受的方法,还是我缺少一种更简单/更清洁的方法?

我使用这种方法让我陷入耦合问题,因为我必须在SideDecorator和派生类中使用Terrain和Terrain中的SideDecorator路径。 在terrain.h中使用简单的指令#include“side_decorator.h”会导致许多编译错误,这使得很难判断它是否是一个前向声明问题或者我的代码中有什么其他东西是什么...

那么让Side产生基于Terrain参数的装饰结果,而不是反之? 然后Terrain只需要一种方法来指示它需要的分段,并且它们的方向可以由Side安排。 也许这会缓和耦合?

与耦合无关,但考虑在您的设计中更广泛地使用泛型编程 - 侧面,地形和/或段不应该使用通用性而不是继承性,也不应该使用通用性。 从某种意义上说,它更像是一个实现而不是一个设计问题,但它确实会影响设计。 不幸的是,我认为我对应用领域的理解不够深入,无法提供更具体的建议(很久以前我曾经玩过卡尔卡松一次,但除了它很有趣之外,我不记得太多了;-)。

我可以制作像TopFieldSide,BottomRoadSide等具体的类,但我认为装饰器模式会更清晰。

Decorator模式增加了复杂性,如果您打算添加新的装饰器但又不想修改主应用程序,那么这种复杂性实际上只会带来回报。 如果你的游戏规则是固定的(除了你提到的具体类别之外别无他法),那么我会说复杂性不会得到回报。

如果您想应用Decorator来学习或掌握模式,那就去吧。 但请注意,它解决的问题可能实际上并不存在于您的设计要求中。

关于你的循环依赖问题的注释:你可以使用PImpl习语,正如本周的Guru文章这里的另一个简单例子)中所解释的那样。

瓷砖有4个边,每个边都是田野,道路,城市之一

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 );

为什么这不是你想要的全部? 注意:引用,指针等等,这些实现细节对于设计问题并不重要。 我认为设计模式过度

另一种可能性是使用模板

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();

语法非常干净,特别是在你可以自动生成的typedef的帮助下,例如:

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

另一方面,这可能导致大量生成的代码。

我认为您的解决方案很好。 实际上,您需要一个虚拟构造函数 ,根据它正在装饰的类型创建正确类型的装饰器。 这需要一个工厂方法 ,即Decorate 它隐藏了为Tile创建的装饰器的细节,但是你的Terrain类必须知道它们可以被装饰。

如果其他类需要他们自己特殊类型的装饰器,我只会遇到这个设计的问题。 然后添加新类型和装饰将成为一个痛苦。 但对于一个或两个明确定义的案例,您的设计很好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM