-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
598 lines (314 loc) · 459 KB
/
atom.xml
File metadata and controls
598 lines (314 loc) · 459 KB
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>枪口下的砚台</title>
<subtitle>所谓拥有,皆非束缚;所有过往,皆为序章。</subtitle>
<link href="https://syshlang.com/atom.xml" rel="self"/>
<link href="https://syshlang.com/"/>
<updated>2020-10-22T01:47:24.603Z</updated>
<id>https://syshlang.com/</id>
<author>
<name>syshlang</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>设计模式之结构型模式中的桥接模式(Bridge Pattern)</title>
<link href="https://syshlang.com/62f7f6a4/"/>
<id>https://syshlang.com/62f7f6a4/</id>
<published>2020-05-30T12:56:21.000Z</published>
<updated>2020-10-22T01:47:24.603Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/62f7f6a4/Bridge.png" class="" title="Bridge Pattern"><a id="more"></a><h1 id="一、基本介绍"><a href="#一、基本介绍" class="headerlink" title="一、基本介绍"></a>一、基本介绍</h1><blockquote><p>    桥接模式(Bridge Pattern)是一种结构型设计模式,基于类的最小设计原则,通过使用封装、聚合及继承等方式让不同的类承担不同的职责,从而把抽象(Abstraction)和实现(Implementation)分离开放在不同的层次中,使得各部分保持独立更加利于扩展。一句话来说,就是在抽象与实现之间提供一个桥梁,降低二者耦合度,达到二者可以独立变化而不互相影响的目的。</p></blockquote><h1 id="二、从“类爆炸”说起"><a href="#二、从“类爆炸”说起" class="headerlink" title="二、从“类爆炸”说起"></a>二、从“类爆炸”说起</h1><p>     <span class="github-emoji" alias="chestnut" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f330.png?v8">🌰</span> 假如,现在有这样一个业务场景,需要对不同颜色不同品牌的手机实现相应的功能,如打电话、发短信、上网等。<br>    如果使用传统的方式,可能是这样的,类图如下:</p><img src="/62f7f6a4/Bridge1.png" class="" title="传统方法对应的类图"><blockquote><p>    从以上的类图中,可以看出存在的问题,首先,这种方式会带来扩展性的问题,随着功能和手机品牌的增加,需要维护的类的数量也会增加,扩展性极差<span class="github-emoji" alias="confounded" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f616.png?v8">😖</span>,产生“类爆炸”;其次,从类的最小设计原则考虑,当需要手机的颜色时,同时还需增加所有品牌的手机,这种设计违反了<a href="/934a08a4/" title="单一职责原则">单一职责原则</a>。</p></blockquote><h1 id="三、桥接模式"><a href="#三、桥接模式" class="headerlink" title="三、桥接模式"></a>三、桥接模式</h1><p>    那么,基于以上两点的考虑,借鉴单一职责原则的核心思想,尝试将对象解耦,将类的功能职责粒度分解细化,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。</p><h2 id="3-1-采用桥接模式解决问题"><a href="#3-1-采用桥接模式解决问题" class="headerlink" title="3.1 采用桥接模式解决问题"></a>3.1 采用桥接模式解决问题</h2><ul><li><p>定义手机品牌接口</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 手机品牌接口</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">PhoneBrand</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Call.</span></span><br><span class="line"><span class="comment"> * 打电话</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">call</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Send message.</span></span><br><span class="line"><span class="comment"> * 发短信</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Go online.</span></span><br><span class="line"><span class="comment"> * 上网</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>不同品牌手机接口的接口实现</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> * HuaWei品牌接口实现</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HuaWeiPhoneBrandImpl</span> <span class="keyword">implements</span> <span class="title">PhoneBrand</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"Call use HuaWei phone."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"SendMessage use HuaWei phone."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"GoOnline use HuaWei phone."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> * Apple品牌接口实现</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ApplePhoneBrandImpl</span> <span class="keyword">implements</span> <span class="title">PhoneBrand</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"Call use Apple phone."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"SendMessage use Apple phone."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"GoOnline use Apple phone."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> * XiaoMi品牌接口实现</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">XiaoMiPhoneBrandImpl</span> <span class="keyword">implements</span> <span class="title">PhoneBrand</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"Call use XiaoMi phone."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"SendMessage use XiaoMi phone."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"GoOnline use XiaoMi phone."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>创建手机这个抽象类,即“桥”</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> * 手机抽象类 相当于“桥”</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Phone</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * PhoneBrand 类聚合</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> PhoneBrand phoneBrand;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Phone</span><span class="params">(PhoneBrand phoneBrand)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> <span class="keyword">this</span>.phoneBrand = phoneBrand;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.phoneBrand.call();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.phoneBrand.sendMessage();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.phoneBrand.goOnline();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>不同颜色的具体手机</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The type Phone black.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhoneBlack</span> <span class="keyword">extends</span> <span class="title">Phone</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Instantiates a new Phone black.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> phoneBrand the phone brand</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">PhoneBlack</span><span class="params">(PhoneBrand phoneBrand)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>(phoneBrand);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.call();</span><br><span class="line"> System.out.println(<span class="string">"The phone of call is Black."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.sendMessage();</span><br><span class="line"> System.out.println(<span class="string">"The phone of sendMessage is Black."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.goOnline();</span><br><span class="line"> System.out.println(<span class="string">"The phone of goOnline is Black."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The type Phone red.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhoneRed</span> <span class="keyword">extends</span> <span class="title">Phone</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Instantiates a new Phone red.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> phoneBrand the phone brand</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">PhoneRed</span><span class="params">(PhoneBrand phoneBrand)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>(phoneBrand);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.call();</span><br><span class="line"> System.out.println(<span class="string">"The phone of call is Red."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.sendMessage();</span><br><span class="line"> System.out.println(<span class="string">"The phone of sendMessage is Red."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.goOnline();</span><br><span class="line"> System.out.println(<span class="string">"The phone of goOnline is Red."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The type Phone white.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhoneWhite</span> <span class="keyword">extends</span> <span class="title">Phone</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Instantiates a new Phone white.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> phoneBrand the phone brand</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">PhoneWhite</span><span class="params">(PhoneBrand phoneBrand)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>(phoneBrand);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.call();</span><br><span class="line"> System.out.println(<span class="string">"The phone of call is White."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.sendMessage();</span><br><span class="line"> System.out.println(<span class="string">"The phone of sendMessage is White."</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goOnline</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.goOnline();</span><br><span class="line"> System.out.println(<span class="string">"The phone of goOnline is White."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>客户端调用</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The type Client.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Bridge test.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">bridgeTest</span><span class="params">()</span> </span>{</span><br><span class="line"> PhoneRed phoneRed = <span class="keyword">new</span> PhoneRed(<span class="keyword">new</span> HuaWeiPhoneBrandImpl());</span><br><span class="line"> phoneRed.call();</span><br><span class="line"> phoneRed.sendMessage();</span><br><span class="line"> phoneRed.goOnline();</span><br><span class="line"> PhoneBlack phoneBlack = <span class="keyword">new</span> PhoneBlack(<span class="keyword">new</span> HuaWeiPhoneBrandImpl());</span><br><span class="line"> phoneBlack.call();</span><br><span class="line"> phoneBlack.sendMessage();</span><br><span class="line"> phoneBlack.goOnline();</span><br><span class="line"> PhoneWhite phoneWhite = <span class="keyword">new</span> PhoneWhite(<span class="keyword">new</span> XiaoMiPhoneBrandImpl());</span><br><span class="line"> phoneWhite.call();</span><br><span class="line"> phoneWhite.sendMessage();</span><br><span class="line"> phoneWhite.goOnline();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    至此,解决问题的方案改进完毕,通过这种方式,如果要添加新品牌的手机,只需让其实现PhoneBrand类即可;如果需要增加手机的颜色,只需让其继承Phone类即可。看下类图,如下:</p></blockquote><img src="/62f7f6a4/Bridge2.png" class="" title="桥接模式方案类图"><blockquote><p>    在这个方案中,Phone这个抽象类是所有具体手机的父类,也是PhoneBrand类聚合的对象,起到了关键的“桥”的作用。基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责,将抽象与实现分离开保证不同层次独立改变互不影响更,从而极大的提高了系统的灵活性,有利于扩展。</p></blockquote></li></ul><h1 id="四、桥接模式在JDBC中的应用"><a href="#四、桥接模式在JDBC中的应用" class="headerlink" title="四、桥接模式在JDBC中的应用"></a>四、桥接模式在JDBC中的应用</h1><ul><li>首先,来看一段客户端调用JDBC连接数据库的过程<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The type Client.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Jdbc test.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">jdbcTest</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// 1. 注册驱动</span></span><br><span class="line"> Class.forName(<span class="string">"com.mysql.jdbc.Driver"</span>);</span><br><span class="line"> <span class="comment">//2. 创建一个连接对象</span></span><br><span class="line"> Connection conn = DriverManager.getConnection(<span class="string">"url"</span>,<span class="string">"user"</span>,<span class="string">"password"</span>);</span><br><span class="line"> <span class="comment">//3. 创建一个sql语句的发送命令对象</span></span><br><span class="line"> Statement stmt = conn.createStatement();</span><br><span class="line"> <span class="comment">// 4. 执行sql,拿到查询的结果集对象</span></span><br><span class="line"> ResultSet rs = stmt.executeQuery(<span class="string">"s"</span>);</span><br><span class="line"> <span class="comment">//5. 输出结果集的数据</span></span><br><span class="line"> <span class="keyword">while</span>(rs.next()){</span><br><span class="line"> System.out.println(rs);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//6. 关闭连接,命令对象以及结果集。</span></span><br><span class="line"> rs.close();</span><br><span class="line"> stmt.close();</span><br><span class="line"> conn.close();</span><br><span class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (SQLException throwables) {</span><br><span class="line"> throwables.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li>然后,看下相关类的UML类图<img src="/62f7f6a4/Bridge3.png" class="" title="桥接模式在JDBC中的应用类图"></li></ul><blockquote><p>    从UML类图可以看出,com.mysql.jdbc.Driver类是java.sql.Driver接口的实现类,注册驱动时,会执行com.mysql.jdbc.Driver类的静态块,该静态代码块中调用java.sql.DriverManager#registerDriver(java.sql.Driver)方法,将Driver对象注册到 DriverManager中,DriverManager就相当于是“桥”;调用java.sql.DriverManager#getConnection(java.lang.String, java.lang.String, java.lang.String)创建一个连接对象时,会根据驱动的类型调用不同类型数据库(mysql、oracle等)实现的 Driver 的 connect() 方法,最终获得连接对象。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><img src="/62f7f6a4/Bridge.png" class="" title="Bridge Pattern"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>基于TrueLicense实现web应用的License验证</title>
<link href="https://syshlang.com/45cf44f/"/>
<id>https://syshlang.com/45cf44f/</id>
<published>2020-05-05T03:29:00.000Z</published>
<updated>2020-09-24T04:17:51.033Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    近期开发的web应用交付海外客户试用时,领导要求需要限制客户的试用期限,于是考虑使用license进行授权。查阅相关资料,了解到一个开源的证书管理引擎——TrueLicense,通过TrueLicense可以实现授权验证功能,用于license的生成和有效性的验证。</p><a id="more"></a><p>    </p><h1 id="一、License授权和验证的原理"><a href="#一、License授权和验证的原理" class="headerlink" title="一、License授权和验证的原理"></a>一、License授权和验证的原理</h1><blockquote><ul><li>首先,需要生成密钥对,生成方法有很多,本次项目使用的是JDK提供的KeyTool工具;</li><li>在服务端,也就是授权者通过私钥(授权者保留,不能泄露)对包含授权信息(如起始日期、截止日期,服务器硬件的MAC地址等)的license进行数字签名;</li><li>在客户端,也就是软件的使用方,通过公钥(一般放在验证的代码中使用)验证license是否符合使用条件。</li></ul></blockquote><h1 id="二、实现步骤"><a href="#二、实现步骤" class="headerlink" title="二、实现步骤"></a>二、实现步骤</h1><h2 id="1-生成密钥对"><a href="#1-生成密钥对" class="headerlink" title="1.生成密钥对"></a>1.生成密钥对</h2><h3 id="1-1-生成私钥库"><a href="#1-1-生成私钥库" class="headerlink" title="1.1.生成私钥库"></a>1.1.生成私钥库</h3><p>    安装jdk,并配置环境变量,然后使用KeyTool工具生成密钥对,命令如下:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">keytool -genkeypair -keysize 1024 -validity 3650 -alias SYSHLANG -keystore privateKeys.keystore -storepass 12345678A -keypass 12345678A -dname "CN=syshlang, OU=syshlang, O=syshlang, L=GZ, ST=GD, C=CN"</span><br></pre></td></tr></table></figure><blockquote><p><strong>参数说明:</strong></p><ul><li>keysize 密钥长度</li><li>validity 私钥的有效期(单位:天)</li><li>alias 私钥别称</li><li>keystore 指定私钥库文件的名称(生成在当前目录)</li><li>storepass 指定私钥库的密码(keystore文件存储密码)</li><li>keypass 指定别名条目的密码(私钥加解密密码)</li><li>dname 证书个人信息<ul><li>CN为你的姓名</li><li>OU为你的组织单位名称</li><li>O为你的组织名称</li><li>L为你所在的城市名称</li><li>ST为你所在的省份名称</li><li>C为你的国家名称</li></ul></li></ul></blockquote><img src="/45cf44f/genkeypair.png" class="" title="genkeypair"><h3 id="1-2-导出公钥"><a href="#1-2-导出公钥" class="headerlink" title="1.2.导出公钥"></a>1.2.导出公钥</h3><p>    这一步主要是把私钥库内的公匙导出到一个文件中,命令如下:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">keytool -exportcert -alias SYSHLANG -keystore privateKeys.keystore -storepass 12345678A -file certfile.cer</span><br></pre></td></tr></table></figure><blockquote><p><strong>参数说明:</strong></p><ul><li>alias 私钥别称</li><li>keystore 指定私钥库文件的名称(如果没有带路径,在当前目录查找)</li><li>storepass 指定私钥库的密码</li><li>file 导出证书文件名称</li></ul></blockquote><img src="/45cf44f/exportcert.png" class="" title="exportcert"><h3 id="1-3-导入证书文件"><a href="#1-3-导入证书文件" class="headerlink" title="1.3.导入证书文件"></a>1.3.导入证书文件</h3><p>    这一步主要是把上一步中导出的证书文件导入到公钥库中,命令如下:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">keytool -import -alias SYSHLANG -file certfile.cer -keystore publicCerts.keystore -storepass 12345678A</span><br></pre></td></tr></table></figure><blockquote><p><strong>参数说明:</strong></p><ul><li>alias 公钥别称</li><li>file 证书文件名称</li><li>keystore 公钥文件名称</li><li>storepass 指定私钥库的密码</li></ul></blockquote><img src="/45cf44f/import.png" class="" title="import"><blockquote><p>    是否信任此证书? [否]:” ,那么请输入”Y”;此步骤中如果没有storepass会提示输入输入密钥库口令,输入之前设置的即可,如果没有设置口令,则输入信任证书默认密钥“changeit”。</p></blockquote><p>    如果顺利通过以上的步骤,会在当前目录下生成三个文件:</p><img src="/45cf44f/keytoolfile.png" class="" title="执行完成生成的三个文件"><blockquote><ul><li>certfile.cer 认证证书,已经没用了,可以删掉</li><li>privateKeys.keystore 私钥,授权者保留,不能泄露</li><li>publicCerts.keystore 公钥,给客人使用(一般放在验证的代码中使用)</li></ul></blockquote><p>    此时,可以查看cacerts中的证书列表</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit // 查看所有</span><br><span class="line">keytool -list -alias SYSHLANG -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit // 查看指定别名</span><br></pre></td></tr></table></figure><p>    删除cacerts中指定名称的证书</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">keytool -delete -alias SYSHLANG -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit</span><br></pre></td></tr></table></figure><h2 id="2-使用TrueLicense实现授权验证"><a href="#2-使用TrueLicense实现授权验证" class="headerlink" title="2.使用TrueLicense实现授权验证"></a>2.使用TrueLicense实现授权验证</h2><h3 id="2-1服务端生成授权证书"><a href="#2-1服务端生成授权证书" class="headerlink" title="2.1服务端生成授权证书"></a>2.1服务端生成授权证书</h3><blockquote><p>    TrueLicense默认只帮我们验证了时间,可以自定义加入一些需要验证的其它信息,例如,服务器硬件的MAC地址、CPU序列号等。然后调用私钥(privateKeys.keystore)生成授权证书文件(license.lic)。</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LicenseCreateParam</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</span><br><span class="line"> <span class="comment">// 添加自定义验证的信息字段</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>    具体代码实现,可以点击<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL0xpY2Vuc2VUb29scy90cmVlL21hc3Rlci9saWNlbnNlU2VydmVy">服务端代码链接<i class="fa fa-external-link-alt"></i></span>查看。</p><h3 id="2-2客户端验证授权证书"><a href="#2-2客户端验证授权证书" class="headerlink" title="2.2客户端验证授权证书"></a>2.2客户端验证授权证书</h3><blockquote><p>    在客户端,继承LicenseManager类,重写verify方法,校验自定义加入一些需要验证的其它信息。将公钥(publicCerts.keystore)放在项目中,将授权证书文件(license.lic)放到对应的路径即可。</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClientLicenseManager</span> <span class="keyword">extends</span> <span class="title">LicenseManager</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> LicenseContent <span class="title">verify</span><span class="params">(LicenseNotary licenseNotary)</span> <span class="keyword">throws</span> LicenseContentException </span>{</span><br><span class="line"> <span class="comment">// 重写verify方法,校验自定义信息</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>    具体代码实现,可以点击<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL0xpY2Vuc2VUb29scy90cmVlL21hc3Rlci9saWNlbnNlQ2xpZW50">客户端代码链接<i class="fa fa-external-link-alt"></i></span>查看。</p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;近期开发的web应用交付海外客户试用时,领导要求需要限制客户的试用期限,于是考虑使用license进行授权。查阅相关资料,了解到一个开源的证书管理引擎——TrueLicense,通过TrueLicense可以实现授权验证功能,用于license的生成和有效性的验证。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="TrueLicense" scheme="https://syshlang.com/tags/TrueLicense/"/>
<category term="License" scheme="https://syshlang.com/tags/License/"/>
</entry>
<entry>
<title>设计模式之结构型模式中的适配器模式(Adapter Pattern)</title>
<link href="https://syshlang.com/fbfea71e/"/>
<id>https://syshlang.com/fbfea71e/</id>
<published>2020-01-17T06:27:22.000Z</published>
<updated>2020-09-17T00:34:15.252Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/fbfea71e/Adapter.png" class="" title="Adapter Pattern"><a id="more"></a><h1 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h1><blockquote><p>    生活中,我们接触到最多的适配器就是电源适配器,不管是电脑的电源适配器、手机电源适配器,还是其他的电子产品电源适配器,其主要目的都是将家用电源220V转换为电子产品需要的电压,这些适配器的接口有两孔的也有三孔的,实质就是把一个转接头或者电压变换成另外所需要的插口或者电压。拿到编程里面来说,就是将一个类的接口转换成客户端所希望的另外一个接口,这样使得原本不能一起工作的那些类(接口不兼容,方法不匹配等)可以一起工作,主要目的就是处理兼容性。</p></blockquote><h1 id="适配器模式分类"><a href="#适配器模式分类" class="headerlink" title="适配器模式分类"></a>适配器模式分类</h1><blockquote><p>    适配器模式主要分为三类:类适配器、对象适配器、接口适配器。类适配器和对象适配器在实现上有些差别,而接口适配器则差别较大。</p></blockquote><h2 id="类适配器模式"><a href="#类适配器模式" class="headerlink" title="类适配器模式"></a>类适配器模式</h2><blockquote><p>    类适配器实现的原理主要是通过继承。适配器类(Adapter)通过继承需要被适配的类(Source),实现需要得到的类(Destination)接口,从而完成Adapter到Destination的适配。</p></blockquote><h3 id="日常举例"><a href="#日常举例" class="headerlink" title="日常举例"></a>日常举例</h3><blockquote><p>手机充电的例子,通过手机充电器(Adapter)完成220V电源(Source)到 5V电压(Destination)的转换</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Source220V</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage220v</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">220</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Destination5V</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">outVoltage5v</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">VoltageAdapter</span> <span class="keyword">extends</span> <span class="title">Source220V</span> <span class="keyword">implements</span> <span class="title">Destination5V</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage5v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> voltage220v = outVoltage220v();</span><br><span class="line"> <span class="keyword">return</span> voltage220v/<span class="number">44</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> VoltageAdapter voltageAdapter = <span class="keyword">new</span> VoltageAdapter();</span><br><span class="line"> voltageAdapter.outVoltage5v();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="对象适配器模式"><a href="#对象适配器模式" class="headerlink" title="对象适配器模式"></a>对象适配器模式</h2><blockquote><p>    对象配器实现的原理主要是通过组合或聚合。在<a href="/fd78ccb3/" title="《设计模式七大原则之合成复用原则(Composite Reuse Principle)》">《设计模式七大原则之合成复用原则(Composite Reuse Principle)》</a>中,合成复用原则指出尽量使用合成/聚合,尽量不要使用类继承。对象适配器模式思路和类适配器模式基本相同,只不过将适配器类(Adapter)做修改,不再继承需要被适配的类(Source),而是直接持有需要被适配的类(Source),实现需要得到的类(Destination)接口,从而完成Adapter到Destination的适配。</p></blockquote><h3 id="日常举例-1"><a href="#日常举例-1" class="headerlink" title="日常举例"></a>日常举例</h3><blockquote><p>仍然是手机充电的例子,只需要修改适配器类(Adapter),如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">VoltageAdapter</span> <span class="keyword">implements</span> <span class="title">Destination5V</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 直接持有需要被适配的类(Source)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> Source220V source220V;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">VoltageAdapter</span><span class="params">(Source220V source220V)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.source220V = source220V;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage5v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> voltage220v = source220V.outVoltage220v();</span><br><span class="line"> <span class="keyword">return</span> voltage220v/<span class="number">44</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> VoltageAdapter voltageAdapter = <span class="keyword">new</span> VoltageAdapter(<span class="keyword">new</span> Source220V());</span><br><span class="line"> voltageAdapter.outVoltage5v();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="接口适配器模式"><a href="#接口适配器模式" class="headerlink" title="接口适配器模式"></a>接口适配器模式</h2><blockquote><p>    接口配器实现的原理主要是通过抽象类来实现适配。接口适配器模式的核心思路是,当不需要全部实现接口的方法时,可以先设计一个抽象的类实现接口,并为接口中的每个方法提供一个默认的实现,对于该抽象类的子类就可以有选择的覆盖父类的某些方法,从而达到适配的目的。因此,该模式也被称为缺省适配器模式或是默认适配器模式(Default Adapter Pattern)。</p></blockquote><h3 id="日常举例-2"><a href="#日常举例-2" class="headerlink" title="日常举例"></a>日常举例</h3><blockquote><p>仍然是手机充电的例子,代码实现如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Destination</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">outVoltage5v</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">outVoltage10v</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">outVoltage36v</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">outVoltage220v</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractVoltageAdapter</span> <span class="keyword">implements</span> <span class="title">Destination</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage5v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">5</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage10v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage36v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">36</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage220v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">220</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">VoltageAdapter</span> <span class="keyword">extends</span> <span class="title">AbstractVoltageAdapter</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">outVoltage5v</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> voltage220v = outVoltage220v();</span><br><span class="line"> <span class="keyword">return</span> voltage220v/<span class="number">44</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> VoltageAdapter voltageAdapter = <span class="keyword">new</span> VoltageAdapter();</span><br><span class="line"> voltageAdapter.outVoltage5v();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="适配器模式在Spring框架中的应用"><a href="#适配器模式在Spring框架中的应用" class="headerlink" title="适配器模式在Spring框架中的应用"></a>适配器模式在Spring框架中的应用</h1><p>对于SpringMVC有一个很重要的servlet,它有一个方法:<br>org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter<br>截取部分源码如下:<br>源码:org.springframework.web.servlet.DispatcherServlet(片段)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServlet</span> <span class="keyword">extends</span> <span class="title">FrameworkServlet</span> </span>{</span><br><span class="line">...</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Return the HandlerAdapter for this handler object.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler the handler object to find an adapter for</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> HandlerAdapter <span class="title">getHandlerAdapter</span><span class="params">(Object handler)</span> <span class="keyword">throws</span> ServletException </span>{</span><br><span class="line"><span class="keyword">for</span> (HandlerAdapter ha : <span class="keyword">this</span>.handlerAdapters) {</span><br><span class="line"><span class="keyword">if</span> (logger.isTraceEnabled()) {</span><br><span class="line">logger.trace(<span class="string">"Testing handler adapter ["</span> + ha + <span class="string">"]"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (ha.supports(handler)) {</span><br><span class="line"><span class="keyword">return</span> ha;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> ServletException(<span class="string">"No adapter for handler ["</span> + handler +</span><br><span class="line"><span class="string">"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"</span>);</span><br><span class="line">}</span><br><span class="line">...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>源码:org.springframework.web.servlet.HandlerAdapter</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">HandlerAdapter</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Given a handler instance, return whether or not this {<span class="doctag">@code</span> HandlerAdapter}</span></span><br><span class="line"><span class="comment"> * can support it. Typical HandlerAdapters will base the decision on the handler</span></span><br><span class="line"><span class="comment"> * type. HandlerAdapters will usually only support one handler type each.</span></span><br><span class="line"><span class="comment"> * <p>A typical implementation:</span></span><br><span class="line"><span class="comment"> * <p>{<span class="doctag">@code</span></span></span><br><span class="line"><span class="comment"> * return (handler instanceof MyHandler);</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler handler object to check</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> whether or not this object can use the given handler</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">supports</span><span class="params">(Object handler)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Use the given handler to handle this request.</span></span><br><span class="line"><span class="comment"> * The workflow that is required may vary widely.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request current HTTP request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> response current HTTP response</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler handler to use. This object must have previously been passed</span></span><br><span class="line"><span class="comment"> * to the {<span class="doctag">@code</span> supports} method of this interface, which must have</span></span><br><span class="line"><span class="comment"> * returned {<span class="doctag">@code</span> true}.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception in case of errors</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> ModelAndView object with the name of the view and the required</span></span><br><span class="line"><span class="comment"> * model data, or {<span class="doctag">@code</span> null} if the request has been handled directly</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function">ModelAndView <span class="title">handle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Same contract as for HttpServlet's {<span class="doctag">@code</span> getLastModified} method.</span></span><br><span class="line"><span class="comment"> * Can simply return -1 if there's no support in the handler class.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request current HTTP request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler handler to use</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the lastModified value for the given handler</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> javax.servlet.http.HttpServlet#getLastModified</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> org.springframework.web.servlet.mvc.LastModified#getLastModified</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="title">getLastModified</span><span class="params">(HttpServletRequest request, Object handler)</span></span>;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>再看HandlerAdapter的继承关系图:</p><img src="/fbfea71e/handleradapter.png" class="" title="HandlerAdapter"><blockquote><p><strong>分析:</strong> 从上面的源码片段及HandlerAdapter的继承关系图,可以看出Spring定义了一个适配接口HandlerAdapter,而其实现子类使得每一种Controller都有一种对应的适配器实现类,扩展Controller时只需增加对应的适配器实现类就可以了。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><img src="/fbfea71e/Adapter.png" class="" title="Adapter Pattern"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>设计模式之创建型模式中的建造者模式(Builder Pattern)</title>
<link href="https://syshlang.com/8cf99788/"/>
<id>https://syshlang.com/8cf99788/</id>
<published>2020-01-17T00:56:09.000Z</published>
<updated>2020-09-17T00:34:15.252Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/8cf99788/builder.jpg" class="" title="Builder Pattern"><a id="more"></a><h1 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h1><blockquote><p>    在java开发过程中,我们经常会创建大量的对象,这些对象有简单的也有复杂的,但是不管是简单对象还是复杂对象,构建这些对象的过程是相对稳定的,只不过它们的内部属性(成员属性)不同,这也就意味着构建的具体内部细节不一样。那么,基于这种情况,我们可以将复杂的对象的构建过程抽象出来,通过抽象过程的不同实现方法来实现不同对象的内部细节构建过程,从某种意义上来说,这也是产品构建过程复杂度的解耦,这就是建造者模式(Builder Pattern)。</p></blockquote><blockquote><p>    建造者模式(Builder Pattern)又叫生成器模式,它把对象的创建步骤抽象成生成器,将一个产品的内部表象与产品的生产过程分割开来,一步一步构建一个复杂的对象,用户只用指定复杂对象的类型和内容,而无需知道内部的具体构建细节就可以构建它们。</p></blockquote><h1 id="建造者模式的四个角色"><a href="#建造者模式的四个角色" class="headerlink" title="建造者模式的四个角色"></a>建造者模式的四个角色</h1><ul><li>产品角色(Product):我们所要构建的产品对象;</li><li>抽象建造者(Builder):创建产品(Product)对象的接口/抽象类。它定义了创建一个产品(Product)对象所需要的各个部件的操作(抽象方法),同时包含一个获取产品(Product)对象(获取成品)的方法。</li><li>具体建造者(ConcreteBuilder):抽象建造者的具体实现,实现抽象建造者(Builder)的接口,构建和装配产品(Product)对象的各个部件,对于不同的部件或者构建步骤进行不同的详细实现,来完成不同的产品。</li><li>指导者(Director):主要用来使用Buider接口,构建一个使用Buider接口的对象,以一个相对稳定且统一的过程生产产品(Product)对象。</li></ul><h1 id="日常举例"><a href="#日常举例" class="headerlink" title="日常举例"></a>日常举例</h1><blockquote><p>建造小汽车的例子:小汽车主要部件:发动机(Engine)、车身框架(Frame)、轮胎(Wheel)等,不管是什么品牌的汽车,都有这些部件,只不过内部的构造和质量等不一样。代码实现,如下:</p></blockquote><ul><li>产品角色(Product)<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String engine;</span><br><span class="line"> <span class="keyword">private</span> String frame;</span><br><span class="line"> <span class="keyword">private</span> String wheel;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getEngine</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> engine;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setEngine</span><span class="params">(String engine)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.engine = engine;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getFrame</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> frame;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setFrame</span><span class="params">(String frame)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.frame = frame;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getWheel</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> wheel;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setWheel</span><span class="params">(String wheel)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.wheel = wheel;</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Car{"</span> +</span><br><span class="line"> <span class="string">"engine='"</span> + engine + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", frame='"</span> + frame + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", wheel='"</span> + wheel + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li>抽象建造者(Builder)<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CarBuilder</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 建造发动机</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">String <span class="title">buildEngine</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 建造车身框架</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">String <span class="title">buildFrame</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 建造轮胎</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">String <span class="title">buildWheel</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取小汽车成品</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">Car <span class="title">getCar</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li>具体建造者(ConcreteBuilder)<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BaoMaCarBuilder</span> <span class="keyword">implements</span> <span class="title">CarBuilder</span></span>{</span><br><span class="line"> Car car = <span class="keyword">new</span> Car();</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">buildEngine</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.car.setEngine(<span class="string">"建造宝马发动机!"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">buildFrame</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.car.setFrame(<span class="string">"建造宝马车身框架!"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">buildWheel</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.car.setWheel(<span class="string">"建造宝马轮胎!"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Car <span class="title">getCar</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.car;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li>指导者(Director)<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CarDirector</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> CarBuilder carBuilder;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">CarDirector</span><span class="params">(CarBuilder carBuilder)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.carBuilder = carBuilder;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构建汽车的流程交给指导者</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Car <span class="title">builderCar</span><span class="params">()</span></span>{</span><br><span class="line"> carBuilder.buildEngine();</span><br><span class="line"> carBuilder.buildFrame();</span><br><span class="line"> carBuilder.buildWheel();</span><br><span class="line"> <span class="keyword">return</span> carBuilder.getCar();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li>客户端使用<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> BaoMaCarBuilder baoMaCarBuilder = <span class="keyword">new</span> BaoMaCarBuilder();</span><br><span class="line"> CarDirector carDirector = <span class="keyword">new</span> CarDirector(baoMaCarBuilder);</span><br><span class="line"> Car car = carDirector.builderCar();</span><br><span class="line"> System.out.println(car);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>运行结果:<img src="/8cf99788/buildercar.png" class="" title="客户端运行结果"></li></ul><h1 id="建造者模式在JDK中的应用"><a href="#建造者模式在JDK中的应用" class="headerlink" title="建造者模式在JDK中的应用"></a>建造者模式在JDK中的应用</h1><p>先看一张StringBuilder类图</p><img src="/8cf99788/StringBuilder.png" class="" title="StringBuilder类图"><p>源码:java.lang.Appendable</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Appendable</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Appends the specified character sequence to this <tt>Appendable</tt>.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> Depending on which class implements the character sequence</span></span><br><span class="line"><span class="comment"> * <tt>csq</tt>, the entire sequence may not be appended. For</span></span><br><span class="line"><span class="comment"> * instance, if <tt>csq</tt> is a {<span class="doctag">@link</span> java.nio.CharBuffer} then</span></span><br><span class="line"><span class="comment"> * the subsequence to append is defined by the buffer's position and limit.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> csq</span></span><br><span class="line"><span class="comment"> * The character sequence to append. If <tt>csq</tt> is</span></span><br><span class="line"><span class="comment"> * <tt>null</tt>, then the four characters <tt>"null"</tt> are</span></span><br><span class="line"><span class="comment"> * appended to this Appendable.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> A reference to this <tt>Appendable</tt></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> * If an I/O error occurs</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">Appendable <span class="title">append</span><span class="params">(CharSequence csq)</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Appends a subsequence of the specified character sequence to this</span></span><br><span class="line"><span class="comment"> * <tt>Appendable</tt>.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> An invocation of this method of the form <tt>out.append(csq, start,</span></span><br><span class="line"><span class="comment"> * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in</span></span><br><span class="line"><span class="comment"> * exactly the same way as the invocation</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <pre></span></span><br><span class="line"><span class="comment"> * out.append(csq.subSequence(start, end)) </pre></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> csq</span></span><br><span class="line"><span class="comment"> * The character sequence from which a subsequence will be</span></span><br><span class="line"><span class="comment"> * appended. If <tt>csq</tt> is <tt>null</tt>, then characters</span></span><br><span class="line"><span class="comment"> * will be appended as if <tt>csq</tt> contained the four</span></span><br><span class="line"><span class="comment"> * characters <tt>"null"</tt>.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> start</span></span><br><span class="line"><span class="comment"> * The index of the first character in the subsequence</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> end</span></span><br><span class="line"><span class="comment"> * The index of the character following the last character in the</span></span><br><span class="line"><span class="comment"> * subsequence</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> A reference to this <tt>Appendable</tt></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IndexOutOfBoundsException</span></span><br><span class="line"><span class="comment"> * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt></span></span><br><span class="line"><span class="comment"> * is greater than <tt>end</tt>, or <tt>end</tt> is greater than</span></span><br><span class="line"><span class="comment"> * <tt>csq.length()</tt></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> * If an I/O error occurs</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">Appendable <span class="title">append</span><span class="params">(CharSequence csq, <span class="keyword">int</span> start, <span class="keyword">int</span> end)</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Appends the specified character to this <tt>Appendable</tt>.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> c</span></span><br><span class="line"><span class="comment"> * The character to append</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> A reference to this <tt>Appendable</tt></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> * If an I/O error occurs</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">Appendable <span class="title">append</span><span class="params">(<span class="keyword">char</span> c)</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>源码:java.lang.AbstractStringBuilder(片段)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractStringBuilder</span> <span class="keyword">implements</span> <span class="title">Appendable</span>, <span class="title">CharSequence</span> </span>{</span><br><span class="line">...</span><br><span class="line"> <span class="comment">// Documentation in subclasses because of synchro difference</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> AbstractStringBuilder <span class="title">append</span><span class="params">(StringBuffer sb)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (sb == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> appendNull();</span><br><span class="line"> <span class="keyword">int</span> len = sb.length();</span><br><span class="line"> ensureCapacityInternal(count + len);</span><br><span class="line"> sb.getChars(<span class="number">0</span>, len, value, count);</span><br><span class="line"> count += len;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 1.8</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">AbstractStringBuilder <span class="title">append</span><span class="params">(AbstractStringBuilder asb)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (asb == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> appendNull();</span><br><span class="line"> <span class="keyword">int</span> len = asb.length();</span><br><span class="line"> ensureCapacityInternal(count + len);</span><br><span class="line"> asb.getChars(<span class="number">0</span>, len, value, count);</span><br><span class="line"> count += len;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Documentation in subclasses because of synchro difference</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> AbstractStringBuilder <span class="title">append</span><span class="params">(CharSequence s)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (s == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> appendNull();</span><br><span class="line"> <span class="keyword">if</span> (s <span class="keyword">instanceof</span> String)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.append((String)s);</span><br><span class="line"> <span class="keyword">if</span> (s <span class="keyword">instanceof</span> AbstractStringBuilder)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.append((AbstractStringBuilder)s);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.append(s, <span class="number">0</span>, s.length());</span><br><span class="line"> }</span><br><span class="line">...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>源码:java.lang.StringBuilder(片段)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">StringBuilder</span></span></span><br><span class="line"><span class="class"> <span class="keyword">extends</span> <span class="title">AbstractStringBuilder</span></span></span><br><span class="line"><span class="class"> <span class="keyword">implements</span> <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">CharSequence</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line">...</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> StringBuilder <span class="title">append</span><span class="params">(Object obj)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> append(String.valueOf(obj));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> StringBuilder <span class="title">append</span><span class="params">(String str)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.append(str);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Appends the specified {<span class="doctag">@code</span> StringBuffer} to this sequence.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * The characters of the {<span class="doctag">@code</span> StringBuffer} argument are appended,</span></span><br><span class="line"><span class="comment"> * in order, to this sequence, increasing the</span></span><br><span class="line"><span class="comment"> * length of this sequence by the length of the argument.</span></span><br><span class="line"><span class="comment"> * If {<span class="doctag">@code</span> sb} is {<span class="doctag">@code</span> null}, then the four characters</span></span><br><span class="line"><span class="comment"> * {<span class="doctag">@code</span> "null"} are appended to this sequence.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * Let <i>n</i> be the length of this character sequence just prior to</span></span><br><span class="line"><span class="comment"> * execution of the {<span class="doctag">@code</span> append} method. Then the character at index</span></span><br><span class="line"><span class="comment"> * <i>k</i> in the new character sequence is equal to the character at</span></span><br><span class="line"><span class="comment"> * index <i>k</i> in the old character sequence, if <i>k</i> is less than</span></span><br><span class="line"><span class="comment"> * <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i></span></span><br><span class="line"><span class="comment"> * in the argument {<span class="doctag">@code</span> sb}.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> sb the {<span class="doctag">@code</span> StringBuffer} to append.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a reference to this object.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> StringBuilder <span class="title">append</span><span class="params">(StringBuffer sb)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.append(sb);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> StringBuilder <span class="title">append</span><span class="params">(CharSequence s)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.append(s);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line">...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p><strong>分析:</strong> 接口Appendable定义了多个append抽象方法,即为抽象建造者;抽象类AbstractStringBuilder实现了接口Appendable的方法,即为具体建造者,但是不能实例化;StringBuilder继承了抽象类AbstractStringBuilder,具体的方法已经由AbstractStringBuilder实现,StringBuilder对部分方法进行了覆盖,由此可以看出,StringBuilder既充当了具体建造者,也是指导者的角色。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><img src="/8cf99788/builder.jpg" class="" title="Builder Pattern"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>原型模式(Prototype Pattern)之浅拷贝和深拷贝</title>
<link href="https://syshlang.com/a853c6f2/"/>
<id>https://syshlang.com/a853c6f2/</id>
<published>2020-01-15T07:06:44.000Z</published>
<updated>2020-09-17T00:34:15.252Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/a853c6f2/prototype-copy.png" class="" title="浅拷贝和深拷贝"><a id="more"></a><blockquote><p>    在<a href="/129d022b/" title="《设计模式之创建型模式中的原型模式(Prototype Pattern)》">《设计模式之创建型模式中的原型模式(Prototype Pattern)》</a>中,通过克隆羊多莉的例子了解了原型模式,从客户端代码运行的结果,很容易发现:通过原型对象创建另一个新对象时,如果更改原型对象的某些类型的属性,新建的对象的属性也可能会发生变化。</p></blockquote><h2 id="浅拷贝"><a href="#浅拷贝" class="headerlink" title="浅拷贝"></a>浅拷贝</h2><blockquote><p>    通过原型对象创建另一个新对象时,将原型对象的非静态成员变量复制到新的对象,对于不同类型的成员变量,拷贝规则如下:</p><ol><li>如果成员变量的数据类型是值类型(基本数据类型),浅拷贝会直接进行值传递,也就是直接复制一份该属性给新对象;</li><li>如果成员变量的数据类型是引用类型,则浅拷贝会进行引用传递,也就是只会将该成员变量的引用值(内存地址)复制一份给新对象,而不会复制引用的对象,那么也就意味着新对象和原型对象的该成员变量都指向同一个实例。因此,一个对象中修改成员变量的值会影响到另一个对象的该成员变量的值。</li></ol></blockquote><p>    上一文我们举的例子就是浅拷贝实现克隆羊,SheepPrototype类实现了Cloneable接口,使用了默认的super.clone()方法。</p><div class="note info"><ul><li>基本类型也称为值类型,分别是字符类型 char,布尔类型 boolean以及数值类型 byte、short、int、long、float、double。</li><li>引用类型则包括类、接口、数组、枚举等。</li><li>Java 将内存空间分为堆和栈。基本类型直接在栈中存储数值,而引用类型是将引用放在栈中,实际存储的值是放在堆中,通过栈中的引用指向堆中存放的数据。</li></ul></div><h2 id="深拷贝"><a href="#深拷贝" class="headerlink" title="深拷贝"></a>深拷贝</h2><blockquote><p>    通过原型对象创建另一个新对象时,将原型对象的非静态成员变量复制到新的对象,不管成员变量的数据类型是值类型还是引用类型,深拷贝都会重新复制一份给新的对象。因此,修改其中一个对象的任何成员变量的值,都不会影响到另一个对象。</p></blockquote><h3 id="深拷贝的实现"><a href="#深拷贝的实现" class="headerlink" title="深拷贝的实现"></a>深拷贝的实现</h3><p><strong>一、重写clone() 方法</strong><br>    重写clone()方法,把要复制的对象所引用的对象都复制一遍,如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeepConcreteSheepPrototype</span> <span class="keyword">implements</span> <span class="title">Cloneable</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"> <span class="keyword">private</span> String color;</span><br><span class="line"> <span class="keyword">private</span> SheepPrototype mother;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">DeepConcreteSheepPrototype</span><span class="params">(String name, <span class="keyword">int</span> age, String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">DeepConcreteSheepPrototype</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getColor</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> SheepPrototype <span class="title">getMother</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> mother;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMother</span><span class="params">(SheepPrototype mother)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.mother = mother;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 克隆实例</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> DeepConcreteSheepPrototype <span class="title">clone</span><span class="params">()</span> </span>{</span><br><span class="line"> DeepConcreteSheepPrototype deepConcreteSheepPrototype = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> deepConcreteSheepPrototype = (DeepConcreteSheepPrototype) <span class="keyword">super</span>.clone();</span><br><span class="line"> SheepPrototype sheepPrototype = mother.clone();</span><br><span class="line"> deepConcreteSheepPrototype.mother = sheepPrototype;</span><br><span class="line"> } <span class="keyword">catch</span> (CloneNotSupportedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> deepConcreteSheepPrototype;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"DeepConcreteSheepPrototype{"</span> +</span><br><span class="line"> <span class="string">"name='"</span> + name + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", age="</span> + age +</span><br><span class="line"> <span class="string">", color='"</span> + color + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", mother="</span> + mother +</span><br><span class="line"> <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CloneDollyPrototype</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> DeepConcreteSheepPrototype deepDolly = <span class="keyword">new</span> DeepConcreteSheepPrototype(<span class="string">"dolly"</span>,<span class="number">2</span>,<span class="string">"gray"</span>);</span><br><span class="line"> deepDolly.setMother(<span class="keyword">new</span> ConcreteSheepPrototype(<span class="string">"dolly"</span>,<span class="number">5</span>,<span class="string">"gray"</span>));</span><br><span class="line"> DeepConcreteSheepPrototype deepConcreteSheepPrototype = deepDolly.clone();</span><br><span class="line"> DeepConcreteSheepPrototype deepConcreteSheepPrototype1 = deepDolly.clone();</span><br><span class="line"> DeepConcreteSheepPrototype deepConcreteSheepPrototypeN = deepDolly.clone();</span><br><span class="line"> deepDolly.getMother().setColor(<span class="string">"red"</span>);</span><br><span class="line"> System.out.println(deepDolly);</span><br><span class="line"> System.out.println(deepConcreteSheepPrototype);</span><br><span class="line"> System.out.println(deepConcreteSheepPrototype1);</span><br><span class="line"> System.out.println(deepConcreteSheepPrototypeN);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行结果如下:</p><img src="/a853c6f2/DeepConcreteSheepPrototype.png" class="" title="重写clone()方法实现深拷贝"><p><strong>二、利用序列化</strong></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeepConcreteSheepSerializable</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">8738439006982997247L</span>;</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"> <span class="keyword">private</span> String color;</span><br><span class="line"> <span class="keyword">private</span> SheepPrototype mother;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getColor</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> SheepPrototype <span class="title">getMother</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> mother;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMother</span><span class="params">(SheepPrototype mother)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.mother = mother;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">deepClone</span><span class="params">()</span></span>{</span><br><span class="line"> ByteArrayOutputStream out = <span class="keyword">null</span>;</span><br><span class="line"> ObjectOutputStream obs = <span class="keyword">null</span>;</span><br><span class="line"> ByteArrayInputStream ios = <span class="keyword">null</span>;</span><br><span class="line"> ObjectInputStream ois = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//序列化</span></span><br><span class="line"> out = <span class="keyword">new</span> ByteArrayOutputStream();</span><br><span class="line"> obs = <span class="keyword">new</span> ObjectOutputStream(out);</span><br><span class="line"> obs.writeObject(<span class="keyword">this</span>);</span><br><span class="line"> obs.close();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//反序列化</span></span><br><span class="line"> ios = <span class="keyword">new</span> ByteArrayInputStream(out.toByteArray());</span><br><span class="line"> ois = <span class="keyword">new</span> ObjectInputStream(ios);</span><br><span class="line"> <span class="comment">//返回生成的新对象</span></span><br><span class="line"> DeepConcreteSheepSerializable deepConcreteSheepSerializable = (DeepConcreteSheepSerializable) ois.readObject();</span><br><span class="line"> ois.close();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> out.close();</span><br><span class="line"> obs.close();</span><br><span class="line"> ios.close();</span><br><span class="line"> ois.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException ex) {</span><br><span class="line"> ex.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"DeepConcreteSheepSerializable{"</span> +</span><br><span class="line"> <span class="string">"name='"</span> + name + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", age="</span> + age +</span><br><span class="line"> <span class="string">", color='"</span> + color + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", mother="</span> + mother +</span><br><span class="line"> <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CloneDollyPrototype</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> DeepConcreteSheepSerializable deepDollySerializable = <span class="keyword">new</span> DeepConcreteSheepSerializable(<span class="string">"dolly"</span>,<span class="number">2</span>,<span class="string">"gray"</span>);</span><br><span class="line"> deepDollySerializable.setMother(<span class="keyword">new</span> ConcreteSheepPrototype(<span class="string">"dolly"</span>,<span class="number">5</span>,<span class="string">"gray"</span>));</span><br><span class="line"> DeepConcreteSheepSerializable deepConcreteSheepSerializable = deepDollySerializable.deepClone();</span><br><span class="line"> deepDollySerializable.getMother().setColor(<span class="string">"red"</span>);</span><br><span class="line"> deepDollySerializable.setAge(<span class="number">6</span>);</span><br><span class="line"> System.out.println(deepDollySerializable);</span><br><span class="line"> System.out.println(deepConcreteSheepSerializable);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行结果:</p><img src="/a853c6f2/DeepConcreteSheepSerializable.png" class="" title="利用序列化实现深拷贝"><blockquote><p>    从上面可以看出,利用序列化实现深拷贝主要是在内存中通过字节流的拷贝来实现的。把原型对象序列化写入到字节流中,然后再从字节流中将其读出来进行反序列化,这样就可以创建一个新的对象,当然,此种方式不会存在原型对象与新对象之间引用共享的问题,推荐使用这种方式实现深拷贝。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><img src="/a853c6f2/prototype-copy.png" class="" title="浅拷贝和深拷贝"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>设计模式之创建型模式中的原型模式(Prototype Pattern)</title>
<link href="https://syshlang.com/129d022b/"/>
<id>https://syshlang.com/129d022b/</id>
<published>2020-01-03T00:58:09.000Z</published>
<updated>2020-09-17T00:34:15.252Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/129d022b/prototype-pattern.png" class="" title="Prototype Pattern"><a id="more"></a><h1 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h1><blockquote><p>    原型模式(Prototype Pattern)主要用于在保证性能的情况下创建重复的对象,也就是创建当前对象的克隆,这种模式是实现了一个原型接口。在开发过程中,如果我们已经明确了所需要创建对象的种类,且创建这种类型对象的代价比较大(创建数量庞大,频繁的数据库交互对数据库等),就可以用原型实例指定所要创建对象的种类,然后通过拷贝这些原型创建新的对象。这就有点像我们生物里面学的细胞分裂。</p></blockquote><img src="/129d022b/prototype.png" class="" title="Prototype Pattern"><h1 id="日常举例"><a href="#日常举例" class="headerlink" title="日常举例"></a>日常举例</h1><blockquote><p>克隆羊的例子:有一只克隆羊叫多莉,没错就是这只羊,长的就是下面图片中的样子。。。现在按照这个样子再克隆N只多莉。。。</p></blockquote><img src="/129d022b/dolly.jpg" class="" title="我是克隆羊多莉..."><h2 id="传统方式"><a href="#传统方式" class="headerlink" title="传统方式"></a>传统方式</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Sheep</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"> <span class="keyword">private</span> String color;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Sheep</span><span class="params">(String name, <span class="keyword">int</span> age, String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Sheep</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getColor</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 以传统的简单方式克隆多莉羊</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CloneDollySimple</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Sheep dolly = <span class="keyword">new</span> Sheep(<span class="string">"dolly"</span>,<span class="number">2</span>,<span class="string">"gray"</span>);</span><br><span class="line"> Sheep sheep = <span class="keyword">new</span> Sheep(dolly.getName(),dolly.getAge(),dolly.getColor());</span><br><span class="line"> Sheep sheep1 = <span class="keyword">new</span> Sheep(dolly.getName(),dolly.getAge(),dolly.getColor());</span><br><span class="line"> Sheep sheepN = <span class="keyword">new</span> Sheep(dolly.getName(),dolly.getAge(),dolly.getColor());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="原型模式"><a href="#原型模式" class="headerlink" title="原型模式"></a>原型模式</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">SheepPrototype</span> <span class="keyword">implements</span> <span class="title">Cloneable</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"> <span class="keyword">private</span> String color;</span><br><span class="line"> <span class="keyword">private</span> SheepPrototype mother;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">SheepPrototype</span><span class="params">(String name, <span class="keyword">int</span> age, String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">SheepPrototype</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> String <span class="title">eat</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getColor</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> SheepPrototype <span class="title">getMother</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> mother;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMother</span><span class="params">(SheepPrototype mother)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.mother = mother;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 克隆实例</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> SheepPrototype <span class="title">clone</span><span class="params">()</span> </span>{</span><br><span class="line"> SheepPrototype sheepPrototype = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> sheepPrototype = (SheepPrototype) <span class="keyword">super</span>.clone();</span><br><span class="line"> } <span class="keyword">catch</span> (CloneNotSupportedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> sheepPrototype;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"SheepPrototype{"</span> +</span><br><span class="line"> <span class="string">"name='"</span> + name + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", age="</span> + age +</span><br><span class="line"> <span class="string">", color='"</span> + color + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", mother="</span> + mother +</span><br><span class="line"> <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 创建当前对象的浅表副本</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConcreteSheepPrototype</span> <span class="keyword">extends</span> <span class="title">SheepPrototype</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ConcreteSheepPrototype</span><span class="params">(String name, <span class="keyword">int</span> age, String color)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>(name, age, color);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> String <span class="title">eat</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Eating green grass"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 以原型模式克隆多莉羊</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CloneDollyPrototype</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> ConcreteSheepPrototype dolly = <span class="keyword">new</span> ConcreteSheepPrototype(<span class="string">"dolly"</span>,<span class="number">2</span>,<span class="string">"gray"</span>);</span><br><span class="line"> dolly.setMother(<span class="keyword">new</span> ConcreteSheepPrototype(<span class="string">"dolly"</span>,<span class="number">5</span>,<span class="string">"gray"</span>));</span><br><span class="line"> ConcreteSheepPrototype sheepPrototype = (ConcreteSheepPrototype) dolly.clone();</span><br><span class="line"> ConcreteSheepPrototype sheepPrototype1 = (ConcreteSheepPrototype) dolly.clone();</span><br><span class="line"> ConcreteSheepPrototype sheepPrototypeN = (ConcreteSheepPrototype) dolly.clone();</span><br><span class="line"> dolly.getMother().setColor(<span class="string">"red"</span>);</span><br><span class="line"> dolly.setAge(<span class="number">6</span>);</span><br><span class="line"> System.out.println(dolly);</span><br><span class="line"> System.out.println(sheepPrototype);</span><br><span class="line"> System.out.println(sheepPrototype1);</span><br><span class="line"> System.out.println(sheepPrototypeN);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行结果:</p><img src="/129d022b/ConcreteSheepPrototype.png" class="" title="浅拷贝"><blockquote><p>    对比以上的两种方式很容易可以看出,传统的方式虽然易于理解,但是每次创建新的对象时,都需要重新初始化对象,并获取原始对象的属性,然后设置属性,显然,这种方式效率低;相对于传统方式,原型模式就方便快捷很多,在无需关注细节的情况下,就可以通过原型对象创建出另外的可定制对象,这种方式必须实现 Cloneable 接口。</p></blockquote><div class="note info"><p>原型模式主要包含3个角色:</p><ol><li>Prototype(抽象原型类):声明克隆方法的接口,是所有具体原型类的公共父类,它可是抽象类也可以是接口,甚至可以是具体实现类。</li><li>ConcretePrototype(具体原型类):它实现抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。</li><li>Client(客户端):在客户类中,让一个原型对象克隆自身从而创建一个新的对象。</li></ol></div><h1 id="原型模式在Spring框架中的应用"><a href="#原型模式在Spring框架中的应用" class="headerlink" title="原型模式在Spring框架中的应用"></a>原型模式在Spring框架中的应用</h1><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"pointcut"</span> <span class="attr">class</span>=<span class="string">"org.springframework.aop.support.JdkRegexpMethodPointcut"</span> <span class="attr">scope</span>=<span class="string">"prototype"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"patterns"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">list</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">value</span>></span>com.syshlang.service..*Service.*(..)<span class="tag"></<span class="name">value</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">list</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">property</span>></span></span><br><span class="line"><span class="tag"></<span class="name">bean</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE )</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Sheep</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"> <span class="keyword">private</span> String color;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    在上面的配置中可以看到一个标签属性scope=”prototype”,原型模式与名称为prototype的作用域相似。在Spring中,一个类如果被标记为”prototype”,那么将该类注入到另一个bean中或者调用容器的getBean()方法时,都会产生一个新的bean实例。其实,这个产生新的bean的过程就是利用了原型模式。</p></blockquote><p>源码:org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//---------------------------------------------------------------------</span></span><br><span class="line"><span class="comment">// Implementation of BeanFactory interface</span></span><br><span class="line"><span class="comment">//---------------------------------------------------------------------</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">getBean</span><span class="params">(String name)</span> <span class="keyword">throws</span> BeansException </span>{</span><br><span class="line"> <span class="keyword">return</span> doGetBean(name, <span class="keyword">null</span>, <span class="keyword">null</span>, <span class="keyword">false</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>源码:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()(片段)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <T> <span class="function">T <span class="title">doGetBean</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">final</span> String name, <span class="keyword">final</span> Class<T> requiredType, <span class="keyword">final</span> Object[] args, <span class="keyword">boolean</span> typeCheckOnly)</span></span></span><br><span class="line"><span class="function"><span class="keyword">throws</span> BeansException </span>{</span><br><span class="line">...</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (mbd.isPrototype()) {</span><br><span class="line"><span class="comment">// It's a prototype -> create a new instance.</span></span><br><span class="line">Object prototypeInstance = <span class="keyword">null</span>;</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">beforePrototypeCreation(beanName);</span><br><span class="line">prototypeInstance = createBean(beanName, mbd, args);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">finally</span> {</span><br><span class="line">afterPrototypeCreation(beanName);</span><br><span class="line">}</span><br><span class="line">bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><img src="/129d022b/prototype-pattern.png" class="" title="Prototype Pattern"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>Oracle和Mysql数据库转换</title>
<link href="https://syshlang.com/463fcbf0/"/>
<id>https://syshlang.com/463fcbf0/</id>
<published>2019-12-30T02:22:40.000Z</published>
<updated>2020-09-17T00:34:15.260Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/463fcbf0/mysql-oracle.jpg" class=""><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>    我们的项目一直使用的是SSH框架+mysql+tomcat服务器,但是最近一个新项目对数据库的使用和web服务器提出了硬性要求,按照他们的要求,需要使用Oracle数据库,并采用Weblogic进行服务部署。本文针对本次数据库转换(Mysql转换Oracle)过程中遇到的一些问题做记录,对于部署服务器的更换(tomcat更换为Weblogic)另一文章将继续分享。</p><h1 id="问题分析"><a href="#问题分析" class="headerlink" title="问题分析"></a>问题分析</h1><p>    首先,我们系统的架构情况如下:</p><blockquote><p>开发环境:</p><ul><li>MAVEN:3.5</li><li>JDK:1.8</li><li>Spring: 4.3.9.RELEASE</li><li>hibernate: 4.3.11.Final</li><li>Shiro:1.4.0</li></ul></blockquote><blockquote><p>开发工具:</p><ul><li>MySql: 5.7.x</li><li>ORACLE: 11.2.0.1.0</li><li>Tomcat: 9.0</li><li>EZDML:2.06(表结构设计器)</li></ul></blockquote><p>    分析了一下部分代码,发现Mysql转换至Oracle,整体框架无需大的改动,由于使用了hibernate框架做持久层,业务操作基本都是HQL,所以无需做单独处理,需要变动的主要涉及到数据库结构的转换和一些公共自定义sql的兼容性处理,明确了解决问题的要点,现在开始着手。</p><h1 id="数据库转换"><a href="#数据库转换" class="headerlink" title="数据库转换"></a>数据库转换</h1><h2 id="数据库结构"><a href="#数据库结构" class="headerlink" title="数据库结构"></a>数据库结构</h2><h3 id="首先,使用EZDML表结构设计器进行数据库的整体转换"><a href="#首先,使用EZDML表结构设计器进行数据库的整体转换" class="headerlink" title="首先,使用EZDML表结构设计器进行数据库的整体转换"></a>首先,使用EZDML表结构设计器进行数据库的整体转换</h3><p>1、打开EZDML,点击模型,选择导入数据库:</p><img src="/463fcbf0/ezdml-mysql.png" class=""><p>2、点击确定,选择需要转换的表名,确定之后就可以看到对应的表结构模型;<br>3、在左边单击表明,就可以看到详细的表结构设计,选择生成,就可以看到不同类型数据库对应的建表DDL。</p><img src="/463fcbf0/ezdml-sql.png" class=""><h3 id="然后,对表结构进行微调"><a href="#然后,对表结构进行微调" class="headerlink" title="然后,对表结构进行微调"></a>然后,对表结构进行微调</h3><h4 id="Mysql和Oracle之间的数据类型转换"><a href="#Mysql和Oracle之间的数据类型转换" class="headerlink" title="Mysql和Oracle之间的数据类型转换"></a>Mysql和Oracle之间的数据类型转换</h4><table><thead><tr><th align="center">MySQL Data Type</th><th align="center">Oracle Data Type</th></tr></thead><tbody><tr><td align="center">BIGINT</td><td align="center">NUMBER(19, 0)</td></tr><tr><td align="center">BIT</td><td align="center">RAW</td></tr><tr><td align="center">BLOB</td><td align="center">BLOB, RAW</td></tr><tr><td align="center">CHAR</td><td align="center">CHAR</td></tr><tr><td align="center">DATE</td><td align="center">DATE</td></tr><tr><td align="center">DATETIME</td><td align="center">DATE</td></tr><tr><td align="center">DECIMAL</td><td align="center">FLOAT (24)</td></tr><tr><td align="center">DOUBLE</td><td align="center">FLOAT (24)</td></tr><tr><td align="center">DOUBLE PRECISION</td><td align="center">FLOAT (24)</td></tr><tr><td align="center">ENUM</td><td align="center">VARCHAR2</td></tr><tr><td align="center">FLOAT</td><td align="center">FLOAT</td></tr><tr><td align="center">INT</td><td align="center">NUMBER(10, 0)</td></tr><tr><td align="center">INTEGER</td><td align="center">NUMBER(10, 0)</td></tr><tr><td align="center">LONGBLOB</td><td align="center">BLOB, RAW</td></tr><tr><td align="center">LONGTEXT</td><td align="center">CLOB, RAW</td></tr><tr><td align="center">MEDIUMBLOB</td><td align="center">BLOB, RAW</td></tr><tr><td align="center">MEDIUMINT</td><td align="center">NUMBER(7, 0)</td></tr><tr><td align="center">MEDIUMTEXT</td><td align="center">CLOB, RAW</td></tr><tr><td align="center">NUMERIC</td><td align="center">NUMBER</td></tr><tr><td align="center">REAL</td><td align="center">FLOAT (24)</td></tr><tr><td align="center">SET</td><td align="center">VARCHAR2</td></tr><tr><td align="center">SMALLINT</td><td align="center">NUMBER(5, 0)</td></tr><tr><td align="center">TEXT</td><td align="center">VARCHAR2, CLOB</td></tr><tr><td align="center">TIME</td><td align="center">DATE</td></tr><tr><td align="center">TIMESTAMP</td><td align="center">DATE</td></tr><tr><td align="center">TINYBLOB</td><td align="center">RAW</td></tr><tr><td align="center">TINYINT</td><td align="center">NUMBER(3, 0)</td></tr><tr><td align="center">TINYTEXT</td><td align="center">VARCHAR2</td></tr><tr><td align="center">VARCHAR</td><td align="center">VARCHAR2, CLOB</td></tr><tr><td align="center">YEAR</td><td align="center">NUMBER</td></tr></tbody></table><h4 id="自增序列处理"><a href="#自增序列处理" class="headerlink" title="自增序列处理"></a>自增序列处理</h4><table><thead><tr><th align="center">MySQL Data Type</th><th align="center">Oracle Data Type</th></tr></thead><tbody><tr><td align="center">有自动增长的数据类型,插入记录时不用操作此字段,会自动获得数据值</td><td align="center">ORACLE没有自动增长的数据类型,需要建立一个自动增长的序列号,插入记录时要把序列号的下一个值赋于此字段</td></tr></tbody></table><p>Mysql自动增长的数据类型</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">create</span> <span class="keyword">table</span> table_name</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">ID</span> <span class="built_in">int</span> auto_increment <span class="comment">-- 自增长</span></span><br><span class="line"> primary <span class="keyword">key</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>Oracle自动增长的数据类型</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">create</span> <span class="keyword">sequence</span> table_name_pk</span><br><span class="line"><span class="keyword">minvalue</span> <span class="number">1</span></span><br><span class="line">maxvalue <span class="number">9999999999999999999999999999</span></span><br><span class="line"><span class="keyword">start</span> <span class="keyword">with</span> <span class="number">447</span></span><br><span class="line"><span class="keyword">increment</span> <span class="keyword">by</span> <span class="number">1</span></span><br><span class="line"><span class="keyword">cache</span> <span class="number">20</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">create</span> <span class="keyword">table</span> table_name</span><br><span class="line">(</span><br><span class="line"><span class="keyword">ID</span> <span class="built_in">int</span> <span class="keyword">generated</span> <span class="keyword">as</span> <span class="keyword">identity</span></span><br><span class="line"><span class="keyword">constraint</span> table_name_pk</span><br><span class="line">primary <span class="keyword">key</span></span><br><span class="line">)</span><br><span class="line">/</span><br></pre></td></tr></table></figure><h4 id="长字符串处理"><a href="#长字符串处理" class="headerlink" title="长字符串处理"></a>长字符串处理</h4><p>    在ORACLE中,进行INSERT和UPDATE时,最大可操作的字符串长度必须小于等于4000个单字节。如果超出这个长度,要插入更长的字符串数据,可以考虑使用CLOB类型。在本项目转换过程中,使用到了指纹数据的16进制字符串的存取,长度超过4000,在Mysql中使用BLOB类型存储没问题,但是ORACLE下不可以。BLOB全称为二进制大型对象(Binary Large Object),它用于存储数据库中的大型二进制对象,原来在ORACLE下,对二进制对象有严格要求,所以采用CLOB类型存储。</p><h4 id="日期字段处理"><a href="#日期字段处理" class="headerlink" title="日期字段处理"></a>日期字段处理</h4><p>     在MYSQL中,日期字段可以分DATE(包含年月日)和DATETIME(包含年月日时分秒)两种类型,而ORACLE日期字段只有DATE(包含年月日时分秒)一种类型。所以在实际业务使用过程中需要进行格式转换。</p><table><thead><tr><th align="center">比较项</th><th align="center">MySQL Data Type</th><th align="center">Oracle Data Type</th></tr></thead><tbody><tr><td align="center">数据类型</td><td align="center">DATE(包含年月日)、<br>DATETIME(包含年月日时分秒)</td><td align="center">DATE(包含年月日时分秒)</td></tr><tr><td align="center">日期格式</td><td align="center">%Y:代表4位的年份<br>%y:代表2为的年份<br>%m:代表月, 格式为(01……12) <br>%c:代表月, 格式为(1……12)<br>%d:代表月份中的天数,格式为(00……31)<br>%e:代表月份中的天数, 格式为(0……31)<br>%H:代表小时,格式为(00……23)<br>%k:代表 小时,格式为(0……23)<br>%h: 代表小时,格式为(01……12)<br>%I: 代表小时,格式为(01……12)<br>%l :代表小时,格式为(1……12)<br>%i: 代表分钟, 格式为(00……59)<br>%r:代表 时间,格式为12 小时(hh:mm:ss [AP]M)<br>%T:代表 时间,格式为24 小时(hh:mm:ss)<br>%S:代表 秒,格式为(00……59)<br>%s:代表 秒,格式为(00……59)</td><td align="center">YYYY、YYY、YY 分别代表4位、3位、2位的数字年<br>MM 数字月<br>DD 数字日<br>AM 表示上午或者下午<br>HH24、HH12 代表24小时制或12小时制<br>MI 分钟<br>SS 秒钟</td></tr><tr><td align="center">当前日期</td><td align="center">sysdate()、current_date、current_time</td><td align="center">sysdate、current_date、current_timestamp</td></tr><tr><td align="center">日期和字符互转</td><td align="center"><strong>DATE_FORMAT</strong><br>例如:DATE_FORMAT(sysdate(),’%Y-%m-%d %H:%i:%s’)<br><strong>STR_TO_DATE</strong><br>例如:STR_TO_DATE(‘2019-12-30 19:25:34’,’%Y-%m-%d %H:%i:%s’)</td><td align="center"><strong>TO_CHAR</strong><br>例如:TO_CHAR(sysdate,’YYYY-MM-DD HH24:MI:SS’)<br><strong>TO_DATE</strong><br>例如:TO_DATE(‘2019-12-30 19:25:34’,’YYYY-MM-DD HH24:MI:SS’)</td></tr><tr><td align="center">日期/时间增减</td><td align="center">增减一小时:<br>date_sub(createDate, interval -1 hour)<br>date_sub(createDate, interval 1 hour)<br>增减一天:<br>date_sub(createDate, interval -1 day)<br>date_sub(createDate, interval 1 day)<br>增减一月:<br>date_sub(createDate, interval -1 month)<br>date_sub(createDate, interval 1 month)<br>增减一季度:<br>date_sub(createDate, interval -3 month)<br>date_sub(createDate, interval 3 month)<br>增减一年:<br>date_sub(createDate, interval -1 year)<br>date_sub(createDate, interval 1 year)</td><td align="center">增减一小时:<br>createDate+1/24 <br>createDate-1/24<br>增减一天:<br>createDate+1<br>createDate-1<br>增减一月:<br>add_months(createDate, 1)<br>add_months(createDate, -1)<br>增减一季度:<br>add_months(createDate, 3)<br>add_months(createDate, -3)<br>增减一年:<br>add_months(createDate, 12) <br>add_months(createDate, -12)</td></tr><tr><td align="center">日期/时间比较</td><td align="center">①直接比较<br>②转成unix时间戳比较<br>③转换为日期类型比较<br></td><td align="center">①直接比较<br>②转换为日期类型比较</td></tr></tbody></table><p>日期/时间比较</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- Mysql</span></span><br><span class="line"><span class="comment">-- 直接比较(此种方式不走索引,一定程度上会降低性能)</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">sysdate</span>() <span class="keyword">from</span> dual <span class="keyword">where</span> <span class="string">'2019-12-30 19:39:05'</span> > <span class="string">'2019-12-30 17:39:05'</span>;</span><br><span class="line"><span class="comment">-- 用unix_timestamp函数,将字符型的时间,转成unix时间戳</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">sysdate</span>() <span class="keyword">from</span> dual <span class="keyword">where</span> <span class="keyword">unix_timestamp</span>(<span class="string">'2019-12-30 19:39:05'</span>) > <span class="keyword">unix_timestamp</span>(<span class="string">'2019-12-30 17:39:05'</span>);</span><br><span class="line"><span class="comment">-- 将字符串转换为相同格式相同进制的日期类型</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">sysdate</span>() <span class="keyword">from</span> dual <span class="keyword">where</span> <span class="keyword">str_to_date</span>(<span class="string">'2019-12-30 19:39:05'</span>,<span class="string">'%Y-%m-%d %H:%i:%s'</span>) > <span class="keyword">str_to_date</span>(<span class="string">'2019-12-30 17:39:05'</span>,<span class="string">'%Y-%m-%d %H:%i:%s'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- Oracle</span></span><br><span class="line"><span class="comment">-- 直接比较</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">sysdate</span> <span class="keyword">from</span> dual <span class="keyword">where</span> <span class="string">'2019-12-30 19:39:05'</span> > <span class="string">'2019-12-30 17:39:05'</span>;</span><br><span class="line"><span class="comment">-- 将字符串转换为相同格式相同进制的日期类型</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">sysdate</span> <span class="keyword">from</span> dual <span class="keyword">where</span> <span class="keyword">to_date</span>(<span class="string">'2019-12-30 19:39:05'</span>,<span class="string">'yyyy-mm-dd hh24:mi:ss'</span>) > <span class="keyword">to_date</span>(<span class="string">'2019-12-30 17:39:05'</span>,<span class="string">'yyyy-mm-dd hh24:mi:ss'</span>);</span><br></pre></td></tr></table></figure><h4 id="返回Map列名大小写问题"><a href="#返回Map列名大小写问题" class="headerlink" title="返回Map列名大小写问题"></a>返回Map列名大小写问题</h4><p>    转换过程发现,使用Hibernate返回实体类型的数据我们可以不用关注列名大小写问题,但是返回Map类型的数据集合时,对Mysql和Oracle返回的Map的key大小写是不一致的,也就是返回列名大小写不统一,对于两数据库不同的系统环境列名大小写情况如下:</p><table><thead><tr><th align="center">系统</th><th align="center">MySQL Data Type</th><th align="center">Oracle Data Type</th></tr></thead><tbody><tr><td align="center">Windows</td><td align="center">默认都不区分大小写,<br>可通过修改配置来区分大小写:<br>lower_case_table_names = 0(0:区分大小写,1:不区分大小写)</td><td align="center">1、在Oracle中,如果字段名称被双引号(””)包裹,Oracle会区分大小写;<br>2、如果字段名称没有被双引号(””)包裹,则全部转换成大写来执行。<br>3、如果表结构设计时,字段名称使用了数据库的保留字,SQL中的字段名称必须用双引号(””)包裹,以避免SQL语句执行出错。</td></tr><tr><td align="center">Linux</td><td align="center">1、数据库名与表名是严格区分大小写的;<br>2、表的别名是严格区分大小写的;<br>3、列名与列的别名在所有的情况下均是忽略大小写的;<br>4、变量名也是严格区分大小写的;</td><td align="center">同Windows</td></tr></tbody></table><p>    根据以上,可以看出,我们要解决大小写问题,需要对返回列表的字段名加引号(””),这种做法工作量过大,于是查看了一下返回Map集合的接口实现,如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> List<Map> <span class="title">findMapResultBySql</span><span class="params">(String sql)</span> </span>{</span><br><span class="line"> SQLQuery query = <span class="keyword">this</span>.getCurrentSession().createSQLQuery(sql);</span><br><span class="line"> query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);</span><br><span class="line"> <span class="keyword">return</span> query.list();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>    很容易可以看出,处理结果集返回的关键是Transformers.ALIAS_TO_ENTITY_MAP,查看源码</p><figure class="highlight java"><figcaption><span>AliasToEntityMapResultTransformer.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AliasToEntityMapResultTransformer</span> <span class="keyword">extends</span> <span class="title">AliasedTupleSubsetResultTransformer</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> AliasToEntityMapResultTransformer INSTANCE = <span class="keyword">new</span> AliasToEntityMapResultTransformer();</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Disallow instantiation of AliasToEntityMapResultTransformer.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">AliasToEntityMapResultTransformer</span><span class="params">()</span> </span>{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">transformTuple</span><span class="params">(Object[] tuple, String[] aliases)</span> </span>{</span><br><span class="line">Map result = <span class="keyword">new</span> HashMap(tuple.length);</span><br><span class="line"><span class="keyword">for</span> ( <span class="keyword">int</span> i=<span class="number">0</span>; i<tuple.length; i++ ) {</span><br><span class="line">String alias = aliases[i];</span><br><span class="line"><span class="keyword">if</span> ( alias!=<span class="keyword">null</span> ) {</span><br><span class="line">result.put( alias, tuple[i] );</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isTransformedValueATupleElement</span><span class="params">(String[] aliases, <span class="keyword">int</span> tupleLength)</span> </span>{</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Serialization hook for ensuring singleton uniqueing.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> The singleton instance : {<span class="doctag">@link</span> #INSTANCE}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> Object <span class="title">readResolve</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">return</span> INSTANCE;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>    可以看出,AliasToEntityMapResultTransformer类的transformTuple方法即是解决问题的关键,于是自定义自己的返回结果集处理工具,如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 返回map统一小写</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomResultTransformer</span> <span class="keyword">extends</span> <span class="title">AliasedTupleSubsetResultTransformer</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> CustomResultTransformer INSTANCE = <span class="keyword">new</span> CustomResultTransformer();</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">CustomResultTransformer</span><span class="params">()</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">transformTuple</span><span class="params">(Object[] tuple, String[] aliases)</span> </span>{</span><br><span class="line"> Map result = <span class="keyword">new</span> HashMap(tuple.length);</span><br><span class="line"> <span class="keyword">for</span> ( <span class="keyword">int</span> i=<span class="number">0</span>; i<tuple.length; i++ ) {</span><br><span class="line"> String alias = aliases[i];</span><br><span class="line"> <span class="keyword">if</span> ( alias!=<span class="keyword">null</span> ) {</span><br><span class="line"> <span class="comment">//将Map的key转为小写返回</span></span><br><span class="line"> result.put( alias.toLowerCase(), tuple[i] );</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isTransformedValueATupleElement</span><span class="params">(String[] aliases, <span class="keyword">int</span> tupleLength)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">private</span> Object <span class="title">readResolve</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> INSTANCE;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>    然后设置SQLQuery的ResultTransformer,如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> CustomResultTransformer ALIAS_TO_ENTITY_LOWERCASE_MAP =</span><br><span class="line">CustomResultTransformer.INSTANCE;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> List<Map> <span class="title">findMapResultBySql</span><span class="params">(String sql)</span> </span>{</span><br><span class="line"> SQLQuery query = <span class="keyword">this</span>.getCurrentSession().createSQLQuery(sql);</span><br><span class="line"> query.setResultTransformer(ALIAS_TO_ENTITY_LOWERCASE_MAP);</span><br><span class="line"> <span class="keyword">return</span> query.list();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>    至此,Oracle和Mysql数据库返回Map列名统一大小写问题得以解决。</p>]]></content>
<summary type="html"><img src="/463fcbf0/mysql-oracle.jpg" class=""></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="database" scheme="https://syshlang.com/categories/database/"/>
<category term="oracle" scheme="https://syshlang.com/categories/database/oracle/"/>
<category term="Oracle" scheme="https://syshlang.com/tags/Oracle/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="Mysql" scheme="https://syshlang.com/tags/Mysql/"/>
</entry>
<entry>
<title>设计模式之创建型的三种工厂模式(Factory Pattern)</title>
<link href="https://syshlang.com/659a32bd/"/>
<id>https://syshlang.com/659a32bd/</id>
<published>2019-09-18T01:18:02.000Z</published>
<updated>2020-09-17T00:34:15.252Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><blockquote><p>    工厂模式(Factory Pattern)主要是为创建对象提供了接口,实际开发中,我们可以通过指定的工厂来生产对象,在工厂中创建对象时,不会对客户端暴露创建逻辑,并且所有的对象都是通过一个共同的工厂(接口)创建出来的,如果创建对象的业务逻辑发生改变,我们只需改动“工厂”的逻辑,这在一定程度上降低了耦合度,达到了解耦的目的。</p></blockquote><a id="more"></a><blockquote><p>    工厂模式(Factory Pattern)可以细分为三类:简单工厂模式(Simple Factory)、 工厂方法模式(Factory Method)、 抽象工厂模式(Abstract Factory)。</p></blockquote><h1 id="简单工厂模式-Simple-Factory"><a href="#简单工厂模式-Simple-Factory" class="headerlink" title="简单工厂模式(Simple Factory)"></a>简单工厂模式(Simple Factory)</h1><blockquote><p>简单工厂模式(Simple Factory)也叫静态工厂模式。</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleFactory</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Shape shape = ShapeSimpleFactory.getShapeByType(<span class="string">"circle"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">Shape</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">String <span class="title">getShapeType</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Circle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getShapeType</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"circle"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getShapeType</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"rectangle"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ShapeSimpleFactory</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Shape <span class="title">getShapeByType</span><span class="params">(String type)</span></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"circle"</span>.equals(type)){</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Circle();</span><br><span class="line"> }<span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">"rectangle"</span>.equals(type)){</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Rectangle();</span><br><span class="line"> }<span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    在上面的例子中,提供了一个ShapeSimpleFactory类,用于封装实例化对象的行为,作为生产几何图形Shape类型对象的“工厂”,该类提供了一个公共的静态方法用于根据类型获取对应的几何图形实体。可以看到这种方式简单粗暴,使用了if…else来做业务逻辑的判断生产对象,试想,那么如果项目的规模变大,Shape的类型增多。。。</p></blockquote><h1 id="工厂方法模式-Factory-Method"><a href="#工厂方法模式-Factory-Method" class="headerlink" title="工厂方法模式(Factory Method)"></a>工厂方法模式(Factory Method)</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FactoryMethod</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> CircleFactory circleFactory = <span class="keyword">new</span> CircleFactory();</span><br><span class="line"> Shape circle = circleFactory.createShape();</span><br><span class="line"> RectangleFactory rectangleFactory = <span class="keyword">new</span> RectangleFactory();</span><br><span class="line"> Shape rectangle = rectangleFactory.createShape();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">Shape</span></span>{}</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Circle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>{ }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>{ }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">ShapeFactoryMethod</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 生产几何图型</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">Shape <span class="title">createShape</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">CircleFactory</span> <span class="keyword">implements</span> <span class="title">ShapeFactoryMethod</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Shape <span class="title">createShape</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Circle();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">RectangleFactory</span> <span class="keyword">implements</span> <span class="title">ShapeFactoryMethod</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Shape <span class="title">createShape</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Rectangle();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    在工厂方法模式的例子中,定义了一个创建对象的父类接口ShapeFactoryMethod,并声明了生产几何图形的方法createShape,由子类工厂实现生产对象的逻辑。乍一看,工厂方法跟简单工厂似乎不一样,但实际上是“换汤不换药”,简单工厂是采用if…else,而工厂方法模式则是将对象的实例化推迟到子类实现。显然,项目的规模变大时,需要创建更多的工厂,该种方式也不适用。</p></blockquote><div class="note info"><p>    简单工厂模式可以看做是工厂方法模式的一种特例,两个归为一类,当项目需要生产的特定对象种类较少时,可以采用这种方式,简单实用。</p></div><h1 id="抽象工厂模式-Abstract-Factory"><a href="#抽象工厂模式-Abstract-Factory" class="headerlink" title="抽象工厂模式(Abstract Factory)"></a>抽象工厂模式(Abstract Factory)</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractFactory</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> ShapeAbstractFactory circlecombination = ShapeAbstractFactory.getFactory(<span class="string">"circlecombination"</span>);</span><br><span class="line"> Shape shape = circlecombination.getShape();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">Shape</span></span>{}</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Circle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>{ }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>{ }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 圆组合</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">CircleCombination</span> <span class="keyword">extends</span> <span class="title">ShapeAbstractFactory</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function">Shape <span class="title">getShape</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Circle();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 矩形组合</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">RectangleCombination</span> <span class="keyword">extends</span> <span class="title">ShapeAbstractFactory</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function">Shape <span class="title">getShape</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Rectangle();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">ShapeAbstractFactory</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> CircleCombination CIRCLECOMBINATION = <span class="keyword">new</span> CircleCombination();</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> RectangleCombination RECTANGLECOMBINATION = <span class="keyword">new</span> RectangleCombination();</span><br><span class="line"> <span class="function"><span class="keyword">static</span> ShapeAbstractFactory <span class="title">getFactory</span><span class="params">(String Combination)</span></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"circlecombination"</span>.equals(Combination)){</span><br><span class="line"> <span class="keyword">return</span> CIRCLECOMBINATION;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"rectanglecombination"</span>.equals(Combination)){</span><br><span class="line"> <span class="keyword">return</span> RECTANGLECOMBINATION;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">abstract</span> Shape <span class="title">getShape</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    看上面的代码例子,可以看到简单工厂和工厂方法的影子,实际上抽象工厂模式可以看作是将简单工厂模式和工厂方法模式进行整合,或者是升级改进版。将工厂抽象成两层,AbstractFactory(抽象工厂)和具体实现的工厂子类,那么我们在创建对象时就可以根据对象的类型特点选择对应的工厂子类进行生产,这样一来,就相当将上面提到的简单工厂模式的单个的工厂类变成了工厂簇,这种方式不仅更利于代码的维护和扩展,而且适用于大规模项目中需要生产大量对象的情况。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><blockquote>
<p>&ensp;&ensp;&ensp;&ensp;工厂模式(Factory Pattern)主要是为创建对象提供了接口,实际开发中,我们可以通过指定的工厂来生产对象,在工厂中创建对象时,不会对客户端暴露创建逻辑,并且所有的对象都是通过一个共同的工厂(接口)创建出来的,如果创建对象的业务逻辑发生改变,我们只需改动“工厂”的逻辑,这在一定程度上降低了耦合度,达到了解耦的目的。</p>
</blockquote></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>设计模式之创建型模式中的单例模式(Singleton Pattern)</title>
<link href="https://syshlang.com/fc936307/"/>
<id>https://syshlang.com/fc936307/</id>
<published>2019-09-16T14:11:01.000Z</published>
<updated>2020-09-17T00:34:15.252Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/fc936307/Singleton.png" class="" title="Singleton"><img src="/fc936307/Singleton1.png" class="" title="Singleton"><a id="more"></a><blockquote><p>    单例模式(Singleton Pattern)是我们平时开发中用的比较多的一种设计模式,如上图所示,所谓类的单例设计模式,就是确保在整个的软件系统中一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,该类只提供一个取得其对象实例的静态方法。</p></blockquote><h1 id="单例设计模式八种方式"><a href="#单例设计模式八种方式" class="headerlink" title="单例设计模式八种方式"></a>单例设计模式八种方式</h1><h2 id="饿汉式"><a href="#饿汉式" class="headerlink" title="饿汉式"></a>饿汉式</h2><h3 id="采用静态常量实现"><a href="#采用静态常量实现" class="headerlink" title="采用静态常量实现"></a>采用静态常量实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HungryStaticConstants</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">HungryStaticConstants</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类内部创建静态对象实例</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> HungryStaticConstants instance = <span class="keyword">new</span> HungryStaticConstants();</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个公有的取得其对象实例的静态方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> HungryStaticConstants <span class="title">getInstance</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    这种方式,在类装载时instance就被实例化,由于类装载原因的不确定性,也就像这种方式的名字所表达的意思一样,饿汉式,没有达到懒加载(lazy loading)的效果,并且还可能造成内存浪费。由于是基于classloder机制的,避免了多线程的同步问题,是多线程安全的,并且没有锁机制,因此执行效率会提高。</p></blockquote><h3 id="采用静态代码块实现"><a href="#采用静态代码块实现" class="headerlink" title="采用静态代码块实现"></a>采用静态代码块实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HungryStaticBlock</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">HungryStaticBlock</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> HungryStaticBlock instance;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在静态代码块中,创建单例对象</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> instance = <span class="keyword">new</span> HungryStaticBlock();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个公有的取得其对象实例的静态方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> HungryStaticBlock <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    这种方式和上面的方式差不多,只不过是将类的实例化放在了静态代码块中进行,static块的执行发生在初始化的阶段。初始化阶段,jvm主要完成对静态变量的初始化,静态块执行等工作,也就是说instance在这个时候被实例化,其优缺点和上面的方式是一样。</p></blockquote><h2 id="懒汉式"><a href="#懒汉式" class="headerlink" title="懒汉式"></a>懒汉式</h2><h3 id="线程不安全"><a href="#线程不安全" class="headerlink" title="线程不安全"></a>线程不安全</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LazyThreadUnsafe</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">LazyThreadUnsafe</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> LazyThreadUnsafe instance;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个静态的公有方法,当使用到该方法时,才去实例化instance</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> LazyThreadUnsafe <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> instance = <span class="keyword">new</span> LazyThreadUnsafe();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    与饿汉式不一样的地方,显然这种方式达到了懒加载(lazy loading)的效果。但是由于这种方式没有加锁 synchronized,它不是多线程安全的,在多线程下会有产生多个实例的可能。</p></blockquote><h3 id="线程安全"><a href="#线程安全" class="headerlink" title="线程安全"></a>线程安全</h3><h4 id="采用同步方法的实现"><a href="#采用同步方法的实现" class="headerlink" title="采用同步方法的实现"></a>采用同步方法的实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LazyThreadSafeSyncMethod</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">LazyThreadSafeSyncMethod</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> LazyThreadSafeSyncMethod instance;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * /提供一个静态的公有方法,加入同步锁,解决线程安全问题</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> LazyThreadSafeSyncMethod <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> instance = <span class="keyword">new</span> LazyThreadSafeSyncMethod();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    很显然,这种方式达到了懒加载(lazy loading)的效果,并且对方法加了同步锁,解决了线程安全问题,但是每个线程在获得实例执行getInstance()方法时都要进行同步,效率很低。</p></blockquote><h4 id="采用同步代码块实现"><a href="#采用同步代码块实现" class="headerlink" title="采用同步代码块实现"></a>采用同步代码块实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LazyThreadSafeSyncBlock</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">LazyThreadSafeSyncBlock</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> LazyThreadSafeSyncBlock instance;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个静态的公有方法,对代码块加入同步锁,解决线程安全问题</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> LazyThreadSafeSyncBlock <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> <span class="keyword">synchronized</span> (LazyThreadSafeSyncBlock.class){</span><br><span class="line"> instance = <span class="keyword">new</span> LazyThreadSafeSyncBlock();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    这种方式和上面的方式差不多,只不过是将同步锁从方法上移到了代码块上,实际效果也不理想。</p></blockquote><h2 id="双检锁-双重校验锁-DCL-double-checked-locking"><a href="#双检锁-双重校验锁-DCL-double-checked-locking" class="headerlink" title="双检锁/双重校验锁(DCL:double-checked locking)"></a>双检锁/双重校验锁(DCL:double-checked locking)</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DoubleCheckedLock</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">DoubleCheckedLock</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> DoubleCheckedLock instance;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个静态的公有方法,加入双重检查代码和同步锁,解决线程安全问题,同时解决懒加载问题</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> DoubleCheckedLock <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> <span class="keyword">synchronized</span> (DoubleCheckedLock.class){</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> instance = <span class="keyword">new</span> DoubleCheckedLock();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    这种方式可以看作是上面两种方式的结合体或者升级方式,这种方式采用了双重校验加锁的机制,既达到了懒加载(lazy loading)的效果,又保证了线程安全,而且效率较高。</p></blockquote><div class="note info"><p>    volatile是一个类型修饰符(type specifier).volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。<br>volatile关键字的两层语义:</p><ul><li>保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的;</li><li>禁止进行指令重排序。</li></ul></div><h2 id="登记式-静态内部类"><a href="#登记式-静态内部类" class="headerlink" title="登记式/静态内部类"></a>登记式/静态内部类</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticInternalClass</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造器私有化,防止new</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">StaticInternalClass</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个静态内部类,</span></span><br><span class="line"><span class="comment"> * 该类中有一个静态属性StaticInternalClass</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonHolder</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> StaticInternalClass INSTANCE = <span class="keyword">new</span> StaticInternalClass();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提供一个静态的公有方法,直接返回内部类的静态属性</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> StaticInternalClass <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> SingletonHolder.INSTANCE;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    首先,这种方式采用了类装载的机制来保证初始化实例时只有一个线程(在类进行初始化时,别的线程是无法进入的),巧妙的解决了线程安全问腿;其次,静态内部类的方式在SingletonHolder类被装载时并不会立即实例化,而是在需要实例化(调用getInstance方法)时,才会装载SingletonHolder类,从而完成StaticInternalClass的实例化,也很巧妙的达到了懒加载(lazy loading)的效果。当然,也不会存在效率低的问题。</p></blockquote><h2 id="枚举"><a href="#枚举" class="headerlink" title="枚举"></a>枚举</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonEnum</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Instance instance = Singleton.INSTANCE.instance;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Instance</span></span>{}</span><br><span class="line"> <span class="class"><span class="keyword">enum</span> <span class="title">Singleton</span></span>{</span><br><span class="line"> INSTANCE;</span><br><span class="line"> <span class="keyword">private</span> Instance instance;</span><br><span class="line"> Singleton() {</span><br><span class="line"> instance = <span class="keyword">new</span> Instance();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    首先,枚举类的构造方法限制为私有的,我们访问枚举类的实例时会执行它的构造方法,并且每个枚举类的实例都是static final类型的,也就是只能被实例化一次,实际也就是通过类加载机制保证了线程安全。</p></blockquote><h1 id="单例模式在Spring框架中的应用"><a href="#单例模式在Spring框架中的应用" class="headerlink" title="单例模式在Spring框架中的应用"></a>单例模式在Spring框架中的应用</h1><blockquote><p>    先上源码,org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)</p></blockquote><figure class="highlight java"><figcaption><span>DefaultSingletonBeanRegistry.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Return the (raw) singleton object registered under the given name.</span></span><br><span class="line"><span class="comment"> * <p>Checks already instantiated singletons and also allows for an early</span></span><br><span class="line"><span class="comment"> * reference to a currently created singleton (resolving a circular reference).</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> beanName the name of the bean to look for</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> allowEarlyReference whether early references should be created or not</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the registered singleton object, or {<span class="doctag">@code</span> null} if none found</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">getSingleton</span><span class="params">(String beanName, <span class="keyword">boolean</span> allowEarlyReference)</span> </span>{</span><br><span class="line">Object singletonObject = <span class="keyword">this</span>.singletonObjects.get(beanName);</span><br><span class="line"><span class="keyword">if</span> (singletonObject == <span class="keyword">null</span> && isSingletonCurrentlyInCreation(beanName)) {</span><br><span class="line"><span class="keyword">synchronized</span> (<span class="keyword">this</span>.singletonObjects) {</span><br><span class="line">singletonObject = <span class="keyword">this</span>.earlySingletonObjects.get(beanName);</span><br><span class="line"><span class="keyword">if</span> (singletonObject == <span class="keyword">null</span> && allowEarlyReference) {</span><br><span class="line">ObjectFactory<?> singletonFactory = <span class="keyword">this</span>.singletonFactories.get(beanName);</span><br><span class="line"><span class="keyword">if</span> (singletonFactory != <span class="keyword">null</span>) {</span><br><span class="line">singletonObject = singletonFactory.getObject();</span><br><span class="line"><span class="keyword">this</span>.earlySingletonObjects.put(beanName, singletonObject);</span><br><span class="line"><span class="keyword">this</span>.singletonFactories.remove(beanName);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> (singletonObject != NULL_OBJECT ? singletonObject : <span class="keyword">null</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><img src="/fc936307/AbstractBeanFactory.png" class="" title="AbstractBeanFactory类图"><img src=http://www.plantuml.com/plantuml/svg/ZPBFIiD04CRl-nH3lIYsJs2HQlrpiz3a9XusoIIkJdVZPeC4zII-WNWHZqAFIl4az6cixMEuQM8j6ajE2_FzllbcXkqaXckJ3eYvmX12OyTBZEQ-sKKk3-ohTFOnVfgzFNoEXfExvmZdokpbTde_dBw-Jnx73SPB3_Z4amGgMln6od9Ez34ILikSD8wLDgm0zZ3aAHb7o8ZGABbCClQ_7ThNhLRb1Aiw5guLGzLO4QxO9iIfHyA7ddU6bYsFjUuORLD1yW5kRB4rYBKoLiS0skusk12emv8CXUG4ItmJYb8tZyrfZHUfq1YuMRmGYxZZ4-0wIfhWAKMs6HYBT4_HF-z9ocpmJOtRLYwn8BytyQpZwEysDHm_qt4YTRdFDMLz356Zz74-OmTbOF_Z5m00><blockquote><p>     如上,Spring依赖注入Bean实例默认是单例的,Spring的依赖注入主要是在org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)方法中,getBean中调用的 doGetBean 方法调用了getSingleton 进行bean的创建,从上面代码可以看到,spring依赖注入时,使用了双重判断加锁的单例模式。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXBhdHRlcm5z">https://github.com/syshlang/java-design-patterns<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-patterns&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><img src="/fc936307/Singleton.png" class="" title="Singleton">
<img src="/fc936307/Singleton1.png" class="" title="Singleton"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>设计模式七大原则之合成复用原则(Composite Reuse Principle)</title>
<link href="https://syshlang.com/fd78ccb3/"/>
<id>https://syshlang.com/fd78ccb3/</id>
<published>2019-09-02T14:50:32.000Z</published>
<updated>2020-09-17T00:34:15.260Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    合成复用原则(CRP:Composite Reuse Principle)又称为组合/聚合复用原则(CARP:Composition/Aggregate Reuse Principle,),该原则指出尽量使用合成/聚合,尽量不要使用类继承。</p><a id="more"></a><p>    在面向对象设计中,其中一个很重要的目标 就是提高软件的高可复用性。而复用已有的设计和实现通常有两种方法,也就是上面提到的,通过组合/聚合关系或通过继承。但是,合成复用原则主张优先考虑使用组合/聚合的方式来达到复用的目的。<br>    为什么要这么主张呢?<br>    实际上在<a href="/64719d09/" title="《设计模式七大原则之里氏代换原则(Liskov Substitution Principle)》">《设计模式七大原则之里氏代换原则(Liskov Substitution Principle)》</a>一文中,我们就提到继承实际上是增强了两个类耦合性,子类在继承基类时,会将基类的实现细节暴露给子类,基类的内部细节通常对子类来说是可见的,其实这种复用又叫作<strong>“白箱”复用</strong>。这种复用容易在“不知情”的情况下破坏系统的封装性,所以遵循里氏代换原则,我们优先通过聚合,组合,依赖等方式来解决问题。<br>    组合/聚合复用有什么好处?<br>    通过组合或聚合达到复用目的的做法实际上是,将已有的成员对象加入到新的对象中,让其成为新对象的一部分,而不破坏原有对象的封装,这样使得成员对象的内部细节不会暴露给新对象,所需的依赖较少,相对于继承复用来说,这种方式降低了耦合性,这种复用又叫作<strong>“黑箱”复用</strong>。</p><div class="note info"><p><strong>合成</strong>:表示一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。<br>合成关系用实心的菱形+实线来表示,如下图:<br><img src="/fd78ccb3/Composition.gif" class="" title="Composition"><br><strong>聚合</strong>:表示一种弱的拥有关系,体现的是A对象可以包含B对象,但是B对象并不是A对象的一部分。<br>聚合关系用空心的菱形+实线来表示,如下图:<br><img src="/fd78ccb3/Aggregate.gif" class="" title="Aggregate"></p></div><p>    合成/聚合复用原则在设计模式中最好的体现就是桥接(Bridge)模式,后面介绍设计模式时再继续介绍。</p><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;合成复用原则(CRP:Composite Reuse Principle)又称为组合/聚合复用原则(CARP:Composition/Aggregate Reuse Principle,),该原则指出尽量使用合成/聚合,尽量不要使用类继承。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>设计模式七大原则之迪米特法则(Demeter Principle)</title>
<link href="https://syshlang.com/8a7ffc25/"/>
<id>https://syshlang.com/8a7ffc25/</id>
<published>2019-09-01T13:28:20.000Z</published>
<updated>2020-09-17T00:34:15.260Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    迪米特法则(LOD:Law of Demeter/Demeter Principle),又叫最少知道原则(LKP:Least Knowledge Principle),即一个类对自己依赖的类知道的越少越好。</p><a id="more"></a><p>    其实,迪米特法则反应出来的核心思想还是编程中总的原则:低耦合,高内聚。类与类关系越密切,耦合度越大,如果实际的需求发生改变,我们需要更改软件,当一个类改动时,另一个或多个类跟这个类的关系越密切(耦合度越高),受到的影响也越大。迪米特法则还有一个更简单的定义:只与直接的朋友通信。</p><div class="note info"><p><strong>直接的朋友</strong>:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。</p></div><blockquote><p>举一个打印员工绩效的例子</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demeterprinciple</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> DevelopmentCenterManage.showPerformance();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心员工</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DevelopmentCenter</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> String performance;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getPerformance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> performance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPerformance</span><span class="params">(String performance)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.performance = performance;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心的开发一部员工</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">FirstDepartment</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> String performance;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getPerformance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> performance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPerformance</span><span class="params">(String performance)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.performance = performance;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心的开发一部员工管理类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">FirstDepartmentManager</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> List<FirstDepartment> <span class="title">getFirstDepartment</span><span class="params">()</span></span>{</span><br><span class="line"> List<FirstDepartment> firstDepartmentList = <span class="keyword">new</span> ArrayList<FirstDepartment>();</span><br><span class="line"> FirstDepartment firstDepartment = <span class="keyword">new</span> FirstDepartment();</span><br><span class="line"> firstDepartment.setName(<span class="string">"zhangsan"</span>);</span><br><span class="line"> firstDepartment.setPerformance(<span class="string">"A"</span>);</span><br><span class="line"> firstDepartmentList.add(firstDepartment);</span><br><span class="line"> <span class="keyword">return</span> firstDepartmentList;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心管理类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DevelopmentCenterManage</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取开发中心所有员工绩效</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> List<DevelopmentCenter> <span class="title">getDevelopmentCenter</span><span class="params">()</span></span>{</span><br><span class="line"> List<DevelopmentCenter> developmentCenterList = <span class="keyword">new</span> ArrayList<DevelopmentCenter>();</span><br><span class="line"> DevelopmentCenter developmentCenter = <span class="keyword">new</span> DevelopmentCenter();</span><br><span class="line"> developmentCenter.setName(<span class="string">"zhangsan"</span>);</span><br><span class="line"> developmentCenter.setPerformance(<span class="string">"A"</span>);</span><br><span class="line"> developmentCenterList.add(developmentCenter);</span><br><span class="line"> <span class="keyword">return</span> developmentCenterList;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 打印绩效</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">showPerformance</span><span class="params">()</span></span>{</span><br><span class="line"> List<DevelopmentCenter> developmentCenterList = getDevelopmentCenter();</span><br><span class="line"> <span class="keyword">for</span> (DevelopmentCenter developmentCenter : developmentCenterList ){</span><br><span class="line"> System.out.println(<span class="string">"name:"</span>+ developmentCenter.getName() + <span class="string">" performance:"</span>+ developmentCenter.getPerformance());</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 开发中心的开发一部员工普遍绩效比较优秀也要打印出来</span></span><br><span class="line"> <span class="comment">// 但此处引入了DevelopmentCenterManage的非直接朋友类FirstDepartment,违反了迪米特法则</span></span><br><span class="line"> List<FirstDepartment> firstDepartmentList = FirstDepartmentManager.getFirstDepartment();</span><br><span class="line"> <span class="keyword">for</span> (FirstDepartment firstDepartment : firstDepartmentList) {</span><br><span class="line"> System.out.println(<span class="string">"name:"</span>+ firstDepartment.getName() + <span class="string">" performance:"</span>+ firstDepartment.getPerformance());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    在上面的例子中,我们想打印出开发中心所有员工的绩效情况,但是由于开发中心的开发一部员工普遍表现优秀,所以也想一起打印出来,但共用了DevelopmentCenterManage类的打印方法,最终导致引入了DevelopmentCenterManage的非直接朋友类FirstDepartment,违反了迪米特法则,这样显然是增加了不必要的耦合。因此,改进如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demeterprinciple1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> DevelopmentCenterManage.showPerformance();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心员工</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DevelopmentCenter</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> String performance;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getPerformance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> performance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPerformance</span><span class="params">(String performance)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.performance = performance;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心的开发一部员工</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">FirstDepartment</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> String performance;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getPerformance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> performance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPerformance</span><span class="params">(String performance)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.performance = performance;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心的开发一部员工管理类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">FirstDepartmentManager</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> List<FirstDepartment> <span class="title">getFirstDepartment</span><span class="params">()</span></span>{</span><br><span class="line"> List<FirstDepartment> firstDepartmentList = <span class="keyword">new</span> ArrayList<FirstDepartment>();</span><br><span class="line"> FirstDepartment firstDepartment = <span class="keyword">new</span> FirstDepartment();</span><br><span class="line"> firstDepartment.setName(<span class="string">"zhangsan"</span>);</span><br><span class="line"> firstDepartment.setPerformance(<span class="string">"A"</span>);</span><br><span class="line"> firstDepartmentList.add(firstDepartment);</span><br><span class="line"> <span class="keyword">return</span> firstDepartmentList;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 增加独立的打印方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">showFirstDepartmentPerformance</span><span class="params">()</span></span>{</span><br><span class="line"> List<FirstDepartment> firstDepartmentList = getFirstDepartment();</span><br><span class="line"> <span class="keyword">for</span> (FirstDepartment firstDepartment : firstDepartmentList) {</span><br><span class="line"> System.out.println(<span class="string">"name:"</span>+ firstDepartment.getName() + <span class="string">" performance:"</span>+ firstDepartment.getPerformance());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 开发中心管理类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DevelopmentCenterManage</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取开发中心所有员工绩效</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> List<DevelopmentCenter> <span class="title">getDevelopmentCenter</span><span class="params">()</span></span>{</span><br><span class="line"> List<DevelopmentCenter> developmentCenterList = <span class="keyword">new</span> ArrayList<DevelopmentCenter>();</span><br><span class="line"> DevelopmentCenter developmentCenter = <span class="keyword">new</span> DevelopmentCenter();</span><br><span class="line"> developmentCenter.setName(<span class="string">"zhangsan"</span>);</span><br><span class="line"> developmentCenter.setPerformance(<span class="string">"A"</span>);</span><br><span class="line"> developmentCenterList.add(developmentCenter);</span><br><span class="line"> <span class="keyword">return</span> developmentCenterList;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 打印绩效</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">showPerformance</span><span class="params">()</span></span>{</span><br><span class="line"> List<DevelopmentCenter> developmentCenterList = getDevelopmentCenter();</span><br><span class="line"> <span class="keyword">for</span> (DevelopmentCenter developmentCenter : developmentCenterList ){</span><br><span class="line"> System.out.println(<span class="string">"name:"</span>+ developmentCenter.getName() + <span class="string">" performance:"</span>+ developmentCenter.getPerformance());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 遵循迪米特法则,这里调用FirstDepartmentManager类自己封装的打印方法,</span></span><br><span class="line"> <span class="comment">// 不在引入非直接朋友类FirstDepartment</span></span><br><span class="line"> FirstDepartmentManager.showFirstDepartmentPerformance();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    迪米特法则的核心是降低类之间的耦合,在实际开发的过程中,对于被依赖的类不管多么复杂,我们都应尽量将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。当然,这不是要求完全没有依赖关系,使用迪米特法则时我们应当根据实际情况权衡,尽量降低类间(对象间)耦合关系。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;迪米特法则(LOD:Law of Demeter/Demeter Principle),又叫最少知道原则(LKP:Least Knowledge Principle),即一个类对自己依赖的类知道的越少越好。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>设计模式七大原则之开闭原则 (Open Close Principle)</title>
<link href="https://syshlang.com/1376ad9f/"/>
<id>https://syshlang.com/1376ad9f/</id>
<published>2019-08-28T02:42:38.000Z</published>
<updated>2020-09-17T00:34:15.260Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    开闭原则 (OCP:Open Close Principle)是编程中最基础、最重要的设计原则。它指出,一个软件中的对象(类,模块,函数等等)应该对于扩展是开放的(对提供方),但是对于修改是封闭的(对使用方)。</p><a id="more"></a><blockquote><p>举一个计算几何形状周长的例子</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Openclose</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> CalculatePerimeter calculatePerimeter = <span class="keyword">new</span> CalculatePerimeter();</span><br><span class="line"> calculatePerimeter.rectanglePerimeter(<span class="number">8</span>,<span class="number">4</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 计算几何图形周长的工具类,提供了一个计算矩形周长的方法</span></span><br><span class="line"><span class="comment"> * 这个种方式扩展性不好,如果新增一个计算圆形的周长,</span></span><br><span class="line"><span class="comment"> * 需要改动类,增加新的方法(违背开闭原则)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">CalculatePerimeter</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 计算矩形周长</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> length</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> width</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">rectanglePerimeter</span><span class="params">(<span class="keyword">double</span> length,<span class="keyword">double</span> width)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> (length + width) * <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    在上面的例子中,CalculatePerimeter类用于计算几何图形周长,并提供了一个计算矩形周长的方法,这种设计方式违反了设计模式的ocp原则,假如我们需要计算其他图形的周长,需要改动原有的类,增加新的方法,如果业务复杂需要改动的地方会更多,扩展性不好很差。改进方式如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Openclose1</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> CalculatePerimeter calculatePerimeter = <span class="keyword">new</span> CalculatePerimeter();</span><br><span class="line"> Rectangle rectangle = <span class="keyword">new</span> Rectangle(<span class="number">8</span>,<span class="number">4</span>);</span><br><span class="line"> calculatePerimeter.calculatePerimeter(rectangle);</span><br><span class="line"> <span class="comment">//如果需要增加计算圆周长,只需自行扩展圆类型</span></span><br><span class="line"> Circle circle = <span class="keyword">new</span> Circle(<span class="number">4</span>);</span><br><span class="line"> calculatePerimeter.calculatePerimeter(circle);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 计算几何图形周长的工具类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">CalculatePerimeter</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">calculatePerimeter</span><span class="params">(Shape shape)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> shape.shapePerimeter();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 抽象出几何图形基类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Shape</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">double</span> <span class="title">shapePerimeter</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在矩形中实现计算周长的细节</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">extends</span> <span class="title">Shape</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">double</span> length;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">double</span> width;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Rectangle</span><span class="params">(<span class="keyword">double</span> length, <span class="keyword">double</span> width)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.length = length;</span><br><span class="line"> <span class="keyword">this</span>.width = width;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">shapePerimeter</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (length + width) * <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 扩展计算圆形周长</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Circle</span> <span class="keyword">extends</span> <span class="title">Shape</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">double</span> π = <span class="number">3.14</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">double</span> radius;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Circle</span><span class="params">(<span class="keyword">double</span> radius)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.radius = radius;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">shapePerimeter</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span> * π * radius;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    开闭原则体现出来的思想就是用抽象构建框架,用实现扩展细节。抽象的灵活性好,适应性广,易扩展,在框架设计时,我们要设计合理的抽象基类,在抽象派生的实现类中实现细节部分,这样当软件需要变化时,可以通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现,这种方式从一定程度上保证了软件架构的稳定性。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;开闭原则 (OCP:Open Close Principle)是编程中最基础、最重要的设计原则。它指出,一个软件中的对象(类,模块,函数等等)应该对于扩展是开放的(对提供方),但是对于修改是封闭的(对使用方)。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>设计模式七大原则之里氏代换原则(Liskov Substitution Principle)</title>
<link href="https://syshlang.com/64719d09/"/>
<id>https://syshlang.com/64719d09/</id>
<published>2019-08-23T08:18:16.000Z</published>
<updated>2020-09-17T00:34:15.256Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    里氏代换原则(LSP:Liskov Substitution Principle)指出:如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。<br>    换句话说,所有引用基类的地方必须能透明地使用其子类的对象。对于子类而言,可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:</p><a id="more"></a><blockquote><ul><li>子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;</li></ul></blockquote><ul><li>子类中可以增加自己特有的方法;</li><li>当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;</li><li>当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。</li></ul><blockquote><p>还是举一个交通工具的例子</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Liskovsubstitution</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Transportation transportation = <span class="keyword">new</span> Transportation();</span><br><span class="line"> transportation.run(<span class="string">"轮船"</span>);</span><br><span class="line"> Transportation1 transportation1 = <span class="keyword">new</span> Transportation1();</span><br><span class="line"> transportation1.run(<span class="string">"轮船"</span>);</span><br><span class="line"> transportation1.runSpeed(<span class="number">120</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Transportation</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String transportation)</span> </span>{</span><br><span class="line"> System.out.println(transportation + <span class="string">" 在水中航行...."</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Transportation1</span> <span class="keyword">extends</span> <span class="title">Transportation</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 覆盖父类的方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> vehicle</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">" 在公路上运行...."</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">runSpeed</span><span class="params">(<span class="keyword">int</span> runSpeed)</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"行驶速度为:"</span>+ runSpeed);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    由上面的例子我们可以看出继承的风险,Transportation类有一个打印交通工具行驶方式行驶方式的功能,且该功能只适用于水中运行的交通工具,刚开始一切正常。但是,现在多了一个新的需求,要打印交通工具的行驶速度,类Transportation1来负责实现,于是Transportation1继承Transportation完成第二个功能,但是在调用者不知道的情况下无意间覆盖(重写)了父类中的方法,导致原本正常的功能发生逻辑错误。改进方式:去掉原有的继承关系,让父类和子类都继承一个更通俗的基类,使用组合方式完成功能。如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Liskovsubstitution1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> TransportationSpeed transportationSpeed = <span class="keyword">new</span> TransportationSpeed(<span class="string">"轮船"</span>,<span class="number">120</span>);</span><br><span class="line"> transportationSpeed.runSpeed();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Transportation</span></span>{</span><br><span class="line"> <span class="keyword">public</span> String way;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">int</span> speed;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TransportationWay</span> <span class="keyword">extends</span> <span class="title">Transportation</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String transportation)</span> </span>{</span><br><span class="line"> System.out.println(transportation + <span class="string">" 在水中航行...."</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TransportationSpeed</span> <span class="keyword">extends</span> <span class="title">Transportation</span></span>{</span><br><span class="line"> <span class="comment">//如果需要使用TransportationWay类的方法,使用组合关系</span></span><br><span class="line"> <span class="keyword">private</span> TransportationWay transportationWay = <span class="keyword">new</span> TransportationWay();</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">TransportationSpeed</span><span class="params">(String way,<span class="keyword">int</span> speed)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.way = way;</span><br><span class="line"> <span class="keyword">this</span>.speed = speed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">TransportationSpeed</span><span class="params">()</span> </span>{</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">runSpeed</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="comment">//组合调用TransportationWay类run方法获取行驶方式</span></span><br><span class="line"> transportationWay.run(way);</span><br><span class="line"> System.out.println(<span class="string">"行驶速度为:"</span>+ speed);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>    里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在实际开发的过程中,使用继承时,我们应当遵循里氏替换原则,在子类中尽量不要重写父类的方法,适当情况下,我们可以通过聚合,组合,依赖等方式来解决问题。</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;里氏代换原则(LSP:Liskov Substitution Principle)指出:如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。<br>&ensp;&ensp;&ensp;&ensp;换句话说,所有引用基类的地方必须能透明地使用其子类的对象。对于子类而言,可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>设计模式七大原则之依赖倒转原则 (Dependence Inversion Principle)</title>
<link href="https://syshlang.com/fa1508aa/"/>
<id>https://syshlang.com/fa1508aa/</id>
<published>2019-08-23T03:04:25.000Z</published>
<updated>2020-09-17T00:34:15.256Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    依赖倒转原则(DIP: Dependence Inversion Principle)也说依赖倒置原则,包含三层含义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。依赖倒转(倒置)的中心思想就是面向接口编程。</p><a id="more"></a><blockquote><p>举个我们日常通信的例子</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Dependenceinversion</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> People people = <span class="keyword">new</span> People();</span><br><span class="line"> people.sendMessageBySMS(<span class="keyword">new</span> SMScommunicate());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SMScommunicate</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"使用手机短信发送信息!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">People</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessageBySMS</span><span class="params">(SMScommunicate smScommunicate)</span></span>{</span><br><span class="line"> smScommunicate.sendMessage();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>在很久之前,互联不发达时,我们通信一般采用手机发送短信或者打电话,如上面的代码,一切正常。但是,随机互联网的普及更多的通信方式出现了,例如微信、QQ等,需求场景发生变化,那么最简单的做法就是新增微信和QQ的通讯类,并且给People增加相应的方法。显然,这种方法不能满足多变性需求,且不稳定。所以,我们使用另一种思路解决,如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Dependenceinversion1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> People people = <span class="keyword">new</span> People();</span><br><span class="line"> people.sendMessage(<span class="keyword">new</span> SMScommunicate());</span><br><span class="line"> people.sendMessage(<span class="keyword">new</span> QQcommunicate());</span><br><span class="line"> people.sendMessage(<span class="keyword">new</span> Wechatcommunicate());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">Communicate</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SMScommunicate</span> <span class="keyword">implements</span> <span class="title">Communicate</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"使用手机短信发送信息!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">QQcommunicate</span> <span class="keyword">implements</span> <span class="title">Communicate</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"使用QQ发送信息!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Wechatcommunicate</span> <span class="keyword">implements</span> <span class="title">Communicate</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"使用微信发送信息!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">People</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">(Communicate communicate)</span></span>{</span><br><span class="line"> communicate.sendMessage();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>根据依赖倒置原则,在新的解决方案中,我们引入了一个通讯工具的接口Communicate,让几种不同的通信方式去实现接口,这样修改后,无论以后怎样扩展,都不需要再修改People类了。</p></blockquote><blockquote><p><strong>依赖关系传递的三种方式</strong></p></blockquote><ul><li><p>接口声明依赖</p><blockquote><p>在上面日常通信的例子中,我们在用的就是接口声明依赖的方式,该方法也叫做接口注入。</p></blockquote></li><li><p>构造函数传递依赖对象</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造函数传递依赖对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">People</span> <span class="keyword">implements</span> <span class="title">Communicate</span></span>{</span><br><span class="line"> <span class="keyword">private</span> Communicate communicate;</span><br><span class="line"> <span class="comment">//构造函数注入</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">People</span><span class="params">(Communicate communicate)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.communicate = communicate;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> communicate.sendMessage();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Communicate</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>Setter方法传递依赖对象</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Setter方法传递依赖对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">People1</span> <span class="keyword">implements</span> <span class="title">Communicate1</span></span>{</span><br><span class="line"> <span class="keyword">private</span> Communicate communicate;</span><br><span class="line"> <span class="comment">//Setter依赖注入</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCommunicate</span><span class="params">(Communicate communicate)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.communicate = communicate;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>{</span><br><span class="line"> communicate.sendMessage();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Communicate1</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><div class="note info"><p>    在java中,抽象指的是接口或抽象类,细节就是具体的实现类,相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。在实际的开发中,低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好;变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化;使用继承时遵循 <a href="/64719d09/" title="里氏代换原则(Liskov Substitution Principle)">里氏代换原则(Liskov Substitution Principle)</a>。</p></div><p> <font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;依赖倒转原则(DIP: Dependence Inversion Principle)也说依赖倒置原则,包含三层含义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。依赖倒转(倒置)的中心思想就是面向接口编程。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>设计模式七大原则之接口隔离原则 (Interface Segregation Principle)</title>
<link href="https://syshlang.com/8d12383c/"/>
<id>https://syshlang.com/8d12383c/</id>
<published>2019-08-18T09:06:06.000Z</published>
<updated>2020-09-17T00:34:15.256Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>     接口隔离原则 (ISP: Interface Segregation Principle)有两种定义:客户端不应该依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上。</p><a id="more"></a><blockquote><p>类之间通过接口依赖的例子</p></blockquote> <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Interfacesegregation</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> B b = <span class="keyword">new</span> B();</span><br><span class="line"> b.dependA(<span class="keyword">new</span> A());</span><br><span class="line"> }</span><br><span class="line"> <span class="class"><span class="keyword">interface</span> <span class="title">InterfaceCommon</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">methodOther</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">A</span> <span class="keyword">implements</span> <span class="title">InterfaceCommon</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"A类方法"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodOther</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"其他类方法"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">B</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">dependA</span><span class="params">(InterfaceCommon interfaceCommon)</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"通过公共接口依赖A类调用A类方法"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>在上面的例子中可以看出,我们使用B类时想通过公共接口InterfaceCommon依赖A类,调用A类实现的方法,但是A类在实现自己的方法时还必须去实现其他类的方法。因此,InterfaceCommon对于B来说不是最小的接口,违背了接口隔离原则。更改方案,将InterfaceCommon拆分为独立的接口,如下:</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Interfacesegregation1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> B b = <span class="keyword">new</span> B();</span><br><span class="line"> b.dependC(<span class="keyword">new</span> A());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">InterfaceA</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">interface</span> <span class="title">InterfaceOther</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">methodOther</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">A</span> <span class="keyword">implements</span> <span class="title">InterfaceA</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"A类方法"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">B</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">dependC</span><span class="params">(InterfaceA interfaceA)</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"通过最小接口依赖A类调用A类方法"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>采用接口隔离原则对接口进行约束时,要注意以下几点:</p></blockquote><ul><li>接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。</li><li>为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。</li><li>提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。</li></ul><div class="note info"><p>接口隔离原则和单一职责的异同:</p><ul><li><p>共同点:<br>这两种原则都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想。</p></li><li><p>不同点:</p></li></ul><ol><li>侧重点不一样,单一职责原则注重的是类的功能职责单一;接口隔离原则注重的是对接口依赖的隔离;</li><li>约束对象不一样,单一职责原则主要约束类,它针对的是类的功能职责,程序的实现和细节;接口隔离原则主要约束接口,它针对的是接口模板功能的设计构建。</li></ol></div><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p> &ensp;&ensp;&ensp;&ensp;接口隔离原则 (ISP: Interface Segregation Principle)有两种定义:客户端不应该依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>Linux上安装 MySQL</title>
<link href="https://syshlang.com/728791e9/"/>
<id>https://syshlang.com/728791e9/</id>
<published>2019-08-10T01:15:41.000Z</published>
<updated>2020-09-25T08:41:02.609Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/77d59a46/MySQL.png" class="" title="Mysql"><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>     <a href="/7d2a91d4/" title="上一篇文章">上一篇文章</a>中,讲到了在Window上通过绿色版压缩包安装的方式安装MySQL,本文继续讲解在Linux系统环境下安装MySQL。Deepin下安装MySQL三种方式:</p><blockquote><p> <strong>在线安装:</strong>通过命令sudo apt-get install mysql-server在线安装,安装完毕之后已经自动配置好环境变量,可以直接使用,比Window下方便很多;<br><strong>二进制包安装:</strong>在网上下载二进制安装包,通过sudo dpkg -i [deb包名]进行安装,安装完毕之后已经自动配置好环境变量,可以直接使用;<br><strong>离线安装:</strong>通过下载离线安装包进行配置安装。</p></blockquote><p>     在线安装和二进制包安装相对比较简单,不同的Linux发行版本安装命令也各有差异,离线安装的方式通用性相对更强,不同的Linux版本安装方式也大同小异,本文重点也是讲述离线的安装方式。</p><h1 id="一、准备工作"><a href="#一、准备工作" class="headerlink" title="一、准备工作"></a>一、准备工作</h1><h2 id="1、系统环境"><a href="#1、系统环境" class="headerlink" title="1、系统环境"></a>1、系统环境</h2><p>     Linux系统的发行版本较多,本此安装是在Deepin 20 Beta环境为例,具体参数如下:</p><img src="/728791e9/installmysql.png" class="" title="Deepin 20 Beta"><blockquote><p>Linux version 5.4.50-amd64-desktop linux内核版本号</p></blockquote><h2 id="2、下载安装包"><a href="#2、下载安装包" class="headerlink" title="2、下载安装包"></a>2、下载安装包</h2><p>     进入<span class="exturl" data-url="aHR0cHM6Ly9kZXYubXlzcWwuY29tL2Rvd25sb2Fkcy9teXNxbC8=">MySQL 下载<i class="fa fa-external-link-alt"></i></span>,可以看到mysql的下载包列表。我选择的是8.0.21版本。<br>     Deepin和Ubuntu都是基于Debian的,他们的软件包管理器相同,都用的apt/dpkg,如果是采用第二种方式安装,就下载相应的deb包进行安装,如下图所示。</p><img src="/728791e9/downmysql.png" class="" title="MySQL 下载"><p>     本次安装我是采用通用方式,通过下载离线安装包进行配置安装,下载安装包之前之前首先要查看一下自己系统的glibc版本,然后下载对应的版本。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sunys@syshlang:~$ getconf GNU_LIBC_VERSION</span><br><span class="line">glibc 2.28</span><br></pre></td></tr></table></figure><img src="/728791e9/downmysql1.png" class="" title="MySQL 下载"><h1 id="二、安装配置"><a href="#二、安装配置" class="headerlink" title="二、安装配置"></a>二、安装配置</h1><h2 id="1、解压安装包并授权"><a href="#1、解压安装包并授权" class="headerlink" title="1、解压安装包并授权"></a>1、解压安装包并授权</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 解压安装包(方法一)</span></span></span><br><span class="line">sunys@syshlang:~/develop$ xz -d mysql-8.0.21-linux-glibc2.17-x86_64-minimal.tar.xz</span><br><span class="line">sunys@syshlang:~/develop$ tar -xvf mysql-8.0.21-linux-glibc2.17-x86_64-minimal.tar</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 或解压安装包(方法二)</span></span></span><br><span class="line">sunys@syshlang:~/develop$ tar -Jxf mysql-8.0.21-linux-glibc2.17-x86_64-minimal.tar.xz</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 将解压的文件复制或剪切到自己的软件安装目录下</span></span></span><br><span class="line">sunys@syshlang:~/develop$ sudo mv mysql-8.0.21-linux-glibc2.17-x86_64-minimal /usr/local/mysql</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 切换至root</span></span></span><br><span class="line">sunys@syshlang:/usr/local/mysql$ su</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 创建mysql的数据文件夹data</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# mkdir data</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 创建mysql_3306.err日志文件(可省略)</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# touch mysql_3306.err</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 设置mysql读写权限</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# chmod -R 777 ./</span><br></pre></td></tr></table></figure><h2 id="2、编辑my-cnf文件"><a href="#2、编辑my-cnf文件" class="headerlink" title="2、编辑my.cnf文件"></a>2、编辑my.cnf文件</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 编辑my.cnf</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# vim /etc/mysql/my.cnf</span><br></pre></td></tr></table></figure><figure class="highlight plain"><figcaption><span>/etc/mysql/my.cnf</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">[client]</span><br><span class="line">port = 3306</span><br><span class="line">socket = /tmp/mysql.sock</span><br><span class="line"></span><br><span class="line">[mysqld]</span><br><span class="line">init-connect='SET NAMES utf8'</span><br><span class="line"># 目录</span><br><span class="line">basedir=/usr/local/mysql</span><br><span class="line">datadir=/usr/local/mysql/data</span><br><span class="line">socket=/tmp/mysql.sock</span><br><span class="line"># 允许最大连接数</span><br><span class="line">max_connections=200</span><br><span class="line"># 服务端使用的字符集默认为8比特编码的latin1字符集</span><br><span class="line">#character-set-server=utf8</span><br><span class="line"># 创建新表时将使用的默认存储引擎</span><br><span class="line">default-storage-engine=INNODB</span><br><span class="line">log-error=/usr/local/mysql/mysql_3306.err</span><br></pre></td></tr></table></figure><blockquote><p> 详细的配置说明见<a href="#%E9%99%84%EF%BC%9A%E9%85%8D%E7%BD%AE%E6%B8%85%E5%8D%95">配置清单</a></p></blockquote><h2 id="3、创建用户和用户组并授权"><a href="#3、创建用户和用户组并授权" class="headerlink" title="3、创建用户和用户组并授权"></a>3、创建用户和用户组并授权</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 添加mysql用户组</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# groupadd mysql</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 添加mysql用户</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# useradd -r -g mysql mysql</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 授权</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# chown -R mysql:mysql ./</span><br></pre></td></tr></table></figure><h2 id="4、初始化数据库"><a href="#4、初始化数据库" class="headerlink" title="4、初始化数据库"></a>4、初始化数据库</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@syshlang:/usr/local/mysql# cd bin/</span><br><span class="line">root@syshlang:/usr/local/mysql# ./mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data</span><br></pre></td></tr></table></figure><p>不错喔!我初始化的时候没有报错,如果报错,可以去mysql_3306.err文件查看错误信息</p><img src="/728791e9/initmysql.png" class="" title="初始化数据库"><p>初始化完成,mysql会自动生成一个初始化密码,可以去日志文件查看,保存这个密码一会会用的到。</p><img src="/728791e9/mysqllog.png" class="" title="日志文件"><h2 id="5、将MySQL服务添加到系统服务"><a href="#5、将MySQL服务添加到系统服务" class="headerlink" title="5、将MySQL服务添加到系统服务"></a>5、将MySQL服务添加到系统服务</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 将mysql的启动服务文件复制到init.d目录</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# cp -r support-files/mysql.server /etc/init.d/mysqld</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 修改配置</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# vim /etc/init.d/mysqld</span><br></pre></td></tr></table></figure><img src="/728791e9/systemmysql.png" class="" title="配置系统服务文件"><h2 id="6、配置环境变量"><a href="#6、配置环境变量" class="headerlink" title="6、配置环境变量"></a>6、配置环境变量</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 编辑profile文件</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# vim /etc/profile</span><br></pre></td></tr></table></figure><blockquote><p>文件末尾追加配置<br>export PATH=$PATH:/usr/local/mysql/bin:/usr/local/mysql/sbin</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 刷新资源</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# source /etc/profile</span><br></pre></td></tr></table></figure><h2 id="7、修改默认密码"><a href="#7、修改默认密码" class="headerlink" title="7、修改默认密码"></a>7、修改默认密码</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 启动MySQL服务</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# /etc/init.d/mysqld start</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 使用临时密码登陆数据库</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# mysql -uroot -p</span><br></pre></td></tr></table></figure><img src="/728791e9/loginmysql.png" class="" title="使用临时密码登陆数据库"><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">## 修改数据库的密码</span><br><span class="line">mysql> ALTER user 'root'@'localhost' IDENTIFIED BY '123456';</span><br><span class="line">Query OK, 0 rows affected (0.13 sec)</span><br><span class="line">## 刷新权限表</span><br><span class="line">mysql> flush privileges;</span><br><span class="line">Query OK, 0 rows affected (0.03 sec)</span><br></pre></td></tr></table></figure><p>     到此,MySQL的安装就结束了,针对MySQL的更改host名,配置权限等与在windows下是一样的,可以参考<a href="/7d2a91d4/" title="《Windows上安装 MySQL》">《Windows上安装 MySQL》</a></p><h1 id="三、其他相关命令"><a href="#三、其他相关命令" class="headerlink" title="三、其他相关命令"></a>三、其他相关命令</h1><h2 id="启动-停止-重启-启动状态"><a href="#启动-停止-重启-启动状态" class="headerlink" title="启动/停止/重启/启动状态"></a>启动/停止/重启/启动状态</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 使用 service</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# service mysql [start|stop|restart|status]</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 使用 mysqld 脚本</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# /etc/init.d/mysqld [start|stop|restart|status]</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 使用 safe_mysqld启动</span></span></span><br><span class="line">root@syshlang:/usr/local/mysql# safe_mysql&</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># MySQL管理工具mysqladmin停止</span></span></span><br><span class="line">mysqladmin shutdown</span><br></pre></td></tr></table></figure><h1 id="附:配置清单"><a href="#附:配置清单" class="headerlink" title="附:配置清单"></a>附:配置清单</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line">user = mysql</span><br><span class="line">port = 3306</span><br><span class="line">socket = /data/3306/mysql.sock,#这里指定了一个特别的连接</span><br><span class="line">basedir = /usr/local/mysql</span><br><span class="line">datadir = /data/3306/data</span><br><span class="line">[client]</span><br><span class="line">port = 3306</span><br><span class="line">socket = /data/3306/mysql.sock,在客户端也要声明它,命令行要用到</span><br><span class="line">3. 查询缓存要不要开</span><br><span class="line">写入频繁的数据库,不要开查询缓存</span><br><span class="line">query_cache_size</span><br><span class="line">查询缓存区的最大长度(默认设置是0,不开辟查询缓存区)。首先要把Query_cache和该表相关的语句全部置为失效,然后在写入更新。那么如果Query_cache非常大,该表的查询结构又比较多,查询语句失效也慢,一个更新或是Insert就会很慢,这样看到的就是Update或是Insert怎么这么慢了。所以在数据库写入量或是更新量也比较大的系统,该参数不适合分配过大。而且在高并发,写入量大的系统,建议把该功能禁掉。</span><br><span class="line">query_cache_limit</span><br><span class="line">指定单个查询能够使用的缓冲区大小,缺省为1M</span><br><span class="line">query_cache_min_res_unit</span><br><span class="line">默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据查询,就容易造成内存碎片和浪费</span><br><span class="line">说明:禁掉查询缓存的方法就是直接注释掉查询缓存的配置,如#query_cache_size=1M, 这样就可以了</span><br><span class="line">4. 其他需要开的缓存</span><br><span class="line">读缓存,线程缓存,排序缓存</span><br><span class="line">sort_buffer_size = 2M</span><br><span class="line">connection级参数。太大将导致在连接数增高时,内存不足。</span><br><span class="line">max_allowed_packet = 32M</span><br><span class="line">网络传输中一次消息传输量的最大值。系统默认值 为1MB,最大值是1GB,必须设置1024的倍数。</span><br><span class="line">join_buffer_size = 2M</span><br><span class="line">和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享</span><br><span class="line">tmp_table_size = 256M</span><br><span class="line">默认大小是 32M。GROUP BY 多不多的问题</span><br><span class="line">max_heap_table_size = 256M</span><br><span class="line">key_buffer_size = 2048M</span><br><span class="line">索引的缓冲区大小,对于内存在4GB左右的服务器来说,该参数可设置为256MB或384MB。</span><br><span class="line">read_buffer_size = 1M</span><br><span class="line">read_rnd_buffer_size = 16M</span><br><span class="line">进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索</span><br><span class="line">bulk_insert_buffer_size = 64M</span><br><span class="line">批量插入数据缓存大小,可以有效提高插入效率,默认为8M</span><br><span class="line">Innodb缓存</span><br><span class="line">innodb_buffer_pool_size = 2048M</span><br><span class="line">只需要用Innodb的话则可以设置它高达 70-80% 的可用内存。一些应用于 key_buffer 的规则有 ——如果你的数据量不大,并且不会暴增,那么无需把innodb_buffer_pool_size 设置的太大了。</span><br><span class="line">innodb_additional_mem_pool_size = 16M</span><br><span class="line">网络传输中一次消息传输量的最大值。系统默认值为1MB,最大值是1GB,必须设置1024的倍数。</span><br><span class="line">innodb_log_files_in_group = 3</span><br><span class="line">循环方式将日志文件写到多个文件。推荐设置为3</span><br><span class="line">innodb_lock_wait_timeout = 120</span><br><span class="line">InnoDB 有其内置的死锁检测机制,能导致未完成的事务回滚。innodb_file_per_table = 0 独享表空间,关闭</span><br><span class="line">5. 连接数</span><br><span class="line">open_files_limit = 10240</span><br><span class="line">允许打开的文件数</span><br><span class="line">back_log = 600</span><br><span class="line">短时间内的多少个请求可以被存在堆栈中</span><br><span class="line">max_connections = 3000</span><br><span class="line">MySQL默认的最大连接数为100,MySQL服务器允许的最大连接数16384</span><br><span class="line">max_connect_errors = 6000</span><br><span class="line">设置每个主机的连接请求异常中断的最大次数,当超过该次数,MYSQL服务器将禁止host的连接请求</span><br><span class="line">thread_cache_size = 300</span><br><span class="line">重新利用保存在缓存中线程的数量</span><br><span class="line">thread_concurrency = 8</span><br><span class="line">thread_concurrency应设为总CPU核数的2倍</span><br><span class="line">thread_stack = 192K</span><br><span class="line">每个线程的堆栈大小,默认值足够大,可满足普通操作。可设置范围为128K至4GB,默认为192KB。</span><br><span class="line">6. 线程池有关参数</span><br><span class="line">线程池很少配</span><br><span class="line">thread_handling</span><br><span class="line">表示线程池模型。</span><br><span class="line">thread_pool_size</span><br><span class="line">表示线程池的group个数,一般设置为当前CPU核心数目。理想情况下,一个group一个活跃的工作线程,达到充分利用CPU的目的。</span><br><span class="line">thread_pool_stall_limit</span><br><span class="line">用于timer线程定期检查group是否“停滞”,参数表示检测的间隔。</span><br><span class="line">thread_pool_idle_timeout</span><br><span class="line">当一个worker空闲一段时间后会自动退出,保证线程池中的工作线程在满足请求的情况下,保持比较低的水平。60秒</span><br><span class="line">thread_pool_oversubscribe</span><br><span class="line">该参数用于控制CPU核心上“超频”的线程数。这个参数设置值不含listen线程计数。</span><br><span class="line">threadpool_high_prio_mode</span><br><span class="line">表示优先队列的模式。</span><br><span class="line">thread_pool_max_threads</span><br><span class="line">限制线程池最大的线程数,超过将无法再创建更多的线程,默认为100000。</span><br><span class="line">thread_pool_high_prio_tickets</span><br><span class="line">最多语序多少次被放入高优先级队列中,默认为4294967295。只有在thread_pool_high_prio_mode为transactions的时候才有效果</span><br><span class="line">说明:</span><br><span class="line">线程处理的最小单位是statement(语句)</span><br><span class="line">线程池实现在server端,通过创建一定数量的线程服务DB请求,相对于one-conection-per-thread的一个线程服务一个连接的方式,线程池服务的最小单位是语句,即一个线程可以对应多个活跃的连接。</span><br><span class="line">7. 慢查询日志</span><br><span class="line">slow_query_log</span><br><span class="line">是否开启慢查询日志,1表示开启,0表示关闭。</span><br><span class="line">log-slow-queries</span><br><span class="line">旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log</span><br><span class="line">slow-query-log-file</span><br><span class="line">新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log</span><br><span class="line">long_query_time</span><br><span class="line">慢查询阈值,当查询时间多于设定的阈值时,记录日志。</span><br><span class="line">log_queries_not_using_indexes</span><br><span class="line">未使用索引的查询也被记录到慢查询日志中(可选项)。</span><br><span class="line">log_output</span><br><span class="line">日志存储方式。log_output='FILE'表示将日志存入文件,默认值是'FILE'。log_output='TABLE'表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中。MySQL数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:log_output='FILE,TABLE'。日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件。</span><br><span class="line">log-error</span><br><span class="line">mysql生成的错误日志存放的路径,它是一个文本文件</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><img src="/77d59a46/MySQL.png" class="" title="Mysql"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="database" scheme="https://syshlang.com/categories/database/"/>
<category term="mysql" scheme="https://syshlang.com/categories/database/mysql/"/>
<category term="database" scheme="https://syshlang.com/tags/database/"/>
<category term="Mysql" scheme="https://syshlang.com/tags/Mysql/"/>
<category term="sql" scheme="https://syshlang.com/tags/sql/"/>
</entry>
<entry>
<title>Windows上安装 MySQL</title>
<link href="https://syshlang.com/7d2a91d4/"/>
<id>https://syshlang.com/7d2a91d4/</id>
<published>2019-08-09T03:20:25.000Z</published>
<updated>2020-09-24T01:20:06.450Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/77d59a46/MySQL.png" class="" title="Mysql"><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>      Window上安装MySQL主要有两种方式:第一种,MySQL安装包安装方式;第二种,绿色版压缩包安装方式。第一种方式相对简单,就是简单的点击下一步安装,不再赘述,本文主要讲解第二种方式的安装及安装过程中出现问题的解决方式。</p><h1 id="下载安装包"><a href="#下载安装包" class="headerlink" title="下载安装包"></a>下载安装包</h1><p>     进入<span class="exturl" data-url="aHR0cHM6Ly9kZXYubXlzcWwuY29tL2Rvd25sb2Fkcy9teXNxbC8=">MySQL 下载<i class="fa fa-external-link-alt"></i></span>,可以看到mysql的下载包列表。我选择的是5.7版本。</p><img src="/7d2a91d4/mysql-donwnload.png" class="" title="MySQL 下载"><h1 id="安装配置"><a href="#安装配置" class="headerlink" title="安装配置"></a>安装配置</h1><ol><li>将下载好的压缩包文件解压到指定目录,比如D:\mysql-5.7.20-winx64;</li><li>配置下 MySQL 的配置文件,打开刚刚解压的文件夹 D:\mysql-5.7.20-winx64 ,修改my-default.ini为my.ini,如果不存在直接创建 my.ini 配置文件,编辑 my.ini 配置以下基本信息:<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># For advice on how to change settings please see</span></span><br><span class="line"><span class="comment"># http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html</span></span><br><span class="line"><span class="comment"># *** DO NOT EDIT THIS FILE. It's a template which will be copied to the</span></span><br><span class="line"><span class="comment"># *** default location during install, and will be replaced if you</span></span><br><span class="line"><span class="comment"># *** upgrade to a newer version of MySQL.</span></span><br><span class="line"><span class="section">[client]</span></span><br><span class="line"><span class="attr">port</span>=<span class="number">3306</span></span><br><span class="line"><span class="attr">default-character-set</span>=utf8</span><br><span class="line"><span class="section">[mysqld]</span></span><br><span class="line"><span class="comment"># 设置为自己MYSQL的安装目录</span></span><br><span class="line"><span class="attr">basedir</span>=D:\mysql-<span class="number">5.7</span>.<span class="number">20</span>-winx64</span><br><span class="line"><span class="comment"># 设置为MYSQL的数据目录</span></span><br><span class="line"><span class="attr">datadir</span>=D:\mysql-<span class="number">5.7</span>.<span class="number">20</span>-winx64\data</span><br><span class="line"><span class="attr">port</span>=<span class="number">3306</span></span><br><span class="line"><span class="attr">character_set_server</span>=utf8</span><br><span class="line"><span class="attr">sql_mode</span>=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES</span><br><span class="line"><span class="comment">#开启查询缓存</span></span><br><span class="line"><span class="attr">explicit_defaults_for_timestamp</span>=<span class="literal">true</span></span><br><span class="line"><span class="comment">#默认的存储引擎</span></span><br><span class="line"><span class="attr">default-storage-engine</span>=INNODB</span><br></pre></td></tr></table></figure>上面这个是5.7版本的配置,MySQL 8+配置如下:<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[client]</span></span><br><span class="line"><span class="comment"># 设置mysql客户端默认字符集</span></span><br><span class="line"><span class="attr">default-character-set</span>=utf8</span><br><span class="line"></span><br><span class="line"><span class="section">[mysqld]</span></span><br><span class="line"><span class="comment"># 设置3306端口</span></span><br><span class="line"><span class="attr">port</span> = <span class="number">3306</span></span><br><span class="line"><span class="comment"># 设置mysql的安装目录</span></span><br><span class="line"><span class="attr">basedir</span>=C:\\web\\mysql-<span class="number">8.0</span>.<span class="number">11</span></span><br><span class="line"><span class="comment"># 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错</span></span><br><span class="line"><span class="comment"># datadir=C:\\web\\sqldata</span></span><br><span class="line"><span class="comment"># 允许最大连接数</span></span><br><span class="line"><span class="attr">max_connections</span>=<span class="number">20</span></span><br><span class="line"><span class="comment"># 服务端使用的字符集默认为8比特编码的latin1字符集</span></span><br><span class="line"><span class="attr">character-set-server</span>=utf8</span><br><span class="line"><span class="comment"># 创建新表时将使用的默认存储引擎</span></span><br><span class="line"><span class="attr">default-storage-engine</span>=INNODB</span><br></pre></td></tr></table></figure></li><li>启动 MySQL 数据库<br>以管理员身份打开 cmd 命令行工具,切换目录:<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">C:\<span class="title">Users</span>\<span class="title">sunys</span>><span class="title">cd</span> <span class="title">D</span>:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span></span></span><br></pre></td></tr></table></figure></li><li>初始化数据库:<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">D:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span>><span class="title">mysqld</span> --<span class="title">initialize</span> --<span class="title">user</span>=<span class="title">mysql</span>--<span class="title">console</span></span></span><br></pre></td></tr></table></figure>此时会给管理账户root随机生成一个临时密码。<div class="note info"><ul><li>-initialize生成随机密码</li><li>-initialize-insecure生成空密码</li><li>默认帐号root,后面的-user=mysql不更改</li></ul></div></li><li>安装Mysql服务<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">D:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span>><span class="title">mysqld</span> --<span class="title">install</span> <span class="title">MySQL</span></span></span><br></pre></td></tr></table></figure></li><li>启动服务<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">D:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span>><span class="title">net</span> <span class="title">start</span> <span class="title">MySQL</span></span></span><br></pre></td></tr></table></figure></li><li>登录数据库<br>当 MySQL 服务已经运行时, 我们可以通过 MySQL 自带的客户端工具登录到 MySQL 数据库中, 首先打开命令提示符, 输入以下格式的命名:<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -h 主机名 -u 用户名 -p</span><br></pre></td></tr></table></figure><div class="note info"><ul><li>-h : 指定客户端所要登录的 MySQL 主机名, 登录本机(localhost 或 127.0.0.1)该参数可以省略;</li><li>-u : 登录的用户名;</li><li>-p : 告诉服务器将会使用一个密码来登录, 如果所要登录的用户名密码为空, 可以忽略此选项。</li></ul></div>我是登录本机的 MySQL 数据库,只需要输入以下命令即可:<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">D:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span>><span class="title">mysql</span> -<span class="title">u</span> <span class="title">root</span> -<span class="title">p</span></span></span><br></pre></td></tr></table></figure>按回车确认,输入之前生成的临时密码(如果生成空密码,这里不用输入密码直接回车即可)。</li><li>成功登录后需要首先修改root账户的随机密码<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>alter user 'root'@'localhost' identified by '密码';</span><br></pre></td></tr></table></figure>密码修改成功后即可使用自己设定的密码登录</li></ol><h1 id="卸载"><a href="#卸载" class="headerlink" title="卸载"></a>卸载</h1><blockquote><p>卸载安装版方式安装的MySQL跟卸载普通的软件方式一样,直接在控制面板的程序和功能中卸载即可;绿色版安装的MySQL卸载方式如下:</p></blockquote><ol><li>在CMD命令行模式下,删除mysql服务<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">C:\<span class="title">Users</span>\<span class="title">sunys</span>><span class="title">sc</span> <span class="title">delete</span> <span class="title">mysql</span></span></span><br></pre></td></tr></table></figure></li><li>regedit进入注册表,删除mysql相关的文件</li></ol><h1 id="问题及解决方案"><a href="#问题及解决方案" class="headerlink" title="问题及解决方案"></a>问题及解决方案</h1><h2 id="缺少dll"><a href="#缺少dll" class="headerlink" title="缺少dll"></a>缺少dll</h2><blockquote><p>安装版,遇到MSVCR120.dll文件丢失错误,如下图:</p></blockquote><img src="/7d2a91d4/mysql9-dll.png" class="" title="MySQL 缺少dll"><blockquote><p>解决方案:下载 <span class="exturl" data-url="aHR0cHM6Ly93d3cubWljcm9zb2Z0LmNvbS9lbi11cy9kb3dubG9hZC9kZXRhaWxzLmFzcHg/aWQ9NDA3ODQ=">VC redist packages for x64<i class="fa fa-external-link-alt"></i></span>,安装即可。</p></blockquote><h2 id="mysql无法启动"><a href="#mysql无法启动" class="headerlink" title="mysql无法启动"></a>mysql无法启动</h2><blockquote><p>重新安装MySQL数据库之后无法启动,报错如下:</p></blockquote><img src="/7d2a91d4/mysql9-start1.png" class="" title="MySQL mysql无法启动"><img src="/7d2a91d4/mysql9-start2.png" class="" title="MySQL mysql无法启动"><blockquote><p>解决方案:</p></blockquote><ol><li>删除原来的mysql服务,进入mysql安装目录下的bin目录运行;<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">D:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span>><span class="title">mysqld</span> --<span class="title">remove</span> <span class="title">MySQL</span></span></span><br></pre></td></tr></table></figure></li><li>在mysql的根目录下, 清空data目录;</li><li>删除注册表,重启电脑(貌似执行这一步之后才会有效,否则还是不行);</li><li>重新执行安装命令并启动服务,启动成功。</li></ol><h2 id="Mysql连接报错:1130"><a href="#Mysql连接报错:1130" class="headerlink" title="Mysql连接报错:1130"></a>Mysql连接报错:1130</h2><blockquote><p>数据库安装完成之后,使用localhost作为地址链接没问题,但是改为真实IP之后,Mysql连接报错:1130-host … is not allowed to connect to this MySql server。</p></blockquote><blockquote><p>这个问题是因为在数据库服务器中的mysql数据库中的user的表中没有权限,解决方案:</p></blockquote><ol><li><p>连接服务器:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">D:\<span class="title">mysql</span>-5.7.20-<span class="title">winx64</span>\<span class="title">bin</span>><span class="title">mysql</span> -<span class="title">u</span> <span class="title">root</span> -<span class="title">p</span></span></span><br></pre></td></tr></table></figure></li><li><p>看当前所有数据库:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>show databases;</span><br></pre></td></tr></table></figure><img src="/7d2a91d4/mysql9-connect1.png" class="" title="当前所有数据库"></li><li><p>进入mysql数据库:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>use mysql;</span><br></pre></td></tr></table></figure></li><li><p>查看mysql数据库中所有的表:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>show tables;</span><br></pre></td></tr></table></figure><img src="/7d2a91d4/mysql9-connect2.png" class="" title="当前数据库所有的表"></li><li><p>查看user表中的数据:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>select host, user from user;</span><br></pre></td></tr></table></figure><img src="/7d2a91d4/mysql9-connect3.png" class="" title="user表中的数据"></li><li><p>修改user表中的Host:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>update user set host='%' where user='ebm';</span><br></pre></td></tr></table></figure></li><li><p>最后刷新一下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>flush privileges;</span><br></pre></td></tr></table></figure></li><li><p>再查看user表中的数据:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql>select host, user from user;</span><br></pre></td></tr></table></figure><img src="/7d2a91d4/mysql9-connect4.png" class="" title="user表中的数据"><blockquote><p>可以看到,此时ebm的host已经发生了变化,再使用真实IP链接mysql,链接成功。</p></blockquote><div class="note info"><p>host列的值:</p><ul><li>localhost 代表只可以本机连接</li><li>% 代表任何客户机都可以连接</li><li>空 值等价于’%’</li><li>固定IP 指定的IP可以连接</li><li>通配符字符(“%”和“_”) 例如:192.168.1.% 就表示ip为192.168.1.前缀的客户端都可以连接</li></ul></div></li></ol>]]></content>
<summary type="html"><img src="/77d59a46/MySQL.png" class="" title="Mysql"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="database" scheme="https://syshlang.com/categories/database/"/>
<category term="mysql" scheme="https://syshlang.com/categories/database/mysql/"/>
<category term="database" scheme="https://syshlang.com/tags/database/"/>
<category term="Mysql" scheme="https://syshlang.com/tags/Mysql/"/>
<category term="sql" scheme="https://syshlang.com/tags/sql/"/>
</entry>
<entry>
<title>设计模式七大原则之单一职责原则 (Single Responsibility Principle)</title>
<link href="https://syshlang.com/934a08a4/"/>
<id>https://syshlang.com/934a08a4/</id>
<published>2019-05-21T12:14:58.000Z</published>
<updated>2020-09-17T00:34:15.256Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><p>    单一职责原则(SRP:Single responsibility principle)又称单一功能原则,对于一个类而言,不应存在多于一个导致类变更的原因,否则类应该被拆分,也就是说一个类只负责一项职责。如果一个类承担的职责项过多,就等于把这些职责耦合起来,使其难维护,复用度低,缺乏灵活性,当需求发生变化时,一项功能职责的变动可能导致整个功能无法使用,因此在实际中开发中,我们应将类的功能职责粒度分解,其核心就是控制类的粒度大小、将对象解耦、提高其内聚性。</p><a id="more"></a><blockquote><p>交通工具的例子</p></blockquote><ul><li>方式一</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingleResponsibility1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Vehicle vehicle = <span class="keyword">new</span> Vehicle();</span><br><span class="line"> vehicle.run(<span class="string">"摩托车"</span>);</span><br><span class="line"> vehicle.run(<span class="string">"汽车"</span>);</span><br><span class="line"> vehicle.run(<span class="string">"飞机"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Vehicle</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">" 在公路上运行...."</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>飞机本应天空中飞行,显然方式一中Vehicle的run方法中,违反了单一职责原则,根据单一职责原则改进如下:</p></blockquote><ul><li>方式二</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingleResponsibility2</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> RoadVehicle roadVehicle = <span class="keyword">new</span> RoadVehicle();</span><br><span class="line"> roadVehicle.run(<span class="string">"摩托车"</span>);</span><br><span class="line"> roadVehicle.run(<span class="string">"汽车"</span>);</span><br><span class="line"></span><br><span class="line"> AirVehicle airVehicle = <span class="keyword">new</span> AirVehicle();</span><br><span class="line"> airVehicle.run(<span class="string">"飞机"</span>);</span><br><span class="line"></span><br><span class="line"> WaterVehicle waterVehicle = <span class="keyword">new</span> WaterVehicle();</span><br><span class="line"> waterVehicle.run(<span class="string">"轮船"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">RoadVehicle</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">"公路运行"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">AirVehicle</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">"天空运行"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">WaterVehicle</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">"水中运行"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>改进之后,每个交通工具类都有自己的单一职责,互不影响,遵守单一职责原则,但是这种改动花销很大,除了要根据职责将类分解为多个类,同时还要修改客户端。因此,改进如下:</p></blockquote><ul><li>方式三</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> sunys</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingleResponsibility3</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> VehicleCommon vehicleCommon = <span class="keyword">new</span> VehicleCommon();</span><br><span class="line"> vehicleCommon.runRoad(<span class="string">"汽车"</span>);</span><br><span class="line"> vehicleCommon.runAir(<span class="string">"飞机"</span>);</span><br><span class="line"> vehicleCommon.runWater(<span class="string">"轮船"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">VehicleCommon</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">runRoad</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">" 在公路上运行...."</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">runAir</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">" 在天空上运行...."</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">runWater</span><span class="params">(String vehicle)</span> </span>{</span><br><span class="line"> System.out.println(vehicle + <span class="string">" 在水中行...."</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>可以看到,这种方式没有对类进行拆分,只是增加方法,改动不大,但最终也满足实际的需求,这种改动虽然没有在类这个级别上遵守单一职责原则,但是在方法级别上,仍然是遵守单一职责原则。在实际开发中,我们可以根据实际情况决定在类级别上遵守单一职责原则,还是在方法级别上遵守单一职责原则;</p></blockquote><p><font color=black size=5 face="华文行楷">附:本次演示的项目地址</font><br><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N5c2hsYW5nL2phdmEtZGVzaWduLXByaW5jaXBsZQ==">https://github.com/syshlang/java-design-principle<i class="fa fa-external-link-alt"></i></span><iframe src="https://ghbtns.com/github-btn.html?user=syshlang&repo=java-design-principle&type=star&count=true&size=large" width="160px" height="30px" frameborder="0" loading="lazy" allowfullscreen></iframe></p>]]></content>
<summary type="html"><p>&ensp;&ensp;&ensp;&ensp;单一职责原则(SRP:Single responsibility principle)又称单一功能原则,对于一个类而言,不应存在多于一个导致类变更的原因,否则类应该被拆分,也就是说一个类只负责一项职责。如果一个类承担的职责项过多,就等于把这些职责耦合起来,使其难维护,复用度低,缺乏灵活性,当需求发生变化时,一项功能职责的变动可能导致整个功能无法使用,因此在实际中开发中,我们应将类的功能职责粒度分解,其核心就是控制类的粒度大小、将对象解耦、提高其内聚性。</p></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计原则" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="principle" scheme="https://syshlang.com/tags/principle/"/>
</entry>
<entry>
<title>JAVA开发中的设计模式</title>
<link href="https://syshlang.com/25810b4c/"/>
<id>https://syshlang.com/25810b4c/</id>
<published>2019-05-17T12:28:57.000Z</published>
<updated>2020-09-25T07:52:39.890Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/25810b4c/java-design-patterns0.jpg" class="" title="设计模式"><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>    在《<a href="/4fb5687d/" title="java抽象类和模板方法设计">java抽象类和模板方法设计</a>》中,讲到了利用接口和抽象类进行模板方法设计。在我们实际开发的过程中,最多的操作可能就是curd堆业务代码,只有负责架构的才会去考虑设计模式相关的东西,然而呢,其实我们接触到与java设计模式相关的还是很多,例如,jDK源码,几乎每个web项目都会使用的企业级应用分层框架spring框架等。<br>    在软件开发过程中,对于软件架构的设计,我们需要从耦合性、内聚性以及可维护性、可扩展性、重用性、灵活性等多方面进行考虑,设计模式的出现在这些方面为我们提供了思路和解决方案。</p><h1 id="设计模式的七大原则"><a href="#设计模式的七大原则" class="headerlink" title="设计模式的七大原则"></a>设计模式的七大原则</h1><blockquote><p>    设计模式的原则,指的就是我们在软件编程的过程中,应该遵循的原则,它是设计模式的基础和依据,主要有七大原则:</p></blockquote><ul><li><a href="/934a08a4/" title="单一职责原则 (Single Responsibility Principle)">单一职责原则 (Single Responsibility Principle)</a></li><li><a href="/8d12383c/" title="接口隔离原则 (Interface Segregation Principle)">接口隔离原则 (Interface Segregation Principle)</a></li><li><a href="/fa1508aa/" title="依赖倒转原则 (Dependence Inversion Principle)">依赖倒转原则 (Dependence Inversion Principle)</a></li><li><a href="/64719d09/" title="里氏代换原则 (Liskov Substitution Principle)">里氏代换原则 (Liskov Substitution Principle)</a></li><li><a href="/1376ad9f/" title="开闭原则 (Open Close Principle)">开闭原则 (Open Close Principle)</a></li><li><a href="/8a7ffc25/" title="迪米特法则(Demeter Principle)">迪米特法则(Demeter Principle)</a></li><li><a href="/fd78ccb3/" title="合成复用原则(Composite Reuse Principle)">合成复用原则(Composite Reuse Principle)</a></li></ul><h1 id="设计模式的分类"><a href="#设计模式的分类" class="headerlink" title="设计模式的分类"></a>设计模式的分类</h1><p>总体来说设按照功能可将计模式分为三大类:</p><table><thead><tr><th align="center">分类</th><th align="center">功能</th><th align="center">设计模式</th></tr></thead><tbody><tr><td align="center">创建型模式</td><td align="center">主要用于创建对象</td><td align="center"><a href="/659a32bd/" title="工厂方法模式">工厂方法模式</a>、<a href="/659a32bd/" title="抽象工厂模式">抽象工厂模式</a>、<a href="/fc936307/" title="单例模式">单例模式</a>、<a href="/129d022b/" title="原型模式">原型模式</a>、<a href="/8cf99788/" title="建造者模式">建造者模式</a></td></tr><tr><td align="center">结构型模式</td><td align="center">主要用于处理类或者对象的组合</td><td align="center"><a href="/fbfea71e/" title="适配器模式">适配器模式</a>、<a href="/62f7f6a4/" title="桥接模式">桥接模式</a>、装饰器模式、代理模式、外观模式、组合模式、享元模式</td></tr><tr><td align="center">行为型模式</td><td align="center">主要用于描述对类或对象怎样交互和怎样分配职责</td><td align="center">策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式</td></tr></tbody></table><p>其实还有两类:并发型模式和线程池模式。</p><h2 id="创建型模式(Creational-patterns)"><a href="#创建型模式(Creational-patterns)" class="headerlink" title="创建型模式(Creational patterns)"></a>创建型模式(Creational patterns)</h2><img src="/25810b4c/java-design-patterns4.jpg" class="" title="创建型模式"><blockquote><p>    创建型模式,顾名思义就是用来创建对象的设计模式,所以这种类型的模式主要用途是就用于创建对象,关注点是对象的创建。这种类型的设计模式主要特点是将创建对象的过程进行了抽象,封装,对于对象的使用者而言只需调用,而不需要去关心对象创建的过程如何。</p></blockquote><h2 id="结构型模式(Structural-patterns)"><a href="#结构型模式(Structural-patterns)" class="headerlink" title="结构型模式(Structural patterns)"></a>结构型模式(Structural patterns)</h2><img src="/25810b4c/java-design-patterns5.jpg" class="" title="结构型模式"><blockquote><p>    结构型设计模式,为我们如何组合类和对象以获得更大的结构提供思路,从程序的结构上解决模块之间的耦合问题。<br>    从组合结构上来看,又可以分为两类:类结构型模式、对象结构型模式。类结构型模式主要关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系;对象结构型模式则主要关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法,更符合“合成复用原则”。</p></blockquote><h2 id="行为型模式(Behavioral-patterns)"><a href="#行为型模式(Behavioral-patterns)" class="headerlink" title="行为型模式(Behavioral patterns)"></a>行为型模式(Behavioral patterns)</h2><img src="/25810b4c/java-design-patterns6.jpg" class="" title="行为型模式"><blockquote><p>    行为型模式,是设计模式中最为庞大的一类,前面两类模式已经解决了对象的创建问题及类和对象的组合结构问题,那么这第三大类型的模式自然就是用来解决类或对象相互协作的问题。这类设计模式主要用于描述程序在运行时复杂的流程控制,例如分配算法与对象间职责,协调类或对象之间相互协作等。<br>    当然,行为型模式也可分为两类:类行为模式、对象行为模式。类行为模式采用继承机制来在类间分派行为,对象行为模式则采用组合或聚合在对象间分配行为;由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。</p></blockquote><h1 id="设计模式之间的关系"><a href="#设计模式之间的关系" class="headerlink" title="设计模式之间的关系"></a>设计模式之间的关系</h1><blockquote><p>给两张图</p></blockquote><img src="/25810b4c/java-design-patterns1.png" class="" title="设计模式思维导图"><img src="/25810b4c/java-design-patterns2.jpg" class="" title="设计模式之间的关系"><h1 id="设计模式在软件中的应用"><a href="#设计模式在软件中的应用" class="headerlink" title="设计模式在软件中的应用"></a>设计模式在软件中的应用</h1><pre class="mermaid">graph LRA(面向对象) -->|设计模式+算法+数据结构| B[功能模块]B -->|多种设计模式| C[框架]C -->|服务器集群| D[架构]</pre><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><img src="/25810b4c/java-design-patterns3.jpg" class="" title="设计模式分类和原则"><blockquote><p>    设计模式实际是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的问题解决方案,当我们在软件开发过程中面临一般问题时,不妨从这方面入手看是否能找到解决方法。</p></blockquote><div class="note info"><p>    设计模式包含了面向对象的精髓,“懂了设计模式,你就懂了面向对象分析和设计(OOA/D)的精要”。</p></div>]]></content>
<summary type="html"><img src="/25810b4c/java-design-patterns0.jpg" class="" title="设计模式"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="JAVA" scheme="https://syshlang.com/tags/JAVA/"/>
<category term="design" scheme="https://syshlang.com/tags/design/"/>
<category term="patterns" scheme="https://syshlang.com/tags/patterns/"/>
</entry>
<entry>
<title>java抽象类和模板方法设计</title>
<link href="https://syshlang.com/4fb5687d/"/>
<id>https://syshlang.com/4fb5687d/</id>
<published>2019-04-20T07:25:41.000Z</published>
<updated>2020-09-17T00:34:15.264Z</updated>
<content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="/assets/js/Meting.min.js"></script><img src="/4fb5687d/abstract.png" class="" title="模板方法设计"><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><blockquote><p>    最近,在做项目时,遇到一个业务场景是这样的:有一种类型的电子锁,开锁的方式有两种,这两种方式开锁的过程有不同的地方也有相同的地方,主要的开锁流程差不多一致,设计这两种方式开锁流程的时候,我想到了利用java抽象类来进行模板方法设计。</p></blockquote><h1 id="Java抽象类与接口的区别"><a href="#Java抽象类与接口的区别" class="headerlink" title="Java抽象类与接口的区别"></a>Java抽象类与接口的区别</h1><blockquote><p>    面试的过程中,很多面试官考察java基础知识的时候,通常都会问诸如“Java抽象类与接口有什么区别?请你说说两者各自的使用场景?”这样的问题,那么两者有什么区别呢,大概总结如下:</p></blockquote><table><thead><tr><th align="center">参数</th><th align="center">抽象类</th><th align="center">接口</th></tr></thead><tbody><tr><td align="center">默认的方法实现</td><td align="center">它可以有默认的方法实现</td><td align="center">接口完全是抽象的。它根本不存在方法的实现</td></tr><tr><td align="center">实现</td><td align="center">子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。</td><td align="center">子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现</td></tr><tr><td align="center">构造器</td><td align="center">抽象类可以有构造器</td><td align="center">接口不能有构造器</td></tr><tr><td align="center">与正常Java类的区别</td><td align="center">除了你不能实例化抽象类之外,它和普通Java类没有任何区别</td><td align="center">接口是完全不同的类型</td></tr><tr><td align="center">成员变量</td><td align="center">抽象类中的静态成员变量的访问类型可以任意</td><td align="center">接口中定义的变量只能是public static final类型,并且默认即为public static final类型。</td></tr><tr><td align="center">成员方法</td><td align="center">抽象方法可以有public、protected和default这些修饰符,可以包含静态方法</td><td align="center">接口方法默认修饰符是public,并且默认即为public abstract类型,不能包含静态方法</td></tr><tr><td align="center">多继承</td><td align="center">抽象方法可以继承一个类和实现多个接口</td><td align="center">接口只可以继承一个或多个其它接口</td></tr><tr><td align="center">速度</td><td align="center">它比接口速度要快</td><td align="center">接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。</td></tr><tr><td align="center">添加新方法</td><td align="center">如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。</td><td align="center">如果你往接口中添加方法,那么你必须改变实现该接口的类。</td></tr></tbody></table><h1 id="Java抽象类与接口的使用场景"><a href="#Java抽象类与接口的使用场景" class="headerlink" title="Java抽象类与接口的使用场景"></a>Java抽象类与接口的使用场景</h1><h2 id="interface的应用场合"><a href="#interface的应用场合" class="headerlink" title="interface的应用场合"></a>interface的应用场合</h2><blockquote><ul><li>类与类之前需要特定的接口进行协调,而不在乎其如何实现;</li></ul></blockquote><ul><li>作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识;</li><li>需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联;</li><li>需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。</li></ul><figure class="highlight java"><figcaption><span>USB.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">USB</span></span>{ <span class="comment">// 定义了USB接口</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">start</span><span class="params">()</span> </span>; <span class="comment">// USB设备开始工作</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span> </span>; <span class="comment">// USB设备结束工作</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><figcaption><span>Flash.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Flash</span> <span class="keyword">implements</span> <span class="title">USB</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">start</span><span class="params">()</span></span>{ <span class="comment">// 覆写方法</span></span><br><span class="line"> System.out.println(<span class="string">"U盘开始工作。"</span>) ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span></span>{ <span class="comment">// 覆写方法</span></span><br><span class="line"> System.out.println(<span class="string">"U盘停止工作。"</span>) ;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><figcaption><span>Print.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Print</span> <span class="keyword">implements</span> <span class="title">USB</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">start</span><span class="params">()</span></span>{ <span class="comment">// 覆写方法</span></span><br><span class="line"> System.out.println(<span class="string">"打印机开始工作。"</span>) ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span></span>{ <span class="comment">// 覆写方法</span></span><br><span class="line"> System.out.println(<span class="string">"打印机停止工作。"</span>) ;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="abstract-class的应用场合"><a href="#abstract-class的应用场合" class="headerlink" title="abstract class的应用场合"></a>abstract class的应用场合</h2><blockquote><ul><li>在既需要统一的接口,又需要实例变量或缺省的方法的情况下,就可以使用它,例如:规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能。</li></ul></blockquote><figure class="highlight java"><figcaption><span>Person.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String name ; <span class="comment">// 定义name属性</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age ; <span class="comment">// 定义age属性</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(String name,<span class="keyword">int</span> age)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name ;</span><br><span class="line"> <span class="keyword">this</span>.age = age ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.name ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.age ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">say</span><span class="params">()</span></span>{ <span class="comment">// 人说话是一个具体的功能</span></span><br><span class="line"> System.out.println(<span class="keyword">this</span>.getContent()) ; <span class="comment">// 输出内容</span></span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> String <span class="title">getContent</span><span class="params">()</span> </span>; <span class="comment">// 说话的内容由子类决定</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><figcaption><span>Student.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">float</span> score ;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Student</span><span class="params">(String name,<span class="keyword">int</span> age,<span class="keyword">float</span> score)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(name,age) ; <span class="comment">// 调用父类中的构造方法</span></span><br><span class="line"> <span class="keyword">this</span>.score = score ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getContent</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"学生信息 --> 姓名:"</span> + <span class="keyword">super</span>.getName() +</span><br><span class="line"> <span class="string">";年龄:"</span> + <span class="keyword">super</span>.getAge() +</span><br><span class="line"> <span class="string">";成绩:"</span> + <span class="keyword">this</span>.score ;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><figcaption><span>Worker.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Worker</span> <span class="keyword">extends</span> <span class="title">Person</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">float</span> salary ;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Worker</span><span class="params">(String name,<span class="keyword">int</span> age,<span class="keyword">float</span> salary)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(name,age) ; <span class="comment">// 调用父类中的构造方法</span></span><br><span class="line"> <span class="keyword">this</span>.salary = salary ;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getContent</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"工人信息 --> 姓名:"</span> + <span class="keyword">super</span>.getName() +</span><br><span class="line"> <span class="string">";年龄:"</span> + <span class="keyword">super</span>.getAge() +</span><br><span class="line"> <span class="string">";工资:"</span> + <span class="keyword">this</span>.salary ;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><div class="note primary"><p>    在实际开发过程中,接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用。模板方法设计模式就是抽象类的一个典型应用,工厂模式、代理设计模式都是通过implements实现接口的设计模式,范型则是装饰设计模式。<br>    关于java开发中的23种设计模式,在下文《<a href="/25810b4c/" title="JAVA开发中的设计模式">JAVA开发中的设计模式</a>》继续。。。</p></div>]]></content>
<summary type="html"><img src="/4fb5687d/abstract.png" class="" title="模板方法设计"></summary>
<category term="technology" scheme="https://syshlang.com/categories/technology/"/>
<category term="java" scheme="https://syshlang.com/categories/java/"/>
<category term="设计模式" scheme="https://syshlang.com/categories/java/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="java" scheme="https://syshlang.com/tags/java/"/>
<category term="abstract" scheme="https://syshlang.com/tags/abstract/"/>
</entry>
</feed>