【问题标题】:C++ separation data and logicC++ 分离数据和逻辑
【发布时间】:2015-05-28 06:02:42
【问题描述】:

我想以这种方式分离的原因 - 数据依赖于无,方法可以有数百个依赖关系。所有,谁依赖于数据不应该依赖于方法依赖。

我想做这样的事情:

//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) 静态转换向下转换未定义。

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

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

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

【问题讨论】:

  • Dieter Lücking,对不起。固定
  • “我要向所有用struct操作的人开放数据,而不是用class。” 你的意思是要向所有操作的类开放数据在数据上,您希望数据对类的用户隐藏?
  • 我的观点:逻辑或行为不能(理智地)用对象来表达。
  • 我的意思是,我想向所有使用该结构的人开放该结构的文件。但我想对所有与班级合作的人隐藏它。

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


【解决方案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,那么您还需要从 className 派生的 dclassName。但是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 消失了。这种方法是理想的,例如,如果您的结构数据是按需从数据库上传的。

【讨论】:

  • “我的意思是,我想向所有使用该结构的人开放该结构的文件。但我想对所有使用该类的人隐藏它。”
  • 而且我不能沮丧,因为正式地,它是 UB
  • 如果你想对所有对类进行操作的人隐藏它,你应该去私有继承。但随后不再垂头丧气。另一种方法是使用组合而不是继承(根据 className is 不是真的 a structName,但实际上 has-一个 structName)
  • @pvl 我添加了一个部分,其中包含使用合成改进设计的建议。
  • 谢谢!但我完全不明白 - 类对象是数据,所以 structNameObjectclassNameObject 是相同类型的对象。为什么没有琐碎的转换(为什么“数据类”和“函数类”之间没有等价关系(不是继承))?
猜你喜欢
  • 2018-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-04
  • 2019-06-07
  • 1970-01-01
相关资源
最近更新 更多