=單例模式=

單例模式需要考慮的重要問題是其生存周期問題,一種是不死鳥,永遠(yuǎn)不銷毀,最為簡(jiǎn)單,但是占用了資源
另一種是有生存周期, 但是又要考慮其引用可能無效的問題
* Lifetime: Dead reference
* Double check locking
=工廠模式=
工廠模式是很常用的模式, 常見的有
*簡(jiǎn)單工廠
*抽象工廠
*工廠方法
=生成器模式=
=原型模式=
這里只是簡(jiǎn)單地用相應(yīng)類圖來表示, 個(gè)中滋味, 在應(yīng)用中自己慢慢體會(huì)吧
相似的一點(diǎn)是抽象的東西有具體的實(shí)現(xiàn), 至于到底用哪個(gè)具體的實(shí)現(xiàn), 交給工廠來創(chuàng)建吧
至于這個(gè)工廠, 視問題域的復(fù)雜性,可以是抽象的, 也可以是具體的,工廠模式大體如此
General Responsibility Assignment
Software Patterns 通用職責(zé)分配軟件模式
模式名稱
|
描述(問題/解決方案)
|
信息專家模式Information Expert
|
問題:對(duì)象設(shè)計(jì)和職責(zé)分配的一般原則是什么?
解決方案:將職責(zé)分配給擁有履行一個(gè)職責(zé)所必需信息的類--即信息專家。(也就是將職責(zé)分配給一個(gè)類,這個(gè)類必須擁有履行這個(gè)職責(zé)所需要的信息。)
|
創(chuàng)建者模式Creator
|
問題:誰應(yīng)該負(fù)責(zé)產(chǎn)生類的實(shí)例(對(duì)應(yīng)于GoF設(shè)計(jì)模式系列里的“工廠模式”)
解決方案:如果符合下面的一個(gè)或多個(gè)條件,則將創(chuàng)建類A實(shí)例的職責(zé)分配給類B.
.類B聚合類A的對(duì)象。
.類B包含類A的對(duì)象。
.類B記錄類A對(duì)象的實(shí)例。
.類B密切使用類A的對(duì)象。
.類B初始化數(shù)據(jù)并在創(chuàng)建類A的實(shí)例時(shí)傳遞給類A(類B是創(chuàng)建類A實(shí)例的一個(gè)專家)。
在以上情況下,類B是類A對(duì)象的創(chuàng)建者。
|
控制器模式
Controller
|
問題:誰處理一個(gè)系統(tǒng)事件?
解決方案:當(dāng)類代表下列一種情況時(shí),為它分配處理系統(tǒng)事件消息的職責(zé)。
.代表整個(gè)系統(tǒng)、設(shè)備或子系統(tǒng)(外觀控制器)。
.代表系統(tǒng)事件發(fā)生的用例場(chǎng)景(用例或回話控制器)。
|
低耦合Low Coupling
|
問題:如何支持低依賴性以及增加重用性?
解決方案:分配職責(zé)時(shí)使(不必要的)耦合保持為最低。
|
高內(nèi)聚High Cohesion
|
問題:如何讓復(fù)雜性可管理?
解決方案:分配職責(zé)時(shí)使內(nèi)聚保持為最高。
|
多態(tài)模式Polymorphism
|
問題:當(dāng)行為隨類型變化而變化時(shí)誰來負(fù)責(zé)處理這些變化?
解決方案:當(dāng)類型變化導(dǎo)致另一個(gè)行為或?qū)е滦袨樽兓瘯r(shí),應(yīng)用多態(tài)操作將行為的職責(zé)分配到引起行為變化的類型。
|
純虛構(gòu)模式Pure Fabrication
|
問題:當(dāng)不想破壞高內(nèi)聚和低耦合的設(shè)計(jì)原則時(shí),誰來負(fù)責(zé)處理這些變化?
解決方案:將一組高內(nèi)聚的職責(zé)分配給一個(gè)虛構(gòu)的或處理方便的“行為”類,它并不是問題域中的概念,而是虛構(gòu)的事務(wù),以達(dá)到支持高內(nèi)聚、低耦合和重用的目的。
|
中介模式Indirection
|
問題:如何分配職責(zé)以避免直接耦合?
解決方案:分配職責(zé)給中間對(duì)象以協(xié)調(diào)組件或服務(wù)之間的操作,使得它們不直接耦合。
|
受保護(hù)變化模式Protected Variations
|
問題:如何分配職責(zé)給對(duì)象、子系統(tǒng)和系統(tǒng),使得這些元素中的變化或不穩(wěn)定的點(diǎn)不會(huì)對(duì)其他元素產(chǎn)生不利影響?
解決方案:找出預(yù)計(jì)有變化或不穩(wěn)定的元素,為其創(chuàng)建穩(wěn)定的“接口”而分配職責(zé)。
|
這些更象是一些OOD的原則, 模式會(huì)有很多, 但是萬變不離其宗, 大都遵循著一些基本的原則
-
OCP(Open-Closed Principle)
- DIP(Dependency Inversion
Principle)
-
LSP(Liskov Substitution
Principle)
- ISP(Interface Insolation
Principle)
- SRP(Single Resposibility
Principle)
- CARP(Composite/Aggregate Reuse
Principle)
- LoD(Law Of Demeter):don't talk
to stranger
之后我們來詳細(xì)討論這些原則
大名鼎鼎的GOF的設(shè)計(jì)模式是最著名的一本里程碑的作品
=模式分類=

