【C/C++ 规范系列 4】- 规避常见的陷阱

本文基于 wiki《 QT API Design Principles 》:

https://wiki.qt.io/Category:Developing_Qt::Documentation

1.常规陷阱(The Convenience Trap)

    一种常见的错觉,需要实现的代码越少,API就越好。请记住,代码编写不止一次,但必须一遍又一遍地理解。例如:

//bad code
QSlider *slider = new QSlider(12, 18, 3, 13, Qt::Vertical, 0, "volume");

    这条代码比下面的读起来要难得多(甚至写起来也更难):

 //god code
 QSlider *slider = new QSlider(Qt::Vertical);
 slider->setRange(12, 18);
 slider->setPageStep(3);
 slider->setValue(13);
 slider->setObjectName("volume");

2.布尔参数陷阱(The Boolean Parameter Trap)

    布尔类型的参数总是带来无法阅读的代码。给现有的函数增加一个bool型的参数几乎永远是一种错误的行为。

    仍以Qt为例,repaint()有一个bool类型的可选参数用于指定背景是否被擦除。可以写出这样的代码:

//bad code
widget->repaint(false);

    初学者很可能是这样理解的,『不要重新绘制!』,能有多少Qt用户真的知道下面3行是什么意思:

//bad code 
widget->repaint();
widget->repaint(true);
widget->repaint(false);

    更好的API设计应该是这样的:

//god code
widget->repaint();
widget->repaintWithoutErasing();

    在Qt 4中,我们通过移除了重新绘制(repaint)而不擦除widget的能力来解决了此问题。Qt 4的双缓冲使这种特性被废弃。

    还有更多这样的例子:(在现在的qt中已经找不到这样的代码了)

//bad code
widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding, true);
textEdit->insert("Where's Waldo?", true, true, false);
QRegExp rx("moc_''''''.c??", false, true);

    一个明显的解决方案是bool类型改成枚举类型。我们在Qt 4的QString中就是这么做的。对比效果如下:

 str.replace("USER", user, false); // Qt 3
 str.replace("USER", user, Qt::CaseInsensitive); // Qt 4

    如果真的不知道怎么做,请记住千万不要把 BOOL 设计成函数参数

3.案例

    为了在实践中展示这些概念,我们将研究Qt 3的QProgressBar API,并将其与Qt 4 API进行比较。

    在Qt 3:

class QProgressBar : public QWidget
{
    …
public:
    int totalSteps() const;
    int progress() const;

    const QString &progressString() const;
    bool percentageVisible() const;
    void setPercentageVisible(bool);

    void setCenterIndicator(bool on);
    bool centerIndicator() const;

    void setIndicatorFollowsStyle(bool);
    bool indicatorFollowsStyle() const;

public slots:
    void reset();
    virtual void setTotalSteps(int totalSteps);
    virtual void setProgress(int progress);
    void setProgress(int progress, int totalSteps);

protected:
    virtual bool setIndicator(QString &progressStr, int progress, int totalSteps);
    …
};

       该API相当的复杂和不一致;例如,reset()setTotalSteps()setProgress()是紧密联系的,但方法的命名并没明确地表达出来。

        改善此API的关键是抓住QProgressBar与Qt 4的QAbstractSpinBox及其子类QSpinBoxQSliderQDail之间的相似性。怎么做?把progresstotalSteps替换为minimummaximumvalue。增加一个valueChanged()消息,再增加一个setRange()函数。

       进一步可以观察到progressStringpercentageindicator其实是一回事,即是显示在进度条上的文本。通常这个文本是个百分比,但是可通过setIndicator()设置为任何内容。以下是新的API:

 virtual QString text() const;
 void setTextVisible(bool visible);
 bool isTextVisible() const;

      默认情况下,显示文本是百分比指示器(percentage indicator),通过重写text()方法来定制行为。

      Qt 3的setCenterIndicator()setIndicatorFollowsStyle()是两个影响对齐方式的函数。他们可被一个setAlignment()函数代替:

 void setAlignment(Qt::Alignment alignment);

       如果开发者未调用setAlignment(),那么对齐方式由风格决定。对于基于Motif的风格,文字内容在中间显示;对于其他风格,在右侧显示。

       下面是改善后的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);
    …
};

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值