C ++分离数据和逻辑

时间:2015-03-24 19:08:04

标签: c++ design-patterns architecture dependencies dependency-management

我想以这种方式分离的原因 - 数据从无到有,方法可以有一百个依赖。所有依赖数据的人都不应该依赖于方法依赖。

我想做类似的事情:

//s_class_name.h
struct structName
{
    data m_data
}

//class_name.h
class className : public structName
{
public:
    void method(arg1, arg2, arg3, ..., argN); //using m_data
}

static_cast<className *>(&structNameObject)->method(arg1, arg2, arg3, ..., argN);

我看到两个问题:

1)打开所有数据访问。我想打开所有使用struct操作但不使用class的数据。

2)静态投射向下转换未定义。

你能解释一下,如何更好地实现模式数据和逻辑分离?

UPD:我有另一个想法,但我无法解释为什么它不好:

1)在s_class_name.h中,我可以声明模板方法
2)在class_name.h中,我可以实例化模板args。

1 个答案:

答案 0 :(得分:1)

可能实施您的设计:

避免使用数据形成未经授权访问的一种方法是保护数据:只有从数据结构继承的类才能访问它:

 class structName
 {
 protected:  // only classes inheriting from this structure can access the data
    data m_data;
 };

然后,从数据结构继承的类可以根据需要使用数据:

class className : public structName
{
public:
    void method(int arg1) { //using m_data
        for (int i = 0; i < arg1; i++)
            cout << i << ":" << m_data << endl; 
    }
};

你可以做以下事情:

className c;    // if your object was a class before 
structName*d=&c; 
static_cast<className *>(d)->method(10);  // you can downcast
               // if your object wasn't a class before, it's UB, but it could probably work if your class has not virtuals and no own data. 

此设计的弱点:

1)数据与逻辑的分离不允许对象封装。

2)数据的初始化必须由派生类完成。这意味着您必须处理系统的显式初始化,因为没有其他方法可以确保数据的一致性。

3)您可以将类链接到错误的数据结构。

4)一旦类继承自数据结构,任何其他类都可以从类继承,从而结束设计。

5)数据不依赖于任何事物的基本假设可能被证明是错误的。您提供的方法可能需要私有数据(例如,保存小计,以及您可能为了性能目的而保留的其他重新规范的冗余数据),这些数据与数据紧密相关。因此,数据还取决于您实现的方法。

6)您的结构无法正确实现多态和继承:如果您有一个继承自dStructName的数据结构StructName,那么您还需要一个dclassName派生的来自className。但是dclassName已经从StructName继承......所以它将是一个非常微妙的问题需要解决,而传统的面向对象设计(将数据+方法封装成有意义的对象)它是一块蛋糕。

改进设计:

改进的方法是使用合成,因为你不能说className structName,但你可以假装className structName

然后设计看起来有点像代理模式,提供另一个对象的代理来控制对它的访问(GoF)或装饰器,这取决于你如何看待它。

struct structName { data m_data; };

class className {
private: 
    structName *data;   // access to your data object 
public:
    className(structName *d) : data(d) {}  // constructor 
    void method(int arg1) { //using m_data
            cout << data->m_data << endl; 
    }
};

以下是一些可能的用途:

structName d; 
className cn(&d);        // creating an object 
cn.method(10);           // using methods on the data 
className(&d).method(3); // throw away temporary object destroyed when expression is evaluated. 
                         // so no need for down-casting anymore.  

通过这种设计,弱点1,4和6消失。这种方法是理想的,例如,如果您的结构数据是按需从数据库上传的。