=模式之間的關(guān)系=

=如何應(yīng)用模式=
DP中的引言說得很好,如何應(yīng)該模式來解決設(shè)計(jì)問題
* 尋找合適的對(duì)象
對(duì)象包括數(shù)據(jù)和操作, 對(duì)象在收到請(qǐng)求(或消息)后, 執(zhí)行相應(yīng)的操作
客戶請(qǐng)求是使對(duì)象執(zhí)行操作的唯一方法, 操作又是對(duì)象改變內(nèi)部數(shù)據(jù)的唯一方法
(這就是封裝的意義,之所以強(qiáng)調(diào)對(duì)象的成員應(yīng)該是私有的原因)
OOD最困難的部分就是將系統(tǒng)分解成對(duì)象集合,因?yàn)橐紤]許多因素:
封裝,粒度,信賴關(guān)系,靈活性,性能,演化,復(fù)用等等,它們之間也互相有所影響或沖突.
設(shè)計(jì)模式可以幫助我們確定那些并不明顯的抽象和描述這些抽象的對(duì)象,如Strategy, State,etc.
==決定對(duì)象的粒度==
如何決定對(duì)象的大小,數(shù)目以及范圍呢, 設(shè)計(jì)模式亦有所幫助:
Facade 描述了怎樣用對(duì)象表示完整的子系統(tǒng)
Flyweight
Abstact Factory
Builder
Visitor
Command
==指定對(duì)象接口==
對(duì)象接口描述了該對(duì)象所能接受的全部請(qǐng)求的集合, 也就是它能夠提供哪些服務(wù)(方法)
當(dāng)給對(duì)象發(fā)送請(qǐng)求時(shí), 所引起的具體操作既與請(qǐng)求本身有關(guān),又與接受對(duì)象有關(guān)
支持相同請(qǐng)求的不同對(duì)象可能對(duì)請(qǐng)求激發(fā)的操作有不同的實(shí)現(xiàn)(動(dòng)態(tài)綁定和多態(tài))
而設(shè)計(jì)模式通過確定接口的主要組成部分及經(jīng)接口發(fā)送的數(shù)據(jù)類型, 來幫助你定義接口.
DP也許還會(huì)告訴你接口中不應(yīng)包括哪些東西, 比如Memento模式所規(guī)定的接口
DP也指定了接口之間的關(guān)系,特別地,它常要求一些類具有相同或相似的接口,或?qū)σ恍╊惖慕涌谧鞒鲆恍┫拗?br />
如Decorator, Proxy模式要求修飾/代理對(duì)象和被修飾/受代理的對(duì)象接口保持一致
Visitor模式中Vistor接口必須反映能訪問的對(duì)象的所有類
==描述對(duì)象的實(shí)現(xiàn)==
* 類繼承還是接口繼承呢
* 針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程
==運(yùn)用復(fù)用機(jī)制==
1.優(yōu)先使用對(duì)象組合,而不是類繼承
2.委托
3.繼承和泛型的比較
==關(guān)聯(lián)運(yùn)行時(shí)刻和編譯時(shí)刻的結(jié)構(gòu)==
==設(shè)計(jì)應(yīng)支持變化==
* 設(shè)計(jì)中常出現(xiàn)的問題
** 通過顯式地指定一個(gè)類來創(chuàng)建對(duì)象
*** Factory , Prototype
** 對(duì)特殊操作的依賴
*** Chain of Reponsibility, Command
** 對(duì)硬件和軟件平臺(tái)的依賴
*** Abstract Factory, Bridge
** 對(duì)對(duì)象表示或?qū)崿F(xiàn)的依賴
** 算法依賴
** 緊耦合
*** Abstract Factory, command, facade, mediator, observere,chain of responsibility
** 通過生成子類來擴(kuò)充功能
*** Bridge, Chain of Reponsibility, composite, Decorator, Observer, Strategy
** 不能方便地對(duì)類進(jìn)行修改
*** Adapter, Decorator, visitor
=如何選擇設(shè)計(jì)模式=
* 考慮設(shè)計(jì)模式是如何解決設(shè)計(jì)問題的
* 瀏覽模式的意圖部分
* 研究模式怎樣互相關(guān)聯(lián)
* 研究目的相似的模式
* 檢查重新設(shè)計(jì)的原因
* 考慮你的設(shè)計(jì)中哪些是可變的

