C++分离数据和逻辑

C++ separation data and logic

本文关键字:数据 分离 C++      更新时间:2023-10-16

我之所以想用这种方式分离——数据从无到有,方法可以有一百个依赖项。所有依赖于数据的人不应该依赖于方法依赖性。

我想做一些类似的事情:

//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) 所有数据访问都已打开。我想向所有使用结构操作但不使用类的人打开数据。

2) 静态强制转换下转换未定义。

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

更新:我有另一个想法,但我无法解释为什么它很糟糕:

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

设计的可能实现:

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

 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) 您的结构无法正确实现多态性和继承:如果您有从StructName继承的数据结构dStructName,那么您还需要从className派生的dclassName。但dclassName已经继承了StructName。。。因此,这将是一个需要解决的非常微妙的问题,而对于传统的面向对象设计(将数据+方法封装到有意义的对象中),这只是小菜一碟。

改进的设计:

一种改进的方法是使用composition,因为你不能真的说classNamestructName,但你可以假装classNamestructName

然后,设计看起来有点像代理模式,为另一个对象提供代理来控制对它的访问(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就消失了。这种方法是理想的,例如,如果您的结构数据是根据需要从数据库上传的。