设为首页 加入收藏

TOP

C++二进制输入输出流接口设计(二)
2015-07-20 17:59:09 来源: 作者: 【 】 浏览:10
Tags:二进制 输入 输出 接口 设计
ble这个方法,它返回了一个布尔值指示seek方法是否有效,有效表明这是一个可随机访问的流,无效则是顺序流。
?
我们没有采用这个方案,虽然少了一层继承关系看起来简单了,实际应用却并不比前面的方案简单。seekable在语义上是一种状态属性(有这个说法吗)表示对象的一类状态,一个布尔型可以表示两种状态,每增加一个则应用复杂度就翻一倍,呈指数增长(不要信我,我随口乱说的)。这里虽然只有一个状态属性,但已经足以给我们造成不少的困扰了:
?
seekable返回的状态究竟是暂时的还是永久的?是否可能中途改变?至少我们从接口上看不出答案;
如果seekable返回false,仍然调用了seek方法会怎样?
一个顺序流的派生类根本不需要但还是要实现seekable和seek两个方法,哪怕只是简单的返回false和抛出异常;
使用者每次试图调用seek方法前都要先调用seekable判断一下,最后会有一堆的if-else;
上面的问题也是胖接口固有的问题,所以一定要慎重使用胖接口,这次我们选择了抛弃。 ? ? ? 把各种派生类和各种辅助类都加上,得到最终的结构图: ? ? ? ??
?至此,我们的工作已基本完成,剩下的都是无聊的体力活。
?
input_stream和random_istream接口:
?
复制代码
?1 class input_stream
?2 {
?3 public:
?4 ? ? virtual void ? ? ? ?read(void* buffer, uint32_t bytes) ? ? ? ? ? ? ? ? ?= 0;
?5 ? ? virtual void ? ? ? ?skip(uint32_t bytes) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0;
?6 ? ? virtual uint64_t ? ?tell() const ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0;
?7 };
?8?
?9?
10 class random_istream : public input_stream
11 {
12 public:
13 ? ? virtual void ? ? ? ?seek(int64_t offset, seek_origin origin) ? ? ? ? ? ?= 0;
14 ? ? virtual uint64_t ? ?size() const ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0;
15 };
复制代码
?注意skip方法,这个方法用于在顺序读入时跳过指定字节数,其功能也可以通过read后丢弃数据的方式实现,在random_istream中则可以直接使用seek方法实现,最终决定加入这个方法主要是为了使用方便,在效率上则与当前流的最优替代方式相当。
?
?
?
output_stream和random_ostream:
?
复制代码
?1 class output_stream
?2 {
?3 public:
?4 ? ? virtual void ? ? ? ?write(void* buffer, uint32_t bytes) ? ? ? ? ? ? ? ? ? ?= 0;
?5 ? ? virtual void ? ? ? ?flush() ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0;
?6 ? ? virtual uint64_t ? ?tell() const ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? = 0;
?7 };
?8?
?9 class random_ostream : public output_stream
10 {
11 public:
12 ? ? virtual void ? ? ? ?seek(int64_t offset, seek_origin origin) ? ? ? ? ? ? ? = 0;
13 };
复制代码
?
?
binary_reader和binary_writer两个类是对input_stream和output_stream的扩展,采用外部扩展的方式相对于继承扩展更加灵活。如果用继承扩展的话binary_reader究竟从input_stream还是random_istream继承呢,或者是把binary_reader设计成独立的接口类,实现类比如file_istream同时继承binary_reader和random_istream呢?这些都是让人纠结的问题,并且每一种方案都不完美。外部扩展的方式则堪称完美,实现起来也简单,只要给binary_reader塞一个input_stream的指针就可以了,用起来就像下面这个样子:
?
复制代码
?1 input_stream* ist = ...
?2?
?3 binary_reader ?reader(ist);
?4?
?5 int v1 = reader.read_uint8();
?6?
?7 reader.skip(4);
?8 int v2 = reader.read_uint16_be();
?9 ...
10?
11 // seek操作也可以支持
12?
13 random_istream* ist = ...
14?
15 binary_reader ?reader(ist);
16?
17 int v1 = reader.read_uint8();
18?
19 ist->seek(4, see_origin::current);
20 int v2 = reader.read_uint16_be();
21 ...
复制代码
?
?
binary_reader的完整声明大体如下,binary_writer与之类似:
?
复制代码
?1 class binary_reader
?2 {
?3 public:
?4 ? ? binary_reader(input_stream* stream);
?5?
?6 ? ? void read(void* buffer, uint32_t read_bytes);
?7 ? ? void skip(uint32_t offset);
?8?
?9 ? ? uint64_t tell() const;
10?
11 ? ? uint8_t read_uint8();
12?
13 ? ? uint16_t read_uint16_be();
14 ? ? uint32_t read_uint24_be();
15 ? ? uint32_t read_uint32_be();
16 ? ? uint64_t read_uint64_be();
17?
18 ? ? uint16_t read_uint16_le();
19 ? ? uint32_t read_uint24_le();
20 ? ? uint32_t read_uint32_le();
21 ? ? uint64_t read_uint64_le();
22?
23 ? ? ? ? ....
24?
25 private:
26 ? ? input_stream* ? ?_stream;
27 };
复制代码
?
?
……
?
花了一周的业余时间总算把这一篇写完了,
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇HDU 4911 Inversion(归并求逆序对) 下一篇HDU - 4911 Inversion

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: