本章讲的是一个简单的打印案例,完全可用几行代码来完成,而面对问题不断复杂化,我们发现修改过程式的代码不足以支撑需求的多变。
作者构造了Picture类,汇总需求细节,见招拆招,尤其在“接口设计”这一节里,把自己当成客户,跟自己一问一答(“我希望有些什么操作,如何表述这些操作?”),逐步分析不断复杂的需求,然后抽象出接口,其中不乏作者的经验之谈:要想决定具体操作的形式,有一个好办法,就是试着使用这些操作,从使用的例子推导出操作的定义形式要比从头苦思冥想地发明这些操作容易得多。
1、最初需求是打印如下文字:
Paris
in the
Spring
2、构造的Picture类,只需要一个构造函数和一个输出即可完成,如果打印如下文字:
+-------+
|Paris |
|in the |
|Spring|
+-------+
3、如果使用C式的过程代码,需要做些打印内容的改变可以完成,作者为Picture类添加了一个frame(Picture&)来完成,如果打印内容改变了,我想C式代码作者就会抓头皮了:
Paris +-------+
in the |Paris |
Spring|in the |
|Spring|
+-------+
4、Picture类便有了 Picture operator |(const Picture&, const Picture&) 接口,用字符‘|’做两个Picture对象的横向合并,用Picture operator &(const Picture&,const Picture&)接口,用字符‘&’做纵向合并,当我们需要打印如下文字的时候:
+--------------+
|+------+ |
||Paris | |
||in the| |
||Spring| |
|+------+ |
|Paris +------+|
|in the|Paris ||
|Spring|in the||
| |Spring||
| +------+|
+--------------+
我们只需要一句 cout << frame(frame(p) & (p | frame(p))) << endl即可完成。
下面是Picture类的源码(原书代码中有些许错误,均做过修改和测试):
1 #include <ioStream>
2
3
4 using namespace std;
5
6 class Picture
7 {
8 friend Picture frame(const Picture&); //加框
9 friend Picture operator&(const Picture&, const Picture&); //纵向合并
10 friend Picture operator|(const Picture&, const Picture&); //横向合并
11 friend ostream& operator << (ostream& o, const Picture& p);
12 private:
13 int height, width;
14 char* data;
15 char& position(int row, int col){
16 return data[row * width + col];
17 };
18 char position(int row, int col) const{
19 return data[row * width + col];
20 };
21 void copyblock(int,int,const Picture&);
22 public:
23 Picture() : height(0),width(0),data(0){};
24 Picture(const char* const*, int);
25 Picture(const Picture& );
26 ~Picture();
27 Picture& operator=(const Picture&);
28 static int max(int m, int n)
29 {
30 return m > n ? m : n;
31 };
32 void init(int h, int w);
33 void clear(int , int ,int ,int );
34 };
35
36 ostream&
37 operator << (ostream& o, const Picture& p)
38 {
39 for(int i = 0; i < p.height; ++i)
40 {
41 for(int j =0; j < p.width; ++j)
42 o << p.position(i,j);
43 o << endl;
44 }
45 return o;
46 };
47
48
49 void Picture::init(int h, int w)
50 {
51 height = h;
52 width = w;
53 data = new char[height * width];
54 };
55
56 Picture::Picture(const char* const* array, int n)
57 {
58 int w = 0;
59 int i ;
60 for(i = 0; i < n; i++)
61 w = Picture::max(w, strlen(array[i]));
62 init(n,w);
63 for(i = 0; i < n; i++)
64 {
65 const char* src = array[i];
66 int len = strlen(src);
67 int j = 0;
68 while(j < len)
69 {
70 position(i,j) = src[j];
71 ++j;
72 }
73 while(j < width)
74 {
75 position(i, j) = ' ';
76 ++j;
77 }
78 }
79 }
80
81 Picture::Picture(const Picture& p):
82 height(p.height), width(p.width),
83 data(new char[p.height * p.width])
84 {
85 copyblock(0,0,p);
86 }
87
88 Picture::~Picture()
89 {
90 delete []data;
91 }
92
93 Picture& Picture::operator=(const Picture& p)
94 {
95 if(this != &p)
96 {
97 delete []data;
98 init(p.height,p.width);
99 copyblock(0,0,p);
100 }
101 return *this;
102 }
103
104 void Picture::copyblock(int row,int col,const Picture& p)
105 {
106 for(int i =0; i < p.height; ++i)
107 {
108 for(int j =0; j < p.width; ++j)
109 position(i+row, j+col) = p.position(i,j);
110 }
111 }
112
113 void Picture::clear(int h1,int w1,int h2,int w2)
114 {
115 for(int r = h1; r < h2; ++r)
116 for(int c = w1; c < w2; ++c)
117 position(r,c) = ' ';
118 }
119
120 Picture frame(const Picture& p)
121 {
122 Picture r;
123 r.init(p.height + 2, p.width + 2);
124 for(int i = 1; i < r.height -1; ++i)
125 {
126 r.position(i,0) = '|';
127 r.position(i, r.width - 1) = '|';
128 }
129 for(int j = 1; j < r.width - 1; ++j)
130 {
131 r.position(0, j) = '-';
132 r.position(r.height - 1, j) = '-';
133 }
134 r.position(0, 0) = '+';
135 r.position(0, r.width-1) = '+';
136 r.position(r.height-1, 0)= '+';
137 r.position(r.height-1,r.width-1)='+';
138 r.copyblock(1,1,p);
139 return r;
140 }
141
142 Picture operator&(const Picture& p, const Picture& q)
143 {
144 Picture r;
145 r.init(p.height + q.height, Picture::max(p.width ,q.width));
146 r.clear(0,p.width,p.height,r.width);
147 r.clear(p.height,q.width,r.height,r.width);
148 r.copyblock(0,0,p);
149 r.copyblock(p.height,0,q);
150 return r;
151 }
152
153 Picture operator|(const Picture& p, const Picture& q)
154 {
155 Picture r;
156 r.init(Picture::max(p.height,q.height),p.width + q.width);
157 r.clear(p.height,0,r.height,q.width);
158 r.clear(q.height,p.width,r.height,r.width);
159 r.copyblock(0,0,p);
160 r.copyblock(0,p.width,q);
161 return r;
162 }
测试代码:
1 char *init[]= {"Paris","in the","Spring"};
2 Picture p(init,3);
3 cout << frame(frame(p) & (p | frame(p))) << endl;