=怎樣使用設(shè)計(jì)模式=
* 大致瀏覽一遍模式
* 回頭研究結(jié)構(gòu)部分
* 看代碼示例部分
* 選擇模式參考者的名字, 使它們?cè)趹?yīng)用上下文中有意義
* 定義類
* 定義模式中專用于應(yīng)用的操作名稱
* 實(shí)現(xiàn)執(zhí)行模式中責(zé)任和協(xié)作的操作
啥叫模式? Patterns in solutions come from patterns in problems.
針對(duì)某一類經(jīng)常出現(xiàn)的問題所采取的行之有效的解決方案
"A pattern is a solution to a problem in a context."
"Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice."(Christopher Alexander -- A Pattern Language)
模式的四個(gè)基本要素:
1. 模式名稱pattern name
2. 問題problem
3. 解決方案solution
4. 效果consequences
如何描述設(shè)計(jì)模式(十大特點(diǎn))
1. 意圖:描述,別名
2. 動(dòng)機(jī):場(chǎng)景
3. 適用性: 什么情況下
4. 結(jié)構(gòu): 類圖, 序列圖
5. 參考者
6. 協(xié)作
7. 效果
8. 實(shí)現(xiàn)
9. 應(yīng)用
10. 相關(guān)模式
在實(shí)踐中學(xué)習(xí)是最佳的方式, 所以先要掌握每個(gè)模式的十大特點(diǎn),更加重要的是在實(shí)際應(yīng)用中學(xué)習(xí), 在水中學(xué)會(huì)游泳
以迭代器模式為例, Java中有一個(gè)Iterator接口
1 public interface Iterator
2 {
3 /**
4 * Tests whether there are elements remaining in the collection. In other
5 * words, calling <code>next()</code> will not throw an exception.
6 *
7 * @return true if there is at least one more element in the collection
8 */
9 boolean hasNext();
10
11 /**
12 * Obtain the next element in the collection.
13 *
14 * @return the next element in the collection
15 * @throws NoSuchElementException if there are no more elements
16 */
17 Object next();
18
19 /**
20 * Remove from the underlying collection the last element returned by next
21 * (optional operation). This method can be called only once after each
22 * call to <code>next()</code>. It does not affect what will be returned
23 * by subsequent calls to next.
24 *
25 * @throws IllegalStateException if next has not yet been called or remove
26 * has already been called since the last call to next.
27 * @throws UnsupportedOperationException if this Iterator does not support
28 * the remove operation.
29 */
30 void remove();
31 }
32
假如你的類中有一些聚集關(guān)系, 那么考慮增加一個(gè)iterator方法,以實(shí)現(xiàn)下面這個(gè)接口
public interface Iterable
{
/**
* Returns an iterator for the collection.
*
* @return an iterator.
*/
Iterator iterator ();
}
返回你自己實(shí)現(xiàn)的ConcreteIterator類, 這個(gè)ConcreteIterator當(dāng)然是實(shí)現(xiàn)了
Iterator接口的
你會(huì)發(fā)現(xiàn)在遍歷和迭代類中的這個(gè)成員的聚集元素時(shí)會(huì)有不同的感覺, 因?yàn)檫@個(gè)Iterator與實(shí)現(xiàn)是分離的.
你的類終歸是給自己或別人使用的,在調(diào)用者的眼里, 非常簡(jiǎn)單, 管你里面是怎么實(shí)現(xiàn)的呢,
反正我知道你能給我一個(gè)迭代器就夠了, 這里面就體現(xiàn)了面向接口編程的好處. 也就是按契約編程
自Java5以來提供的
BlockingQueue是一種特殊的隊(duì)列, 它 是支持兩個(gè)附加操作的
Queue
,這兩個(gè)操作是:檢索元素時(shí)等待隊(duì)列變?yōu)榉强眨约按鎯?chǔ)元素時(shí)等待空間變得可用。
以JDK中的例子略加改寫如下
1 import java.util.concurrent.ArrayBlockingQueue;
2 import java.util.concurrent.BlockingQueue;
3
4 class Producer implements Runnable {
5 private final BlockingQueue queue;
6
7 Producer(BlockingQueue q) {
8 queue = q;
9 }
10
11 public void run() {
12 try {
13 while (true) {
14 queue.put(produce());
15 }
16 } catch (InterruptedException ex) {
17 System.out.println("produce interrupted " + ex.getMessage());
18 Thread.currentThread().interrupt();
19 //return;
20 }
21 }
22
23 Object produce() {
24 System.out.println("produce laugh");
25 return "haha";
26 }
27 }
28
29 class Consumer implements Runnable {
30 private final BlockingQueue queue;
31
32 Consumer(BlockingQueue q) {
33 queue = q;
34 }
35
36 public void run() {
37 try {
38 while (true) {
39 consume(queue.take());
40 }
41 } catch (InterruptedException ex) {
42 System.out.println("consume interrupted " + ex.getMessage());
43 Thread.currentThread().interrupt();
44 }
45 }
46
47 void consume(Object x) {
48 System.out.println("consume laugh "+ x);
49 }
50 }
51
52 public class BlockingQueueTest {
53 public static void main(String args[]) {
54 BlockingQueue q = new ArrayBlockingQueue(10);
55 Producer p = new Producer(q);
56 Consumer c1 = new Consumer(q);
57 Consumer c2 = new Consumer(q);
58 Thread pTh = new Thread(p);
59 pTh.start();
60 Thread cTh1 = new Thread(c1);
61 cTh1.start();
62 Thread cTh2 = new Thread(c2);
63 cTh2.start();
64 try {
65 Thread.sleep(3000);
66 }catch (Exception e) {
67 // TODO: handle exception
68 }
69 pTh.interrupt();
70 cTh1.interrupt();
71 cTh2.interrupt();
72 }
73 }
74