如何在公共API接口类中将auto getter和setter与PIMPL设计模式相结合

q09*_*987 0 c++ design-patterns

//////////////////////////////////////////////////////////////////////////////////////////
// Note: Automatically generate getter and setter
template<typename T>
class Wrap {
public:
  ...
  const T& operator()() const 
  { 
    return m_element; 
  }

  void operator()(const T& element)
  {
    m_element = element;
  }
  ...

private:
  T m_element;
};

// Pro:  The container may have more than 20 different member variables.
//       Each goes with a simple getter and setter for now. Due to the Wrap
//       class, we don't have to add getter and setter for any new variable
// Con:  Since this is a public API interface, if the user directly adopt the
//       Wrap class, it is difficult for any future improvement. Based on this design,
//       we cannot make Wrap private embeded class of Container since the user needs to 
//       access those public member variables of Container
class Container
{
public:
  Wrap<int>         Age;
  Wrap<double>      Balance;
  ...
};

//////////////////////////////////////////////////////////////////////////////////////////
// Con: For each different member variable, we have to add getter and setter methods
//       which will be a problem considering if you have 20 member variables.
// Pro:
//       By using PIMPL pattern, we can make the interface more robust for future improvement
//       without breaking our client's code.
class PimplClass
{
public:
    int Age() const;
    PimplClass& Age(int _age);

    double Balance() const;
    PimplClass& Balance(double _balance);

private:
    Pimpl* m_data; // hide internal data structure from the public API interface
};
//////////////////////////////////////////////////////////////////////////////////////////
Run Code Online (Sandbox Code Playgroud)

问题 >有没有更好的设计我可以将自动getter + setter生成和PIMPL设计模式结合到这个公共API接口中?

谢谢

// ******更新************

在阅读完所有这些文章之后,我确信吸气鬼和二传手都是邪恶的.现在问题是如何一起避免它们.

例如,

class Bond
{
    ...

private:
    long m_lPrice;
    std::string m_strBondName;
    int  m_iVolume;
}
Run Code Online (Sandbox Code Playgroud)

给出Bond包含三个成员变量的上述类,而不使用getter和setter,客户端如何获取债券对象的价格,名称或数量?

这是Qt4中getter/setter的另一个例子.

这是改进的QProgressBar API:

class QProgressBar : public QWidget
{
    ...
public:
    void setMinimum(int minimum);
    int minimum() const;
    void setMaximum(int maximum);
    int maximum() const;
    void setRange(int minimum, int maximum);
    int value() const;

    virtual QString text() const;
    void setTextVisible(bool visible);
    bool isTextVisible() const;
    Qt::Alignment alignment() const;
    void setAlignment(Qt::Alignment alignment);

public slots:
    void reset();
    void setValue(int value);

signals:
    void valueChanged(int value);
    ...
};
Run Code Online (Sandbox Code Playgroud)

谢谢

sbi*_*sbi 8

吸气剂和二传手都在那里,这样你就可以"抓住"对象的内脏并摆弄它的内脏.这应该会让你的警钟响得很响.对于设计良好的类,您不必深入了解它的内容,因为它允许您通过其界面 执行您需要执行的所有操作,而不会通过抽象泄漏任何实现细节.

类的用户的角度设计一个类("如果我有一个qrxl对象,我需要wrgl()像这样做,我还需要lrxl偶尔传递一个对象,然后用它做frgl()")而不是从实施者的角度来看,他需要以某种方式将他的数据和算法组织成有用的(对他来说)块.("让我们把这个Johnny放在这个类中,因为这就是我需要它来实现xrxl()算法的地方.")

我认为在这方面,Java对人类造成了极大的伤害,因为它要求你把所有东西放到某个类中,即使这与你在脑中实际想象你的设计的方式有关,即使你还没有思考面向对象.这似乎使得设计风格变得流行,程序员只是把所有东西都塞进某个类的某个地方,因为"这就是它的完成方式".
在许多Java代码中,我看到底层编程风格实际上是结构化编程(基本上是"将数据收集到有用的块中,并将其传递给您的算法",如C或Pascal中所做的那样),而不是面向对象编程.仅仅因为你替换struct/ recordby class并使这个块中的数据成员只能通过getter和setter访问,这并不意味着你正在进行面向对象的编程.1这就是那篇精彩短文的作者所谓的伪类

从我对Qt的了解很少,它的设计也是一个非常好的例子,一个非常糟糕的例子,所有的东西都分配在堆上,用赤裸的指针传递,并采用准类学校的设计.


给出Bond包含三个成员变量的上述类,而不使用getter和setter,客户端如何获取债券对象的价格,名称或数量?

这是一个错误的问题.正确的问题是为什么用户需要获得这些值?如果您需要手动获取它们,那么Bond对于OO设计而言,它不够高,它只是C风格struct,您可以在一个地方将所需的所有数据放在一起.问你自己:

Bond想要对这样一个对象做什么的用户会怎样?我怎样才能让这个类支持那些操作,而无需用户抓住它并摆弄它的胆量?如何使与之交互的类Bond执行此操作?我可以传递它们的Bond对象,而不是债券对象的价格,名称或数量吗?

是的,有时你必须只有一个债券的价格才能显示它,如果是这样,那么Bond需要支持价格的吸气功能,那就好了.但你仍然可以将一个Bond对象传递给你BondPriceTabledisplayBonds()函数,让它决定是否只想获取名称和价格并将其抛出到屏幕上或显示更多值.无需手动提取名称和价格并将其传递给display()函数.


1 这是骇人听闻尤其因为Java爱好者经常低头看C++的不是"纯粹OO".