我正在阅读Martin Fowler关于对象关系结构模式的PoEAA。作为学习它们时要做的一个项目,我想我应该用C++构建一个迷你eCommerce系统。我很难弄清楚如何从映射器返回对象。
我有一个Product基类,它具有派生类Hat和Shirt。Products有一个type成员来标识它们是哪个派生类。我还有一个带有派生类HatMapper和ShirtMapper的ProductMapper类,所有这些类都实现了一组查找器方法,使我可以尝试检索某些帽子和衬衫。
class Product
{
unsigned long long int id;
std::string name;
unsigned int type;
};
// Derived classes don't necessarily have the same members.
class Hat : public Product
{
unsigned char fitted;
unsigned char color;
unsigned char style;
};
class Shirt : public Product
{
unsigned char size;
};在我的应用程序的逻辑部分中,我要实例化这些映射器并检索产品,这是我遇到问题的地方。我可以毫不费力地实例化一个HatMapper并拉回Hat对象,ShirtMapper和Shirt对象也是如此。这些模式在这些情况下工作得很好(特别是我使用类表继承,即一个包含产品数据的product表,一个包含特定于帽子的数据的hats表,以及一个包含特定于衬衫数据的衬衫的表)。
我的问题是,如果我想检索所有产品,包括帽子和衬衫,我该怎么办?我可以实例化ProductMapper并获取所有产品数据,但这似乎是错误的方法,因为我必须遍历检索到的所有Products,并根据程序逻辑部分中的类型构建Hats和Shirts。此外,当我添加新的产品类型时,我必须修改任何以这种方式处理这种情况的代码。看起来很糟糕。
Fowler的书中有使用派生映射器的映射器的示例,这在我看来是完全错误的(每次我添加新产品时都必须修改基映射器,这不是很好)。这里有一个简单的例子,说明它是如何在那里完成的:
class ProductMapper
{
unsigned long long int productId;
unsigned long long int productType;
HatMapper * hm;
ShirtMapper * sm;
Product * FindById(unsigned long long int id)
{
// Query database for data.
if (this->productType == PRODUCT_TYPE_HAT)
{
return hm->FindById(id); // Hat object.
}
else if (this->productType == PRODUCT_TYPE_SHIRT)
{
return sm->FindById(id); // Shirt object.
}
return NULL;
}
};下面是我如何在我的程序的逻辑部分使用它。书中没有提供这样的例子:
ProductMapper * pm = new ProductMapper();
Product * p = pm->FindById(1); // It's a Product, but a Hat or Shirt?
// Have to check type since a Product was returned.
switch (p->type)
{
case PRODUCT_TYPE_HAT:
{
Hat * h = (Hat) p;
break;
}
// Etc. Modify this every time a new product type is added or removed.
}这将引入循环依赖。此外,假设我以某种方式消除了循环依赖,HatMapper和ShirtMapper类的结果是Hat对象和Shirt对象。因此,当我从ProductMapper返回时,我将向下转换,因此我必须再次在我的逻辑中操作结果,这再次引入了当我引入新产品类型时修改代码的问题。
我不知道该怎么办。在理想的情况下,我希望有一个Product类和一个ProductMapper类,我可以快速扩展这两个类,在不修改现有代码的情况下引入新的产品类型(至少修改太多)。
我希望能够使用PoEAA中的这些模式,它们看起来确实很好和有用,但我不确定这是否只是我在C++中不能做的事情,或者我错过了一些阻止我这样做的东西。替代的模式和方法也非常受欢迎。
发布于 2014-07-30 15:38:55
在这种情况下,感觉Type Object pattern可能会有所帮助,我知道这个链接是关于游戏编程的,但将该模式应用于其他领域就足够了。
现在的问题是,如果你想添加产品,你必须添加几个类,正如你注意到的,这可能会变得很难维护。
编辑:也许你可以使用这样的东西(代码是C++11,以简化示例):
class ProductProperty
{
typedef std::map<std::string, unsigned char> PropertyMap;
PropertyMap properties;
public:
ProductProperty(std::initializer_list<PropertyMap::value_type> il):
properties(il)
{}
// Use of at() is intended to only deal with the defined properties
const PropertyMap::value_type::second_type&
get(const PropertyMap::value_type::first_type& prop) const
{
return properties.at(prop);
}
PropertyMap::value_type::second_type&
get(const PropertyMap::value_type::first_type& prop)
{
return properties.at(prop);
}
};
// Some helpers to illustrate
std::shared_ptr<ProductProperty> makeHatProperty()
{
return std::make_shared<ProductProperty>(
ProductProperty{
{"fitted", ***whatever**},
{"color", ***whatever**},
{"style", ***whatever**}
});
}
std::shared_ptr<ProductProperty> makeShirtProperty()
{
return std::make_shared<ProductProperty>(
ProductProperty{{"size", ***whatever**}}
);
}
class Product
{
unsigned long long int id;
std::string name;
unsigned int type;
std::shared_ptr<ProductProperty> properties;
public:
Product(std::shared_ptr<ProductProperty> props):
properties(props)
{}
// Whatever function you need to get/set/check properties
};https://stackoverflow.com/questions/25030800
复制相似问题