基于各个属性/访问器的聚合设计类层次结构

时间:2016-03-20 00:36:29

标签: c++ design-patterns data-structures

我正在设计一个包含可提供对数据库行的访问的类的库。基础数据保存在map中,其中value是union类型。考虑以下基类:

class dbObject
{
    protected:
    // Get and set property values using generic name for property
    union_type GetPropertyValue(string property_name);
    void SetPropertyValue(string property_name, union_type value);

    // Add mapping from generic property name to column name
    void AddPropertyMapping(string property_name, string column_name);

    private:
    map<property_name, column_name>
    map<column_name, union_type>
};

需要继承自dbObject的每个类
  • 为需要访问的列添加属性映射
  • 为其属性提供访问者

这样,呈现给库用户的最终接口类具有适当的访问器并隐藏了底层结构/实现。这里的动机是大多数类共享相同数据的大部分,因此我们希望它们继承访问器和映射设置代码,而不是为每个类单独编写它们。最初我构建的派生类每个都包含一些共享访问器,例如:

class dbDerivedObjectOne : dbObject
{
    public:
    int GetPropertyOne();
    void SetPropertyOne(int value);
    string GetPropertyTwo();
    void SetPropertyTwo(string value);
};

class dbDerivedObjectTwo : dbDerivedObjectOne 
{
    public:
    double GetPropertyThree();
    void SetPropertyThree(double value);
    int GetPropertyFour();
    void SetPropertyFour(int value);
};

// This is the API class which is presented to the library user
// It has inherited all the necessary accessors and setup code
class dbInterfaceClass : dbDerivedObjectTwo
{
};

正如您所看到的,这个层次结构因此基于叶子/接口类需要的访问器而不是真实的&#34; is-a&#34;你希望在适当的设计中看到的关系。它还会导致一些问题,即某些类需要访问已在父类中公开的某些属性子集,但不希望公开父类中的所有属性,因为其中一些属性是无意义/不存在的对于派生类。

如果没有一个已知的设计模式可供参考,我目前倾向于一个重构,它涉及将派生类分解为单个属性类并使用多重继承来构建接口类。

class dbObjectProperty
{
    union_type GetProperty(string property_name)
    void SetProperty(string property_name, union_type value)
};

class dbPropertyOne : dbObjectProperty
{
    // calls dbObjectProperty::GetProperty() with its property name
    // returns the int from the union_type
    int GetPropertyOne();

    // wraps the int in a union_type
    // calls dbObjectProperty::SetProperty() with its property name
    int SetPropertyOne(int value);
};

class dbPropertyTwo : dbObjectProperty
{
    // calls dbObjectProperty::GetProperty() with its property name
    // returns the string from the union_type
    string GetPropertyTwo();

    // wraps the string in a union_type
    // calls dbObjectProperty::SetProperty() with its property name
    void SetPropertyTwo(string value);
};

class InterfaceClassOne : dbPropertyOne, dbPropertyTwo
{
    // exposes all of the accessors from its parent classes
}

这个解决方案更加精细,允许我将每个接口类构建为一组(可能共享的)属性,每个属性都提供自己的访问器/更改器。但是,实际的实现将涉及从25-30个不同的属性类继承的类,这看起来像一个可怕的多继承设计。而且,这似乎是对继承概念的滥用。接口类并不真正适合&#34;是&#34;与dbObjectProperty的关系,而不是它们实际上是一个集合,我们滥用多重继承,以避免重复访问代码。

问题:

  1. 我应该看一下这种结构的既定设计模式吗?
  2. 是否有其他/更好的方法来解决此问题,同时避免重复访问代码?
  3. 多重继承解决方案是考虑到糟糕/危险的设计,还是仅仅是C ++的本质迫使我滥用系统来实现一种在较不严格的语言中更容易的东西?

1 个答案:

答案 0 :(得分:1)

因此,根据我的理解,您正试图为自己节省一些打字工作。我会建议一个宏观,但我不是那些专家;),所以我甚至不知道它们是否可以工作(尽管可能值得研究)。

我确实找到了另一种解决方案,这是一个简化的例子(vc ++):

template<typename T>
class Property {
private:
    std::map<std::string, union_type>& map_ref;
    const std::string name;
public:
    Property(std::map<std::string, union_type>& my_map, std::string&& name) : map_ref(my_map), name(name) {}

    T Get() const {
        return static_cast<T>(map_ref[name]);
    }

    void Set(T new_value) const {
        map_ref[name] = static_cast<union_type>(new_value);
    }
};

class MyObject {
private:
    std::map<std::string, union_type> my_map;
public:
    const Property<int> my_int{ my_map, "my_int" };
};

我不清楚你是如何从union_type转到别人的,所以我在这里用静态演员表示。

这样做的缺点是获取和设置需要更多的努力。 my_object.my_int.Get()。不过,它应该可以节省一些工作,而不必输入每个吸气剂和制定者。

这样做的好处是,您仍然可以使用实际的属性名称进行访问,而不仅仅是PropertyOne,PropertyTwo等。(其中,imho,很不错......)