何为流畅接口?先上代码String(“1”)(“2”)(“3”)(“4”)(“5”)。流畅接口从字面上看是用起来很顺手,究竟是有多顺手,又应用在哪里呢?相信你看完本文多少会有些答案了。
以自定义String类(继承QString)为例。
1 | class String : public QString { |
当我们需要往String增加字符串时我们常规做法:1
2
3
4
5
6String str;
str.append("1");
str.append("2");
str.append("3");
str.append("4");
str.append("5");
感觉上面起来都有些啰嗦,看了下QString文档,QString的append接口调用后返回自己的引用,那么就可以这样写。1
2
3
4
5
6String str;
str.append("1")
.append("2")
.append("3")
.append("4")
.append("5");
在这里看来,append接口就是流畅接口了,它避免啰嗦的调用。
头铁君这时候跳出来说,Qt君啊,你还是失算了。我还有更流畅的做法,你看:1
2
3
4
5String &operator()(const QString &str)
{
append(str);
return *this;
}
通过String类重载()
操作符后我还可以这样做:1
String("1")("2")("3")("4")("5");
头铁君向我投来得瑟的目光,看得我瑟瑟发抖。
头铁君啊,你别老是这么头铁,看来我要放大招了。你那做法那里是流畅接口的精神啊,看到那么多括号都怕了,你别说这是给别人用?!
头铁君,来看看我的做法吧。1
2
3
4
5String &operator<<(const QString str)
{
append(str);
return *this;
}
通过重载<<
操作符做出类似管道效果的流畅接口。1
2String str;
str << "1" << "2" << "3" << "4" << "5";
头铁君看了不感惊叹,还真是比我那堆括号好用啊。就是看起来有些眼熟的呀。哦,对了。原来和qDebug()
原理相似的呀。1
qDebug() << "1" << "2" << "3" << "4" << "5";
头铁君出了名是头铁,还有其他的应用场合吗?
来来来,别急。我们再看下QString的arg()
接口的使用。1
2
3
4
5
6
7QString fileName;
QString size;
QString md5;
QString status = QString("File Info: file name: %1; size: %2; checksum md5: %3")
.arg(fileName)
.arg(size)
.arg(md5);
头铁君若有所思一会,立马打开电脑查了起来。看着头铁君桌面的卡布奇诺都凉了,他还在查。看起来冻的卡布奇诺更有味道,感觉就是太甜了。
哦,原来是这样啊。这不就是Builder模式吗?通过返回自己的引用或指针来实现流式(链式)编程。明白了,头铁君抬头看到我喝着他的卡布奇诺,为了避免尴尬,说了一句,今天天气不错哈。
从流畅接口(Builder模式)到只读对象的实现。
Network类只提供获取ip,mask,gateway,dns的方法,而设置方法都被隐藏起来了。而真正实现设置网络属性是通过NetworkBuilder类来进行操作。并可以通过它来体现流畅接口。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28class NetworkBuilder;
class Network {
public:
Network();
static NetworkBuilder builder();
QString ip() const;
QString mask() const;
QString gateway() const;
QString dns() const;
private:
friend NetworkBuilder;
QString m_ip;
QString m_mask;
QString m_gateway;
QString m_dns;
};
class NetworkBuilder {
public:
NetworkBuilder &ip(const QString &ip);
NetworkBuilder &mask(const QString &ip);
NetworkBuilder &gateway(const QString &gateway);
NetworkBuilder &dns(const QString &dns);
Network build();
};
通过NetworkBuilder构建Network属性后通过build的调用返回Network对象。1
2
3
4
5Network::builder().ip("192.168.1.1")
.mask("255.255.255.0")
.gateway("192.168.1.1")
.dns("8.8.8.8")
.build();
现实意义:
- 通过只读对象来限定接口使用者的乱用行为;
- 明确确定设置参数后需要调用build接口生效,这就意味着可以提醒接口调用者生效了那些参数。
- 可以体现出清晰明确的编程。
- 让接口调用者用来顺手(流畅)。
文章首发微信公众号Qt君。