
2006年3月17日
在一個(gè)項(xiàng)目里面有這么一個(gè)技術(shù)需求:
1.集合中元素個(gè)數(shù),10M
2.根據(jù)上限和下限從一個(gè)Set中過濾出滿足要求的元素集合.
實(shí)際這個(gè)是個(gè)很典型的技術(shù)要求, 之前的項(xiàng)目也遇見過,但是因?yàn)楫?dāng)時(shí)的類庫不多, 都是直接手寫實(shí)現(xiàn)的. 方式基本等同于第一個(gè)方式.
在這個(gè)過程中, 我寫了四個(gè)方式, 基本記錄到下面.
第一個(gè)方式:對Set進(jìn)行迭代器遍歷, 判斷每個(gè)元素是否都在上限和下限范圍中.如果滿足則添加到結(jié)果集合中, 最后返回結(jié)果集合.
測試效果:集合大小100K, 運(yùn)算時(shí)間 3000ms+
過濾部分的邏輯如下:
1 void filerSet(Set<BigDecimal> targetSet, String lower, String higher) {
2 BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
3 BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
4
5 Set<BigDecimal> returnSet = new HashSet<BigDecimal>();
6 for (BigDecimal object : targetSet) {
7 if (isInRange(object, bdLower, bdHigher)) {
8 returnSet.add(object);
9 }
10 }
11 }
12
13 private boolean isInRange(BigDecimal object, BigDecimal bdLower,
14 BigDecimal bdHigher) {
15 return object.compareTo(bdLower) >= 0
16 && object.compareTo(bdHigher) <= 0;
17 }
第二個(gè)方式: 借助TreeSet, 原始集合進(jìn)行排序, 然后直接subset.
測試效果: 集合大小10M, 運(yùn)算時(shí)間: 12000ms+(獲得TreeSet) , 200ms(獲得結(jié)果)
過濾部分的邏輯如下(非常繁瑣):
1 Set<BigDecimal> getSubSet(TreeSet<BigDecimal> targetSet, String lower,
2 String higher) {
3
4 BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
5 BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
6
7 if ((bdHigher.compareTo(targetSet.first()) == -1)
8 || (bdLower.compareTo(targetSet.last()) == 1)) {
9 return null;
10 }
11
12 boolean hasLower = targetSet.contains(bdLower);
13 boolean hasHigher = targetSet.contains(bdHigher);
14 if (hasLower) {
15 if (hasHigher) {
16 System.out.println("get start:" + bdLower);
17 System.out.println("get end:" + bdHigher);
18 return targetSet.subSet(bdLower, true, bdHigher, true);
19 } else {
20 BigDecimal newEnd = null;
21 System.out.println("get start:" + bdLower);
22 SortedSet<BigDecimal> returnSet = null;
23 if (bdHigher.compareTo(targetSet.last()) != -1) {
24 newEnd = targetSet.last();
25 } else {
26 SortedSet<BigDecimal> newTargetSet = targetSet
27 .tailSet(bdLower);
28 for (BigDecimal object : newTargetSet) {
29 if (object.compareTo(bdHigher) == 1) {
30 newEnd = object;
31 break;
32 } else if (object.compareTo(bdHigher) == 0) {
33 newEnd = object;
34 break;
35 }
36 }
37 }
38 returnSet = targetSet.subSet(bdLower, true, newEnd, true);
39 if (newEnd.compareTo(bdHigher) == 1) {
40 returnSet.remove(newEnd);
41 }
42 return returnSet;
43 }
44
45 } else {
46 if (hasHigher) {
47 System.out.println("get end:" + bdHigher);
48 TreeSet<BigDecimal> newTargetSet = (TreeSet<BigDecimal>) targetSet
49 .headSet(bdHigher, true);
50 BigDecimal newStart = null;
51 SortedSet<BigDecimal> returnSet = null;
52
53 if (bdLower.compareTo(targetSet.first()) == -1) {
54 newStart = targetSet.first();
55 } else {
56 for (BigDecimal object : newTargetSet) {
57 if (object.compareTo(bdLower) != -1) {
58 newStart = object;
59 break;
60 }
61 }
62 }
63 returnSet = targetSet.subSet(newStart, true, bdHigher, true);
64
65 return returnSet;
66 } else {
67 System.out.println("Not get start:" + bdLower);
68 System.out.println("Not get end:" + bdHigher);
69 BigDecimal newStart = null;
70 BigDecimal newEnd = null;
71 if (bdHigher.compareTo(targetSet.last()) != -1) {
72 newEnd = targetSet.last();
73 }
74 if (bdLower.compareTo(targetSet.first()) == -1) {
75 newStart = targetSet.first();
76 }
77 for (BigDecimal object : targetSet) {
78 if (newStart == null) {
79 if (object.compareTo(bdLower) != -1) {
80 newStart = object;
81 if (newEnd != null) {
82 break;
83 }
84 }
85 }
86
87 if (newEnd == null) {
88 if (object.compareTo(bdHigher) != -1) {
89 newEnd = object;
90 if (newStart != null) {
91 break;
92 }
93 }
94 }
95 }
96
97 if (newStart == null) {
98 if (newEnd == null) {
99 if ((bdHigher.compareTo(targetSet.first()) == -1)
100 || (bdLower.compareTo(targetSet.last()) == 1)) {
101 return null;
102 }
103 return targetSet;
104 } else {
105 SortedSet<BigDecimal> newTargetSet = targetSet.headSet(
106 newEnd, true);
107 if (newEnd.compareTo(bdHigher) == 1) {
108 newTargetSet.remove(newEnd);
109 }
110 return newTargetSet;
111 }
112 } else {
113 if (newEnd == null) {
114 SortedSet<BigDecimal> newTargetSet = targetSet.tailSet(
115 newStart, true);
116 return newTargetSet;
117 } else {
118 SortedSet<BigDecimal> newTargetSet = targetSet.subSet(
119 newStart, true, newEnd, true);
120 if (newEnd.compareTo(bdHigher) == 1) {
121 newTargetSet.remove(newEnd);
122 }
123 return newTargetSet;
124 }
125 }
126 }
127 }
128 }
第三種方式: 使用Apache Commons Collections, 直接對于原始Set進(jìn)行filter.
測試效果:集合大小10M,過濾結(jié)果1M, 運(yùn)算時(shí)間: 1000ms+
過濾部分的代碼如下:
1 //過濾的主體邏輯
2 void filterSet(Set<BigDecimal> targetSet, String lower, String higher) {
3 final BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
4 final BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
5
6 Predicate predicate = new Predicate() {
7 public boolean evaluate(Object object) {
8 BigDecimal bDObject = (BigDecimal) object;
9 return bDObject.compareTo(bdLower) >= 0
10 && bDObject.compareTo(bdHigher) <= 0;
11 }
12 };
13
14 CollectionUtils.filter(targetSet, predicate);
15 }
第四種方式:使用Guava(google Collections), 直接對于原始Set進(jìn)行Filter
測試效果:集合大小10M,過濾結(jié)果1M, 運(yùn)算時(shí)間: 100ms-
過濾部分的代碼如下:
1 //guava filter
2
3 Set<BigDecimal> filterSet(Set<BigDecimal> targetSet, String lower,
4 String higher) {
5 final BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
6 final BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
7
8 Set<BigDecimal> filterCollection = Sets.filter(targetSet,
9 new Predicate<BigDecimal>() {
10 @Override
11 public boolean apply(BigDecimal input) {
12 BigDecimal bDObject = (BigDecimal) input;
13 return bDObject.compareTo(bdLower) >= 0
14 && bDObject.compareTo(bdHigher) <= 0;
15 }
16 });
17
18 return filterCollection;
19 }
四種方式對比如下:
第一種方式: 僅依賴于JAVA原生類庫 遍歷時(shí)間最慢, 代碼量很小
第二種方式: 僅依賴于JAVA原生類庫 遍歷時(shí)間比較慢(主要慢在生成有序Set), 代碼量最多
第三種方式: 依賴于Apache Commons Collections, 遍歷時(shí)間比較快, 代碼量很少
第四種方式: 依賴于Guava, 遍歷時(shí)間最快, 代碼量很少
基于目前個(gè)人的技術(shù)水平和視野, 第四種方式可能是最佳選擇.
記錄一下, 以后可能還會有更好的方案.
posted @
2014-06-21 23:33 混沌中立 閱讀(7374) |
評論 (10) |
編輯 收藏
在幾年之前,在大學(xué)里面的時(shí)候,認(rèn)為系統(tǒng)的架構(gòu)設(shè)計(jì),就像建筑設(shè)計(jì)一樣,會把骨架搭成,然后有具體人員進(jìn)行詳細(xì)的開發(fā).
在后來,工作中,慢慢有了一些變化,因?yàn)樵鹊南敕ú惶泻蠈?shí)際,系統(tǒng)就是在變化之中的,如果固定了骨架,那就很難的敏捷面對變化.
所以,系統(tǒng)的架構(gòu)設(shè)計(jì),應(yīng)該是面向接口的設(shè)計(jì),確定各個(gè)部分之間的數(shù)據(jù)接口和方法接口.這樣,即使有了變化,只要遵循接口的定義,就還是可以面對變化.
最近,又有了想法的變化.架構(gòu)的設(shè)計(jì),應(yīng)該就是規(guī)則和規(guī)約的設(shè)計(jì).設(shè)計(jì)出一系列,統(tǒng)一的,和諧的規(guī)則,在這些規(guī)則之前圈住的部分,實(shí)際就是系統(tǒng)的全貌.
接口的設(shè)計(jì),實(shí)際只是規(guī)則和規(guī)約設(shè)計(jì)的一個(gè)部分.
架構(gòu)的設(shè)計(jì),不應(yīng)該只是程序方面的事情,同時(shí)也包含了心理學(xué)方面和社會學(xué)方面的一些規(guī)則.例如:團(tuán)隊(duì)在面對變化時(shí)候,需要采用的規(guī)則和流程.
只有包含了這些非程序上的規(guī)則之后,才能保證架構(gòu)風(fēng)格的統(tǒng)一協(xié)調(diào).
以上,是我對系統(tǒng)設(shè)計(jì)的想法的轉(zhuǎn)變過程.記錄于此,以供回溯.
posted @
2009-09-02 10:53 混沌中立 閱讀(248) |
評論 (0) |
編輯 收藏
面對著滿屏幕的程序
是三年前,項(xiàng)目剛剛啟動的時(shí)候,同事寫的代碼.
三年過去了,項(xiàng)目由第一期變成了第七期.
這段代碼還是在這里,有個(gè)屬性是list,其中每個(gè)cell都是一個(gè)長度18的String數(shù)組.
數(shù)組里面放置了所需要導(dǎo)出到頁面table的內(nèi)容.
現(xiàn)在要開始修改了,需要向頁面的table中增加4列.
繁瑣的讓人要命的工作,需要跟蹤這個(gè)循環(huán),判斷每個(gè)pattern下面,這個(gè)長度18的數(shù)組里面放了哪些內(nèi)容.
好吧,對象化維護(hù)從數(shù)組開始,把數(shù)組對折,因?yàn)檫@個(gè)數(shù)組時(shí)一個(gè)比較數(shù)組,前面9個(gè)元素是之前的情況,后面9個(gè)事之后的情況.
用一個(gè)bean,放入兩次就可以了.但是bean中,需要一個(gè)標(biāo)志,標(biāo)識是之前的情況還是之后的情況.
同時(shí)需要一個(gè)transform方法,把之前從幾個(gè)來源過來的情況,變成bean的屬性.
接下來需要一個(gè)values方法,把bean里面的屬性直接按順序轉(zhuǎn)化成數(shù)組.
本期新增的4個(gè)屬性,直接放入bean中就可以了.
這樣原來很復(fù)雜的數(shù)組,就可以簡單的用對象來解決.外部的接口完全沒有變化.
維護(hù)程序,從把數(shù)組(特別是異型數(shù)組)對象化開始.
posted @
2009-08-20 13:43 混沌中立 閱讀(1355) |
評論 (1) |
編輯 收藏
這個(gè)小的project是前一個(gè)階段,待業(yè)在家的時(shí)候,迷戀sudoku的時(shí)候,自己寫來玩的。
正好當(dāng)時(shí)在看Uncle Bob的《Agile Software Development: Principles, Patterns, and Practices》 (敏捷軟件開發(fā):原則、模式與實(shí)踐),所以就按照自己對書中的一些概念和方法的理解,結(jié)合自己之前的開發(fā)經(jīng)驗(yàn)寫出來一段小的代碼。
代碼行數(shù): < 900
類的個(gè)數(shù): 18
抽象類的個(gè)數(shù):2
工廠類的個(gè)數(shù):1
包的個(gè)數(shù):5
一些關(guān)于類和包作用的說明:
1.Cell:表示一個(gè)Cell,是一個(gè)游戲中的一個(gè)單元格。
? Cell主要由3個(gè)部分組成,Point,Value,Status.
2.Point:表示一個(gè)坐標(biāo),主要格式為:(2,3).
? ?。。∽⒁猓河捎趥€(gè)人比較懶,所以開始的錯(cuò)誤被貫徹了下來。
? 這個(gè)錯(cuò)誤就是(2,3)表示的是由最左上的位置為坐標(biāo)原點(diǎn),第二行和第三列所確定的那個(gè)單元格。也就是縱坐標(biāo)在前,橫坐標(biāo)在后了。
3.Value:表示一個(gè)值
4.Status:表示Cell的狀態(tài),只有兩個(gè)狀態(tài),一個(gè)是NotSure,另一個(gè)是Sure.
5.AbstractCells:表示一些cell的集合,主要有三個(gè)子類
???? BlockCells:表示一個(gè)由多個(gè)Cell組成的塊,例如一個(gè)2*2由4個(gè)Cell組成的塊,或者一個(gè)2*3由6個(gè)Cell組成的塊
???? HorizonCells:表示一個(gè)橫行,即:從(0,0)到(0,n)坐標(biāo)確定的所有Cell的集合。
???? VerticalCells:表示一個(gè)縱行,即:從(0,0)到(n,0)坐標(biāo)確定的所有Cell的集合。
6.AbstractPolicy:就是游戲的策略。
?? 這個(gè)主要表示的是:4*4的游戲,還是9*9的游戲。
?? 可以在以后對此類進(jìn)行繼承和擴(kuò)展,例如16*16的游戲我就沒有實(shí)現(xiàn)。
?? 主要擴(kuò)展3個(gè)方法:
????????????????? 1)getValueRange,返回當(dāng)前policy的value的個(gè)數(shù)。4*4的游戲的getValueRange返回的就應(yīng)該是4。
??? ??? ? 2)getStep:表示當(dāng)前policy中相鄰的兩個(gè)BlockCells的坐標(biāo)差。
??? ??? ? 3)getIncrease:說不明白了:)(只可意會不可言傳。)
7.Game:進(jìn)行Policy的場所(我一直想拋棄這個(gè)類)
8.TestGame:游戲運(yùn)行的地方,包括從PolicyFactory取得指定的Policy,設(shè)置輸入輸出文件的路徑。
9.PolicyFactory:取得Policy的工廠。
??? getPolicy(int x) :這個(gè)方法獲得的是正方形的sudoku的策略。例如:4*4的,9*9,16*16。
??? getPolicy(int x, int y):這個(gè)方法獲得的是長方形的Sudoku的策略。例如:9*12的。
雖然是盡量避免bad code smell,但是由于能力有限,還是出現(xiàn)了一些不好的地方。
例如:之間的關(guān)聯(lián)關(guān)系還是很多,而且很強(qiáng);抽象的方法和抽象類的個(gè)數(shù)偏少等等。
里面實(shí)現(xiàn)了三個(gè)解決sudoku的方法:
1.在一個(gè)Cell中出現(xiàn)的Value,不會在和這個(gè)Cell處在同一個(gè)AbstractCells中的所有Cell中出現(xiàn);
2.如果一個(gè)Cell中,所有可能出現(xiàn)的Value的個(gè)數(shù)為1,那么Cell的Value必然是這個(gè)最后的Value;
2.如果一個(gè)Value,如果在當(dāng)前AbstractCells的所有其他的Cell中都不可能出現(xiàn),那么它必然是最后一個(gè)Cell的Value。
附件1:src code
http://www.aygfsteel.com/Files/GandofYan/sudoku.rar
附件2:輸入輸出文件的example
http://www.aygfsteel.com/Files/GandofYan/temp.rar
posted @
2006-07-13 16:19 混沌中立 閱讀(2165) |
評論 (4) |
編輯 收藏
如同Tom DeMacro說的:無法控制的東西就不能管理,無法測量的東西就無法控制。
軟件的度量對于設(shè)計(jì)者和開發(fā)者非常重要,之前只是對這些有一個(gè)簡單的了解。今天看來,了解的還遠(yuǎn)遠(yuǎn)不夠。
- Cyclomatic Complexity (圈復(fù)雜性)
- Response for Class (類的響應(yīng))
- Weighted methods per class (每個(gè)類重量方法)
一個(gè)系統(tǒng)中的所有類的這三個(gè)度量能夠說明這個(gè)系統(tǒng)的設(shè)計(jì)上的一些問題(不是全部),這三個(gè)度量越大越不好。
如果一個(gè)類這三個(gè)度量很高,證明了這個(gè)類需要重構(gòu)了。
以第一個(gè)度量來說,有下面的一個(gè)表格:
CC Value | Risk |
1-10 | Low
risk program |
11-20 | Moderate
risk |
21-50 | High
risk |
>50 | Most
complex and highly unstable method |
CC數(shù)值高,可以通過減少if else(switch case也算)判斷來達(dá)到目的;
可以通過減少類與其他類的調(diào)用來減少RFC;
通過分割大方法和大類來達(dá)到減少WMPC.
而Uncle Bob和Jdepend的度量標(biāo)準(zhǔn)應(yīng)該算是另一個(gè)度量系統(tǒng)。
用包中的每個(gè)類平均的內(nèi)部關(guān)系數(shù)目作為包內(nèi)聚性的一種表示方式。用于表示包和它的所有類之間的關(guān)系。
H=(R+1)/N
R:包內(nèi)類的關(guān)系數(shù)目(與包外部的類沒有關(guān)系)
N:包內(nèi)類的數(shù)量
被分析package的具體和抽象類(和接口)的數(shù)量,用于衡量package的可擴(kuò)展性。
依賴于被分析package的其他package的數(shù)量,用于衡量pacakge的職責(zé)。
被分析package的類所依賴的其他package的數(shù)量,用于衡量package的獨(dú)立性。
被分析package中的抽象類和接口與所在package所有類數(shù)量的比例,取值范圍為0-1。
A=Cc/N
用于衡量package的不穩(wěn)定性,取值范圍為0-1。I=0表示最穩(wěn)定,I=1表示最不穩(wěn)定。
I=Ce/(Ce+Ca)
??? ??? ? 被分析package和理想曲線A+I(xiàn)=1的垂直距離,用于衡量package在穩(wěn)定性和抽象性之間的平衡。理想??? ??? ? 的package要么完全是抽象類和穩(wěn)定(x=0,y=1),要么完全是具體類和不穩(wěn)定(x=1,y=0)。
??? ??? ? 取值范圍為0-1,D=0表示完全符合理想標(biāo)準(zhǔn),D=1表示package最大程度地偏離了理想標(biāo)準(zhǔn)。
??? ?? ?? D = |A+I-1|/0.70710678
??? ?? ?? 注:0.70710678*0.70710678 =2,既為“根號2“
我認(rèn)為D是一個(gè)綜合的度量,架構(gòu)和設(shè)計(jì)的改善可以通過D數(shù)值的減少來體現(xiàn),反之就可以認(rèn)為是設(shè)計(jì)和架構(gòu)的退化。
讀過http://javaboutique.internet.com/tutorials/metrics/index.html之后的一些想法
另一篇中文的內(nèi)容相近的文章可以參考http://www.jdon.com/artichect/coupling.htm
不過第二篇的中文文章中間關(guān)于Cyclomatic Complexity,有一個(gè)情況遺漏了
public void findApplications(String id, String name){
if(id!=null && name!=null) {
//do something
}else{
//do something
}
}
這種情況的CC不是2+1,而是2+1+1,依據(jù)是公式(1)。公式(2)應(yīng)該是公式(1)的簡化版。
Cyclomatic Complexity
(CC) = no of decision points + no of logical operations +1 (1)
Cyclomatic Complexity (CC) = number of decision points +1 (2)
參考了JDepend的參數(shù)和Uncle Bob的《
Agile Software Development: Principles, Patterns, and Practices》
(敏捷軟件開發(fā):原則、模式與實(shí)踐)
posted @
2006-06-07 10:52 混沌中立 閱讀(1515) |
評論 (3) |
編輯 收藏
轉(zhuǎn)自:http://www.keyusoft.cn/Contentview.aspx?year=2005&month=$10&day=$6&postid=123
通過一周左右的研究,對規(guī)則引擎有了一定的了解。現(xiàn)在寫點(diǎn)東西跟大家一起交流,本文主要針對RETE算法進(jìn)行描述。我的文筆不太好,如果有什么沒講明白的或是說錯(cuò)的地方,請給我留言。
首先申明,我的帖子借鑒了網(wǎng)上很流行的一篇帖子,好像是來自CSDN;還有一點(diǎn),我不想做太多的名詞解釋,因?yàn)槲乙膊皇莻€(gè)研究很深的人,定義的不好怕被笑話。
好現(xiàn)在我們開始。
首先介紹一些網(wǎng)上對于規(guī)則引擎比較好的帖子。
1、 來自JAVA視頻網(wǎng)
2、? RETE算法的最原始的描述,我不知道在哪里找到的,想要的人可以留下E-mail
?
接著統(tǒng)一一下術(shù)語,很多資料里的術(shù)語都非?;靵y。
1、? facts 事實(shí),我們實(shí)現(xiàn)的時(shí)候,會有一個(gè)事實(shí)庫。用F表示。
2、? patterns 模板,事實(shí)的一個(gè)模型,所有事實(shí)庫中的事實(shí)都必須滿足模板中的一個(gè)。用P表示。
3、
? conditions
條件,規(guī)則的組成部分。也必須滿足模板庫中的一條模板。用C表示。我們可以這樣理解facts、patterns、conditions之間的關(guān)系。
Patterns是一個(gè)接口,conditions則是實(shí)現(xiàn)這個(gè)接口的類,而facts是這個(gè)類的實(shí)例。
4、? rules 規(guī)則,由一到多個(gè)條件構(gòu)成。一般用and或or連接conditions。用R表示。
5、? actions 動作,激活一條rule執(zhí)行的動作。我們這里不作討論。
6、? 還有一些術(shù)語,如:working-memory、production-memory,跟這里的概念大同小異。
7、? 還有一些,如:alpha-network、beta-network、join-node,我們下面會用到,先放一下,一會討論。
?
引用一下網(wǎng)上很流行的例子,我覺得沒講明白,我在用我的想法解釋一下。
?
假設(shè)在規(guī)則記憶中有下列三條規(guī)則
?
if A(x) and B(x) and C(y) then add D(x)
if A(x) and B(y) and D(x) then add E(x)
if A(x) and B(x) and E(x) then delete A(x)
?
RETE算法會先將規(guī)則編譯成下列的樹狀架構(gòu)排序網(wǎng)絡(luò)
而工作記憶內(nèi)容及順序?yàn)閧A(1),A(2),B(2),B(3),B(4),C(5)},當(dāng)工作記憶依序進(jìn)入網(wǎng)絡(luò)后,會依序儲存在符合條件的節(jié)點(diǎn)中,直到完全符合條件的推論規(guī)則推出推論。以上述例子而言, 最后推得D(2)。
?
讓我們來分析這個(gè)例子。
?
模板庫:(這個(gè)例子中只有一個(gè)模板,算法原描述中有不同的例子, 一般我們會用tuple,元組的形式來定義facts,patterns,condition)
P: (?A , ?x)? 其中的A可能代表一定的操作,如例子中的A,B,C,D,E ; x代表操作的參數(shù)??纯催@個(gè)模板是不是已經(jīng)可以描述所有的事實(shí)。
?
條件庫:(這里元組的第一項(xiàng)代表實(shí)際的操作,第二項(xiàng)代表形參)
C1: (A , <x>)
C2: (B , <x>)
C3: (C , <y>)
C4: (D , <x>)
C5: (E , <x>)
C6: (B , <y>)
?
事實(shí)庫:(第二項(xiàng)代表實(shí)參)
F1: (A,1)
F2: (A,2)
F3: (B,2)
F4: (B,3)
F5: (B,4)
F6: (C,5)
?
?????? 規(guī)則庫:
?????? ? R1: c1^c2^c3
?????? ? R2: c1^c2^c4
?????? ? R3: c1^c2^c5
?
??????
?????? 有人可能會質(zhì)疑R1: c1^c2^c3,沒有描述出,原式中:
if A(x) and B(x) and C(y) then add D(x),A=B的關(guān)系。但請仔細(xì)看一下,這一點(diǎn)已經(jīng)在條件庫中定義出來了。
?
?????? 下面我來描述一下,規(guī)則引擎中RETE算法的實(shí)現(xiàn)。
?????? 首先,我們要定一些規(guī)則,根據(jù)這些規(guī)則,我們的引擎可以編譯出一個(gè)樹狀結(jié)構(gòu),上面的那張圖中是一種簡易的表現(xiàn),其實(shí)在實(shí)現(xiàn)的時(shí)候不是這個(gè)樣子的。
?????? 這就是beta-network出場的時(shí)候了,根據(jù)rules我們就可以確定beta-network,下面,我就畫出本例中的beta-network,為了描述方便,我把a(bǔ)lpha-network也畫出來了。
??????
?

上圖中,左邊的部分就是beta-network,右邊是alpha-network,圓圈是join-node.
從上圖中,我們可以驗(yàn)證,在beta-network中,表現(xiàn)出了rules的內(nèi)容,其中r1,r2,r3共享了許多BM和join-node,這是由于這些規(guī)則中有共同的部分,這樣能加快match的速度。
右
邊的alpha-network是根據(jù)事實(shí)庫構(gòu)建的,其中除alpha-network節(jié)點(diǎn)的節(jié)點(diǎn)都是根據(jù)每一條condition,從事實(shí)庫中
match過來的,這一過程是靜態(tài)的,即在編譯構(gòu)建網(wǎng)絡(luò)的過程中已經(jīng)建立的。只要事實(shí)庫是穩(wěn)定的,即沒有大幅度的變化,RETE算法的執(zhí)行效率應(yīng)該是非常
高的,其原因就是已經(jīng)通過靜態(tài)的編譯,構(gòu)建了alpha-network。我們可以驗(yàn)證一下,滿足c1的事實(shí)確實(shí)是w1,w2。
下
面我們就看一下,這個(gè)算法是怎么來運(yùn)行的,即怎么來確定被激活的rules的。從top-node往下遍歷,到一個(gè)join-node,與AM for
c1的節(jié)點(diǎn)匯合,運(yùn)行到match c1節(jié)點(diǎn)。此時(shí),match c1節(jié)點(diǎn)的內(nèi)容就是:w1,w2。繼續(xù)往下,與AM for
c2匯合(所有可能的組合應(yīng)該是w1^w3,w1^w4,w1^w5,w2^w3,w2^w4,w2^w5),因?yàn)閏1^c2要求參數(shù)相同,因此,
match
c1^c2的內(nèi)容是:w2^w3。再繼續(xù),這里有一個(gè)扇出(fan-out),其中只有一個(gè)join-node可以被激活,因?yàn)榕赃叺腁M只有一個(gè)非空。
因此,也只有R1被激活了。
解決扇出帶來的效率降低的問題,我們可以使用hashtable來解決這個(gè)問題。
RETE算法還有一些問題,如:facts庫變化,我們怎么才能高效的重建alpha-network,同理包括rules的變化對beta-network的影響。這一部分我還沒細(xì)看,到時(shí)候再貼出來吧。
posted @
2006-05-30 15:30 混沌中立 閱讀(1052) |
評論 (2) |
編輯 收藏
最近插件又加多了,eclipse老是死掉
?
一怒之下,刪除重裝
?
以前因?yàn)閼?沒有把插件的目錄和主體的目錄分開,這次也給它分開了
?
?
插件少了之后,eclipse確實(shí)快了不少
?
附eclipse啟動參數(shù): -nl en_US vmargs -Xverify:none -Xms256M -Xmx1024M
-XX:PermSize=50M? -XX:+UseParallelGC
posted @
2006-05-30 13:48 混沌中立 閱讀(570) |
評論 (0) |
編輯 收藏
freemind一個(gè)比較不錯(cuò)free的
mind map 軟件,很多人建議使用這個(gè)來管理自己的思路.
?
mind manager另一個(gè)比較不錯(cuò)的mind
map的軟件,可以和office兼容.不過是商業(yè)的
?
visio,就不介紹了.office里面有的東西.做流程圖來說,確實(shí)是比較好的軟件.但是在思路不清楚的時(shí)候,很難畫出什么有用的東西來.這點(diǎn)就比不上前面兩個(gè)東西了.不過對我來說visio可能更順手,因?yàn)槲医?jīng)常畫的是軟件流程圖........
posted @
2006-05-30 13:36 混沌中立 閱讀(1759) |
評論 (2) |
編輯 收藏
?
在最近的圍繞domain
object的討論中浮現(xiàn)出來了三種模型,(還有一些其他的旁枝,不一一分析了),經(jīng)過一番討論,各種問題逐漸清晰起來,在這里我試圖做一個(gè)總結(jié),便于大家了解和掌握。
第一種模型:只有g(shù)etter/setter方法的純數(shù)據(jù)類,所有的業(yè)務(wù)邏輯完全由business
object來完成(又稱TransactionScript),這種模型下的domain object被Martin Fowler稱之為“貧血的domain
object”。下面用舉一個(gè)具體的代碼來說明,代碼來自Hibernate的caveatemptor,但經(jīng)過我的改寫:
一個(gè)實(shí)體類叫做Item,指的是一個(gè)拍賣項(xiàng)目
一個(gè)DAO接口類叫做ItemDao
一個(gè)DAO接口實(shí)現(xiàn)類叫做ItemDaoHibernateImpl
一個(gè)業(yè)務(wù)邏輯類叫做ItemManager(或者叫做ItemService)
java代碼:?
|
public
class Item implementsSerializable{ ? ? privateLong id = null; ? ? privateint version; ? ?
privateString name; ? ? private User seller;
? ? privateString description; ? ? private MonetaryAmount
initialPrice; ? ? private MonetaryAmount
reservePrice; ? ? privateDate startDate; ? ? privateDate endDate; ? ? privateSet categorizedItems = newHashSet();
? ? privateCollection bids = newArrayList();
? ? private
Bid successfulBid; ? ? private ItemState state;
? ? private
User approvedBy; ? ? privateDate approvalDatetime; ? ? privateDate created = newDate();
? ? //?
getter/setter方法省略不寫,避免篇幅太長 }
|
java代碼:?
|
public
interface ItemDao { ? ? public Item
getItemById(Long id); ? ? publicCollection findAll();
? ? publicvoid
updateItem(Item item); }
|
ItemDao定義持久化操作的接口,用于隔離持久化代碼。
java代碼:?
|
public
class
ItemDaoHibernateImpl implements ItemDao extends
HibernateDaoSupport { ? ? public Item
getItemById(Long id){ ? ? ? ? return(Item) getHibernateTemplate().load(Item.class, id); ? ? } ? ? publicCollection findAll(){ ? ? ? ? return(List) getHibernateTemplate().find("from
Item"); ? ? } ? ? publicvoid updateItem(Item item){ ? ? ? ? getHibernateTemplate().update(item);
? ? } }
|
ItemDaoHibernateImpl完成具體的持久化工作,請注意,數(shù)據(jù)庫資源的獲取和釋放是在ItemDaoHibernateImpl
里面處理的,每個(gè)DAO方法調(diào)用之前打開Session,DAO方法調(diào)用之后,關(guān)閉Session。(Session放在ThreadLocal中,保證一次調(diào)用只打開關(guān)閉一次)
java代碼:?
|
public
class ItemManager { ? ? private ItemDao itemDao;
? ? publicvoid
setItemDao(ItemDao itemDao){
this.itemDao = itemDao;} ? ? public Bid
loadItemById(Long id){ ? ? ? ? itemDao.loadItemById(id);
? ? } ? ? publicCollection listAllItems(){ ? ? ? ? return? itemDao.findAll();
? ? } ? ? public Bid placeBid(Item item, User bidder, MonetaryAmount
bidAmount, ? ? ? ? ? ? ? ? ? ? ? ? ? ? Bid currentMaxBid, Bid
currentMinBid)throws BusinessException
{ ? ? ? ? ? ? if(currentMaxBid != null &&
currentMaxBid.getAmount().compareTo(bidAmount) > 0){ ? ? ? ? ? ? throw new
BusinessException("Bid too low."); ? ? } ? ? ? ? // Auction is active ? ? if( !state.equals(ItemState.ACTIVE)) ? ? ? ? ? ? throw new
BusinessException("Auction is not active yet."); ? ? ? ? // Auction still valid ? ? if( item.getEndDate().before(newDate())) ? ? ? ? ? ? throw new
BusinessException("Can't place new bid, auction already
ended."); ? ? ? ? // Create new Bid ? ? Bid newBid =
new Bid(bidAmount, item, bidder); ? ? ? ? // Place bid for this Item ? ?
item.getBids().add(newBid); ? ? itemDao.update(item);?
? ?//? 調(diào)用DAO完成持久化操作 ? ? return newBid; ? ?
} }
|
事務(wù)的管理是在ItemManger這一層完成的,ItemManager實(shí)現(xiàn)具體的業(yè)務(wù)邏輯。除了常見的和CRUD有關(guān)的簡單邏輯之外,這里還有一個(gè)placeBid的邏輯,即項(xiàng)目的競標(biāo)。
以上是一個(gè)完整的第一種模型的示例代碼。在這個(gè)示例中,placeBid,loadItemById,findAll等等業(yè)務(wù)邏輯統(tǒng)統(tǒng)放在ItemManager中實(shí)現(xiàn),而Item只有g(shù)etter/setter方法。
?
?
第二種模型,也就是Martin Fowler指的rich domain object是下面這樣子的:
一個(gè)帶有業(yè)務(wù)邏輯的實(shí)體類,即domain object是Item
一個(gè)DAO接口ItemDao
一個(gè)DAO實(shí)現(xiàn)ItemDaoHibernateImpl
一個(gè)業(yè)務(wù)邏輯對象ItemManager
java代碼:?
|
public
class Item implementsSerializable{ ? ? //? 所有的屬性和getter/setter方法同上,省略 ? ?
public Bid
placeBid(User bidder, MonetaryAmount
bidAmount, ? ? ? ? ? ? ? ? ? ? ? ? Bid currentMaxBid, Bid currentMinBid) ? ? ? ? ? ? throws BusinessException
{ ? ? ? ? ? ? ? ? // Check highest bid (can also be a different
Strategy (pattern)) ? ? ? ? ? ? if(currentMaxBid != null &&
currentMaxBid.getAmount().compareTo(bidAmount) > 0){ ? ? ? ? ? ? ? ? ? ? throw new
BusinessException("Bid too low."); ? ? ? ? ? ? } ? ? ? ? ? ? ? ? // Auction is active ? ? ? ? ? ?
if( !state.equals(ItemState.ACTIVE)) ? ? ? ? ? ? ? ? ? ? throw new
BusinessException("Auction is not active yet."); ? ? ? ? ? ? ? ? // Auction still valid ? ? ? ? ? ?
if( this.getEndDate().before(newDate())) ? ? ? ? ? ? ? ? ? ? throw new
BusinessException("Can't place new bid, auction already
ended."); ? ? ? ? ? ? ? ?
// Create new Bid ? ? ? ? ? ?
Bid newBid = new
Bid(bidAmount, this, bidder); ? ? ? ? ? ? ? ? // Place bid for this Item ? ? ? ? ?
? this.getBids.add(newBid);? //
請注意這一句,透明的進(jìn)行了持久化,但是不能在這里調(diào)用ItemDao,Item不能對ItemDao產(chǎn)生依賴! ? ? ? ? ? ?
? ? return newBid;
? ? } }
|
競標(biāo)這個(gè)業(yè)務(wù)邏輯被放入到Item中來。請注意this.getBids.add(newBid);
如果沒有Hibernate或者JDO這種O/R
Mapping的支持,我們是無法實(shí)現(xiàn)這種透明的持久化行為的。但是請注意,Item里面不能去調(diào)用ItemDAO,對ItemDAO產(chǎn)生依賴!
ItemDao和ItemDaoHibernateImpl的代碼同上,省略。
java代碼:?
|
public
class ItemManager { ? ? private ItemDao itemDao;
? ? publicvoid
setItemDao(ItemDao itemDao){
this.itemDao = itemDao;} ? ? public Bid
loadItemById(Long id){ ? ? ? ? itemDao.loadItemById(id);
? ? } ? ? publicCollection listAllItems(){ ? ? ? ? return? itemDao.findAll();
? ? } ? ? public Bid placeBid(Item item, User bidder, MonetaryAmount
bidAmount, ? ? ? ? ? ? ? ? ? ? ? ? ? ? Bid currentMaxBid, Bid
currentMinBid)throws BusinessException
{ ? ? ? ? item.placeBid(bidder, bidAmount, currentMaxBid,
currentMinBid); ? ? ? ? itemDao.update(item);?
? // 必須顯式的調(diào)用DAO,保持持久化 ? ? } }
|
在第二種模型中,placeBid業(yè)務(wù)邏輯是放在Item中實(shí)現(xiàn)的,而loadItemById和findAll業(yè)務(wù)邏輯是放在
ItemManager中實(shí)現(xiàn)的。不過值得注意的是,即使placeBid業(yè)務(wù)邏輯放在Item中,你仍然需要在ItemManager中簡單的封裝一層,以保證對placeBid業(yè)務(wù)邏輯進(jìn)行事務(wù)的管理和持久化的觸發(fā)。
這種模型是Martin Fowler所指的真正的domain
model。在這種模型中,有三個(gè)業(yè)務(wù)邏輯方法:placeBid,loadItemById和findAll,現(xiàn)在的問題是哪個(gè)邏輯應(yīng)該放在Item
中,哪個(gè)邏輯應(yīng)該放在ItemManager中。在我們這個(gè)例子中,placeBid放在Item中(但是ItemManager也需要對它進(jìn)行簡單的封裝),loadItemById和findAll是放在ItemManager中的。
切分的原則是什么呢? Rod Johnson提出原則是“case by case”,可重用度高的,和domain
object狀態(tài)密切關(guān)聯(lián)的放在Item中,可重用度低的,和domain object狀態(tài)沒有密切關(guān)聯(lián)的放在ItemManager中。
我提出的原則是:看業(yè)務(wù)方法是否顯式的依賴持久化。
Item的placeBid這個(gè)業(yè)務(wù)邏輯方法沒有顯式的對持久化ItemDao接口產(chǎn)生依賴,所以要放在Item中。請注意,如果脫離了Hibernate這個(gè)持久化框架,Item這個(gè)domain
object是可以進(jìn)行單元測試的,他不依賴于Hibernate的持久化機(jī)制。它是一個(gè)獨(dú)立的,可移植的,完整的,自包含的域?qū)ο?/span>。
而loadItemById和findAll這兩個(gè)業(yè)務(wù)邏輯方法是必須顯式的對持久化ItemDao接口產(chǎn)生依賴,否則這個(gè)業(yè)務(wù)邏輯就無法完成。如果你要把這兩個(gè)方法放在Item中,那么Item就無法脫離Hibernate框架,無法在Hibernate框架之外獨(dú)立存在。
?
?
第三種模型印象中好像是firebody或者是Archie提出的(也有可能不是,記不清楚了),簡單的來說,這種模型就是把第二種模型的domain
object和business object合二為一了。所以ItemManager就不需要了,在這種模型下面,只有三個(gè)類,他們分別是:
Item:包含了實(shí)體類信息,也包含了所有的業(yè)務(wù)邏輯
ItemDao:持久化DAO接口類
ItemDaoHibernateImpl:DAO接口的實(shí)現(xiàn)類
由于ItemDao和ItemDaoHibernateImpl和上面完全相同,就省略了。
java代碼:?
|
public
class Item implementsSerializable{ ? ? //? 所有的屬性和getter/setter方法都省略 ? ?privatestatic ItemDao itemDao;
? ? publicvoid
setItemDao(ItemDao itemDao){this.itemDao = itemDao;} ? ? ? ? publicstatic Item
loadItemById(Long id){ ? ? ? ? return(Item) itemDao.loadItemById(id);
? ? } ? ? publicstaticCollection findAll(){ ? ? ? ? return(List) itemDao.findAll();
? ? }
? ? public Bid placeBid(User bidder, MonetaryAmount bidAmount, ? ?
? ? ? ? ? ? ? ? Bid currentMaxBid, Bid currentMinBid) ? ? throws BusinessException
{ ? ? ? ? ? ? // Check highest bid (can also be a different
Strategy (pattern)) ? ? ? ? if(currentMaxBid != null &&
currentMaxBid.getAmount().compareTo(bidAmount) > 0){ ? ? ? ? ? ? ? ? throw new
BusinessException("Bid too low."); ? ? ? ? } ? ? ? ? ? ? ? ? // Auction is active ? ? ? ? if( !state.equals(ItemState.ACTIVE)) ? ? ? ? ? ? ? ? throw new
BusinessException("Auction is not active yet."); ? ? ? ? ? ? ? ? // Auction still valid ? ? ? ? if( this.getEndDate().before(newDate())) ? ? ? ? ? ? ? ? throw new
BusinessException("Can't place new bid, auction already
ended."); ? ? ? ? ? ? ? ?
// Create new Bid ? ? ? ? Bid
newBid = new
Bid(bidAmount, this, bidder); ? ? ? ? ? ? ? ? // Place bid for this Item ? ? ? ?
this.addBid(newBid); ? ? ? ? itemDao.update(this);?
? ? //? 調(diào)用DAO進(jìn)行顯式持久化 ? ? ? ?
return newBid;
? ? } }
|
在這種模型中,所有的業(yè)務(wù)邏輯全部都在Item中,事務(wù)管理也在Item中實(shí)現(xiàn)。
?
?
在上面三種模型之外,還有很多這三種模型的變種,例如partech的模型就是把第二種模型中的DAO和
Manager三個(gè)類合并為一個(gè)類后形成的模型;例如frain....(id很長記不住)的模型就是把第三種模型的三個(gè)類完全合并為一個(gè)單類后形成的模型;例如Archie是把第三種模型的Item又分出來一些純數(shù)據(jù)類(可能是,不確定)形成的一個(gè)模型。
但是不管怎么變,基本模型歸納起來就是上面的三種模型,下面分別簡單評價(jià)一下:
第一種模型絕大多數(shù)人都反對,因此反對理由我也不多講了。但遺憾的是,我觀察到的實(shí)際情形是,很多使用Hibernate的公司最后都是這種模型,這里面有很大的原因是很多公司的技術(shù)水平?jīng)]有達(dá)到這種層次,所以導(dǎo)致了這種貧血模型的出現(xiàn)。從這一點(diǎn)來說,Martin
Fowler的批評聲音不是太響了,而是太弱了,還需要再繼續(xù)吶喊。
第二種模型就是Martin
Fowler一直主張的模型,實(shí)際上也是我一直在實(shí)際項(xiàng)目中采用這種模型。我沒有看過Martin的POEAA,之所以能夠自己摸索到這種模型,也是因?yàn)閺?2年我已經(jīng)開始思考這個(gè)問題并且尋求解決方案了,但是當(dāng)時(shí)沒有看到Hibernate,那時(shí)候做的一個(gè)小型項(xiàng)目我已經(jīng)按照這種模型來做了,但是由于沒有O/R
Mapping的支持,寫到后來又不得不全部改成貧血的domain
object,項(xiàng)目做完以后再繼續(xù)找,隨后就發(fā)現(xiàn)了Hibernate。當(dāng)然,現(xiàn)在很多人一開始就是用Hibernate做項(xiàng)目,沒有經(jīng)歷過我經(jīng)歷的那個(gè)階段。
不過我覺得這種模型仍然不夠完美,因?yàn)槟氵€是需要一個(gè)業(yè)務(wù)邏輯層來封裝所有的domain
logic,這顯得非常羅嗦,并且業(yè)務(wù)邏輯對象的接口也不夠穩(wěn)定。如果不考慮業(yè)務(wù)邏輯對象的重用性的話(業(yè)務(wù)邏輯對象的可重用性也不可能好),很多人干脆就去掉了xxxManager這一層,在Web層的Action代碼直接調(diào)用xxxDao,同時(shí)容器事務(wù)管理配置到Action這一層上來。
Hibernate的caveatemptor就是這樣架構(gòu)的一個(gè)典型應(yīng)用。
第三種模型是我很反對的一種模型,這種模型下面,Domain
Object和DAO形成了雙向依賴關(guān)系,無法脫離框架測試,并且業(yè)務(wù)邏輯層的服務(wù)也和持久層對象的狀態(tài)耦合到了一起,會造成程序的高度的復(fù)雜性,很差的靈活性和糟糕的可維護(hù)性。也許將來技術(shù)進(jìn)步導(dǎo)致的O/R
Mapping管理下的domain object發(fā)展到足夠的動態(tài)持久透明化的話,這種模型才會成為一個(gè)理想的選擇。就像O/R
Mapping的流行使得第二種模型成為了可能(O/R Mapping流行以前,我們只能用第一種模型,第二種模型那時(shí)候是不現(xiàn)實(shí)的)。
?
?
既然大家都統(tǒng)一了觀點(diǎn),那么就有了一個(gè)很好的討論問題的基礎(chǔ)了。Martin Fowler的Domain
Model,或者說我們的第二種模型難道是完美無缺的嗎?當(dāng)然不是,接下來我就要分析一下它的不足,以及可能的解決辦法,而這些都來源于我個(gè)人的實(shí)踐探索。
在第二種模型中,我們可以清楚的把這4個(gè)類分為三層:
1、實(shí)體類層,即Item,帶有domain logic的domain
object
2、DAO層,即ItemDao和ItemDaoHibernateImpl,抽象持久化操作的接口和實(shí)現(xiàn)類
3、業(yè)務(wù)邏輯層,即ItemManager,接受容器事務(wù)控制,向Web層提供統(tǒng)一的服務(wù)調(diào)用
在這三層中我們大家可以看到,domain
object和DAO都是非常穩(wěn)定的層,其實(shí)原因也很簡單,因?yàn)閐omain object是映射數(shù)據(jù)庫字段的,數(shù)據(jù)庫字段不會頻繁變動,所以domain
object也相對穩(wěn)定,而面向數(shù)據(jù)庫持久化編程的DAO層也不過就是CRUD而已,不會有更多的花樣,所以也很穩(wěn)定。
問題就在于這個(gè)充當(dāng)business workflow facade的業(yè)務(wù)邏輯對象,它的變動是相當(dāng)頻繁的。業(yè)務(wù)邏輯對象通常都是無狀態(tài)的、受事務(wù)控制的、Singleton類,我們可以考察一下業(yè)務(wù)邏輯對象都有哪幾類業(yè)務(wù)邏輯方法:
第一類:DAO接口方法的代理,就是上面例子中的loadItemById方法和findAll方法。
ItemManager之所以要代理這種類,目的有兩個(gè):向Web層提供統(tǒng)一的服務(wù)調(diào)用入口點(diǎn)和給持久化方法增加事務(wù)控制功能。這兩點(diǎn)都很容易理解,你不能既給Web層程序員提供xxxManager,也給他提供xxxDao,所以你需要用xxxManager封裝xxxDao,在這里,充當(dāng)了一個(gè)簡單代理功能;而事務(wù)控制也是持久化方法必須的,事務(wù)可能需要跨越多個(gè)DAO方法調(diào)用,所以必須放在業(yè)務(wù)邏輯層,而不能放在DAO層。
但是必須看到,對于一個(gè)典型的web應(yīng)用來說,絕大多數(shù)的業(yè)務(wù)邏輯都是簡單的CRUD邏輯,所以這種情況下,針對每個(gè)DAO方法,xxxManager都需要提供一個(gè)對應(yīng)的封裝方法,這不但是非??菰锏模彩橇钊烁杏X非常不好的。
第二類:domain
logic的方法代理。就是上面例子中placeBid方法。雖然Item已經(jīng)有了placeBid方法,但是ItemManager仍然需要封裝一下Item的placeBid,然后再提供一個(gè)簡單封裝之后的代理方法。
這和第一種情況類似,其原因也一樣,也是為了給Web層提供一個(gè)統(tǒng)一的服務(wù)調(diào)用入口點(diǎn)和給隱式的持久化動作提供事務(wù)控制。
同樣,和第一種情況一樣,針對每個(gè)domain logic方法,xxxManager都需要提供一個(gè)對應(yīng)的封裝方法,同樣是枯燥的,令人不爽的。
第三類:需要多個(gè)domain object和DAO參與協(xié)作的business
workflow。這種情況是業(yè)務(wù)邏輯對象真正應(yīng)該完成的職責(zé)。
在這個(gè)簡單的例子中,沒有涉及到這種情況,不過大家都可以想像的出來這種應(yīng)用場景,因此不必舉例說明了。
通過上面的分析可以看出,只有第三類業(yè)務(wù)邏輯方法才是業(yè)務(wù)邏輯對象真正應(yīng)該承擔(dān)的職責(zé),而前兩類業(yè)務(wù)邏輯方法都是“無奈之舉”,不得不為之的事情,不但枯燥,而且令人沮喪。
分析完了業(yè)務(wù)邏輯對象,我們再回頭看一下domain object,我們要仔細(xì)考察一下domain
logic的話,會發(fā)現(xiàn)domain logic也分為兩類:
第一類:需要持久層框架隱式的實(shí)現(xiàn)透明持久化的domain
logic,例如Item的placeBid方法中的這一句:
java代碼:?
|
this.getBids().add(newBid);
|
上面已經(jīng)著重提到,雖然這僅僅只是一個(gè)Java集合的添加新元素的操作,但是實(shí)際上通過事務(wù)的控制,會潛在的觸發(fā)兩條SQL:一條是insert一條記錄到bid表,一條是更新item表相應(yīng)的記錄。如果我們讓Item脫離Hibernate進(jìn)行單元測試,它就是一個(gè)單純的Java集合操作,如果我們把他加入到Hibernate框架中,他就會潛在的觸發(fā)兩條SQL,這就是隱式的依賴于持久化的domain logic。
特別請注意的一點(diǎn)是:在沒有Hibernate/JDO這類可以實(shí)現(xiàn)“透明的持久化”工具出現(xiàn)之前,這類domain logic是無法實(shí)現(xiàn)的。
對于這一類domain logic,業(yè)務(wù)邏輯對象必須提供相應(yīng)的封裝方法,以實(shí)現(xiàn)事務(wù)控制。
第二類:完全不依賴持久化的domain logic,例如readonly例子中的Topic,如下:
java代碼:?
|
class Topic { ? ? boolean
isAllowReply(){ ? ? ? ? Calendar dueDate =
Calendar.getInstance();
? ? ? ? dueDate.setTime(lastUpdatedTime); ? ? ? ? dueDate.add(Calendar.DATE, forum.timeToLive); ? ? ? ? ? ? Date now = newDate();
? ? ? ? return
now.after(dueDate.getTime()); ? ? } }
|
注意這個(gè)isAllowReply方法,他和持久化完全不發(fā)生一丁點(diǎn)關(guān)系。在實(shí)際的開發(fā)中,我們同樣會遇到很多這種不需要持久化的業(yè)務(wù)邏輯(主要發(fā)生在日期運(yùn)算、數(shù)值運(yùn)算和枚舉運(yùn)算方面),這種domain
logic不管脫離不脫離所在的框架,它的行為都是一致的。對于這種domain
logic,業(yè)務(wù)邏輯層并不需要提供封裝方法,它可以適用于任何場合。
posted @
2006-05-30 13:31 混沌中立 閱讀(3059) |
評論 (1) |
編輯 收藏
原文地址:
http://www.cnblogs.com/idior/archive/2005/07/04/186086.html近日?有關(guān)o/r?m的討論突然多了起來.?在這里覺得有必要澄清一些概念,?免的大家討論來討論去,?才發(fā)現(xiàn)最根本的理解有問題.
1.?何謂實(shí)體?
實(shí)體(類似于j2ee中的Entity?Bean)通常指一個(gè)承載數(shù)據(jù)的對象,?但是注意它也是可以有行為的!?只不過它的行為一般只操作自身的數(shù)據(jù).?比如下面這個(gè)例子:
class?Person
{
??string?firstName;
??string?lastName;
??public?void?GetName()
??{
?????return??lastName+firstName;
??}???
}
GetName就是它的一個(gè)行為.
2?何謂對象?
對象最重要的特性在于它擁有行為.?僅僅擁有數(shù)據(jù),你可以稱它為對象,?但是它卻失去它最重要的靈魂.?
class?Person
{
??string?firstName;
??string?lastName;
??Role?role;
??int?baseWage;
??public?void?GetSalary()
??{
?????return?baseWage*role.GetFactory();
??}???
}
這樣需要和別的對象(不是Value?Object)打交道的對象,我就不再稱其為實(shí)體.?領(lǐng)域模型就是指由這些具有業(yè)務(wù)邏輯的對象構(gòu)成的模型.
3.?E/R?M?or?O/R?M?!!
仔細(xì)想想我們?yōu)槭裁葱枰猳/r?m,無非是想利用oo的多態(tài)來處理復(fù)雜的業(yè)務(wù)邏輯,?而不是靠一堆的if?else.?
而現(xiàn)在在很多人的手上o/r?m全變成了e/r?m.他們不考慮對象的行為,?而全關(guān)注于如何保存數(shù)據(jù).這樣也難怪他們會產(chǎn)生將CRUD這些操作放入對象中的念頭.?如果你不能深刻理解oo,?那么我不推薦你使用o/r?m,?Table?Gateway,?Row?Gateway才是你想要的東西.
作為一個(gè)O/R?M框架,很重要的一點(diǎn)就是實(shí)現(xiàn)映射的透明性(Transparent),比較顯著的特點(diǎn)就是在代碼中我們是看不到SQL語句的(框架自動生成了)。這里所指的O/R?M就是類似于此的框架,
4.?POEAA中的相關(guān)概念
??很多次發(fā)現(xiàn)有人錯(cuò)用其中的概念,?這里順便總結(jié)一下:
??1.?Table?Gateway
????以表為單位的實(shí)體,基本沒有行為,只有CRUD操作.
??2.?Row?Gateway
????以行為單位的實(shí)體,基本沒有行為,只有CRUD操作.
??3.?Active?Record
????以行為單位的實(shí)體,擁有一些基本的操作自身數(shù)據(jù)的行為(如上例中的GetName),同時(shí)包含有CRUD操作.
其實(shí)Active?Record最符合某些簡單的需求,?接近于E/R?m.
通常也有很多人把它當(dāng)作O/R?m.不過需要注意的是Active?Record中是充滿了SQL語句的(不像orm的SQL透明),?所以有人想起來利用O/R?m來實(shí)現(xiàn)"Active?Record",?雖然在他們眼里看起來很方便,?其實(shí)根本就是返祖.
用CodeGenerator來實(shí)現(xiàn)Active?Record也許是一個(gè)比較好的方法.
??4.?Data?Mapper
這才是真正的O/R?m,Hibernate等等工具的目標(biāo).
5.O/R?M需要關(guān)注的地方?(希望大家?guī)兔ν晟埔幌?
?1.?關(guān)聯(lián),?O/R?M是如何管理類之間的關(guān)聯(lián).當(dāng)然這不僅于o/r?m有關(guān)與設(shè)計(jì)者的設(shè)計(jì)水平也有很大關(guān)系.
?2.?O/R?M對繼承關(guān)系的處理.
?3.?O/R?M對事務(wù)的支持.
?4.?O/R?M對查詢的支持.
?
以上觀點(diǎn)僅屬個(gè)人意見,?不過在大家討論有關(guān)O/R?m之前,?希望先就一些基本概念達(dá)成共識,?不然討論下去會越離越遠(yuǎn).?
(建議:?如果對oo以及dp沒有一定程度的了解,?最好別使用o/r?m,?dataset?加上codesmith或許是更好的選擇)
posted @
2006-05-30 13:20 混沌中立 閱讀(381) |
評論 (0) |
編輯 收藏
from http://www.code365.com/web/122/Article/17927.Asp
Thomas Bayes,一位偉大的數(shù)學(xué)大師,他的理論照亮了今天的計(jì)算領(lǐng)域,和他的同事們不同:他認(rèn)為上帝的存在可以通過方程式證明,他最重要的作品被別人發(fā)行,而他已經(jīng)去世241年了。
18世紀(jì)牧師們關(guān)于概率的理論成為應(yīng)用發(fā)展的數(shù)學(xué)基礎(chǔ)的一部分。
搜索巨人Google和Autonomy,一家出售信息恢復(fù)工具的公司,都使用了貝葉斯定理(Bayesian
principles)為數(shù)據(jù)搜索提供近似的(但是技術(shù)上不確切)結(jié)果。研究人員還使用貝葉斯模型來判斷癥狀和疾病之間的相互關(guān)系,創(chuàng)建個(gè)人機(jī)器人,開發(fā)
能夠根據(jù)數(shù)據(jù)和經(jīng)驗(yàn)來決定行動的人工智能設(shè)備。
雖然聽起來很深奧,而這個(gè)原理的意思--大致說起來--卻很簡單:某件事情發(fā)生的概率大致可以由它過去發(fā)生的頻率近似地估計(jì)出來。研究人員把這個(gè)原理應(yīng)用在每件事上,從基因研究到過濾電子郵件。
在明尼蘇達(dá)州大學(xué)的網(wǎng)站上能夠找到一份詳細(xì)的數(shù)學(xué)概要。而在Gametheory.net上的一個(gè)Bayes Rule Applet程序讓你能夠回答諸如“如果你測試某種疾病,有多大風(fēng)險(xiǎn)”之類的問題。
貝葉斯理論的一個(gè)出名的倡導(dǎo)者就是微軟。該公司把概率用于它的Notification Platform。該技術(shù)將會被內(nèi)置到微軟未來的軟件中,而且讓計(jì)算機(jī)和蜂窩電話能夠自動地過濾信息,不需要用戶幫助,自動計(jì)劃會議并且和其他人聯(lián)系。
如果成功的話,該技術(shù)將會導(dǎo)致“context server”--一種電子管家的出現(xiàn),它能夠解釋人的日常生活習(xí)慣并在不斷變換的環(huán)境中組織他們的生活。
“Bayes的研究被用于決定我應(yīng)該怎樣最好地分配計(jì)算和帶寬,” Eric Horvitz表示,他是微軟研究部門Adaptive
Systems & Interaction
Group的高級研究員和分組管理者?!拔覀€(gè)人相信在這個(gè)不確定的世界里,你不能夠知道每件事,而概率論是任何智能的基礎(chǔ)?!?
到今年年底,Intel也將發(fā)布它自己的基于貝葉斯理論的工具包。一個(gè)關(guān)于照相機(jī)的實(shí)驗(yàn)警告醫(yī)生說病人可能很快遭受痛苦。在本周晚些時(shí)候在該公司的Developer Forum(開發(fā)者論壇)上將討論這種發(fā)展。
雖然它在今天很流行,Bayes的理論并不是一直被廣泛接受的:就在10年前,Bayes研究人員還在他們的專業(yè)上躊躇不前。但是其后,改進(jìn)的數(shù)學(xué)模型,更快的計(jì)算機(jī)和實(shí)驗(yàn)的有效結(jié)果增加了這種學(xué)派新的可信程度。
“問題之一是它被過度宣傳了,” Intel微處理器實(shí)驗(yàn)室的應(yīng)用軟件和技術(shù)管理經(jīng)理Omid Moghadam表示?!笆聦?shí)上,能夠處理任何事情的能力并不存在。真正的執(zhí)行在過去的10年里就發(fā)生了。”
Bayes啞元
Bayes的理論可以粗略地被簡述成一條原則:為了預(yù)見未來,必須要看看過去。Bayes的理論表示未來某件事情發(fā)生的概率可以通過計(jì)算它過去發(fā)生的頻率來估計(jì)。一個(gè)彈起的硬幣正面朝上的概率是多少?實(shí)驗(yàn)數(shù)據(jù)表明這個(gè)值是50%。
“Bayes表示從本質(zhì)上說,每件事都有不確定性,你有不同的概率類型,”斯坦佛的管理科學(xué)和工程系(Department of Management Science and Engineering at Stanford)的教授Ron Howard表示。
例如,假設(shè)不是硬幣,一名研究人員把塑料圖釘往上拋,想要看看它釘頭朝上落地的概率有多大,或者有多少可能性是側(cè)面著地,而釘子是指向什么方向的。形狀,成型過程中的誤差,重量分布和其他的因素都會影響該結(jié)果。
Bayes技術(shù)的吸引力在于它的簡單性。預(yù)測完全取決于收集到的數(shù)據(jù)--獲得的數(shù)據(jù)越多,結(jié)果就越好。另一個(gè)優(yōu)點(diǎn)在于Bayes模型能夠自我糾正,也就是說數(shù)據(jù)變化了,結(jié)果也就跟著變化。
概率論的思想改變了人們和計(jì)算機(jī)互動的方式?!斑@種想法是計(jì)算機(jī)能夠更象一個(gè)幫助者而不僅僅是一個(gè)終端設(shè)備,” Peter Norvig表示。他是Google的安全質(zhì)量總監(jiān)。他說“你在尋找的是一些指導(dǎo),而不是一個(gè)標(biāo)準(zhǔn)答案?!?
從這種轉(zhuǎn)變中,研究獲益非淺。幾年前,所謂的Boolean搜索引擎的一般使用需要把搜索按照“if, and, or but”的語法進(jìn)行提交,然后去尋找匹配的詞?,F(xiàn)在的搜索引擎采用了復(fù)雜的運(yùn)算法則來搜索數(shù)據(jù)庫,并找出可能的匹配。
如同圖釘?shù)哪莻€(gè)例子顯示的那樣,復(fù)雜性和對于更多數(shù)據(jù)的需要可能很快增長。由于功能強(qiáng)大的計(jì)算機(jī)的出現(xiàn),對于把好的猜測轉(zhuǎn)變成近似的輸出所必須的結(jié)果進(jìn)行控制成為可能。
更重要的是,UCLA的Judea Pearl這樣的研究人員研究出如何讓Bayes模型能夠更好地追蹤不同的現(xiàn)象之間條件關(guān)系的方法,這樣能夠極大地減少計(jì)算量。
例如,對于人口進(jìn)行大規(guī)模的關(guān)于肺癌成因的調(diào)查可能會發(fā)現(xiàn)它是一種不太廣泛的疾病,但是如果局限在吸煙者范圍內(nèi)進(jìn)行調(diào)查就可能會發(fā)現(xiàn)一些關(guān)聯(lián)性。對于肺癌患者進(jìn)行檢查能夠幫助調(diào)查清楚習(xí)慣和這種疾病之間的關(guān)系。
“每一個(gè)單獨(dú)的屬性或者征兆都可能取決于很多不同的事情,但是直接決定它的卻是為數(shù)不多的事情,”斯坦佛計(jì)算機(jī)科學(xué)系(computer
science department at Stanford)的助理教授Daphne
Koller表示?!霸谶^去的15年左右的時(shí)間里,人們在工具方面進(jìn)行了改革,這讓你能夠描繪出大量人群的情況。”
和其他一些項(xiàng)目一樣,Koller是使用概率論技術(shù)來更好地把病癥和疾病聯(lián)系起來,并把遺傳基因和特定的細(xì)胞現(xiàn)象聯(lián)系起來。
記錄演講
一項(xiàng)相關(guān)的技術(shù),名為Hidden Markov模型,讓概率能夠預(yù)測次序。例如,一個(gè)演講識別應(yīng)用知道經(jīng)常在“q”之后的字母是“u”。除了這些,該軟件還能夠計(jì)算“Qagga”(一種滅絕了的斑馬的名稱)一詞出現(xiàn)的概率。
概率技術(shù)已經(jīng)內(nèi)置在微軟的產(chǎn)品中了。Outlook Mobile
Manage是一個(gè)能夠決定什么時(shí)候往移動設(shè)備上發(fā)出一封內(nèi)勤的電子郵的軟件。它是從Priorities發(fā)展而來的,Priorities是微軟在
1998年公布的一個(gè)實(shí)驗(yàn)系統(tǒng)。Windows XP的故障檢修引擎也依賴于概率計(jì)算。
隨著該公司的Notification Platform開始內(nèi)置在產(chǎn)品中,在未來的一年中會有更多的應(yīng)用軟件發(fā)布,微軟的Horvitz這樣表示。
Notification
Platform的一個(gè)重要組成部分名為Coordinate,它從個(gè)人日歷,鍵盤,傳感器照相機(jī)以及其他來源收集數(shù)據(jù),來了解某個(gè)人生活和習(xí)慣。收集的
數(shù)據(jù)可能包括到達(dá)的時(shí)間,工作時(shí)間和午餐的時(shí)間長度,哪種類型的電話或電子郵件被保存,而哪些信息被刪除,在某天的特定時(shí)間里鍵盤被使用的頻率,等等。
這些數(shù)據(jù)可以被用來管理信息流和使用者收到的其他信息。例如,如果一位經(jīng)理在下午2:40發(fā)送了一封電子郵件給一名員工,
Coordinate可以檢查該員工的日歷程序,然后發(fā)現(xiàn)他在下午2:00有一個(gè)會議。該程序還可以掃描關(guān)于該員工習(xí)慣的數(shù)據(jù),然后發(fā)現(xiàn)該員工通常會在有
會議之后大約一個(gè)小時(shí)才重新使用鍵盤。該程序可能還能夠發(fā)現(xiàn)該名員工通常會在5分鐘之內(nèi)回復(fù)該經(jīng)理的電子郵件。根據(jù)上面這些數(shù)據(jù),該軟件能夠估計(jì)出該員工
可能至少在20分鐘之內(nèi)不可能回復(fù)該電子郵件,該軟件可能會把這條信息發(fā)送到該員工的手提電話上。同時(shí),該軟件可能會決定不把別人的電子郵件也轉(zhuǎn)發(fā)出去。
“我們正在平衡以打攪你為代價(jià)所獲得信息的價(jià)值,” Horvitz表示。使用這個(gè)軟件,他堅(jiān)持道,“能夠讓更多的人跟上事情的發(fā)展,而不被大量的信息所淹沒?!?
Horvitz補(bǔ)充道,隱私和對于這些功能的用戶控制是確定的。呼叫者并不知道為什么一條信息可能會被優(yōu)先或推遲處理。
微軟還把Bayes模型使用在其他的一些產(chǎn)品上,包括DeepListener 以及Quartet (語音激活),SmartOOF 以及TimeWave (聯(lián)系控制)。消費(fèi)者多媒體軟件也獲益非淺,Horvitz表示。
Bayes技術(shù)不僅僅被應(yīng)用在PC領(lǐng)域。在University of
Rochester,研究人員發(fā)現(xiàn)一個(gè)人的步伐可以在一步前發(fā)生改變。雖然這種改變對于人類來說太過于細(xì)微,一臺和電腦連接在一起的照相機(jī)可以捕捉并跟蹤
這種動作。如果行走異常出現(xiàn),計(jì)算機(jī)就能夠發(fā)出警報(bào)。
一個(gè)實(shí)驗(yàn)用的安全照相機(jī)采用了同樣的原理:大部分到達(dá)機(jī)場的人都會在停車以后直接走向目的地,所以如果有人停了車,然后走向另一輛車就不太正常,因此就可能引發(fā)警報(bào)。今年秋天一個(gè)創(chuàng)建Bayes模型和技術(shù)信息的基本引擎將會公布在Intel的開發(fā)者網(wǎng)站上。
理論沖突
雖然該技術(shù)聽起來簡單易懂,關(guān)于它的計(jì)算可能卻比較慢。Horvitz回憶說他是斯坦佛20世紀(jì)80年代僅有的兩個(gè)概率和人工智能的畢業(yè)生之一。其他所有的人學(xué)習(xí)的是邏輯系統(tǒng),采用的是“if and then”的模式和世界互動。
“概率論那時(shí)候不流行,” Horvitz表示。但是當(dāng)邏輯系統(tǒng)不能夠預(yù)測所有的意外情況時(shí),潮流發(fā)生了轉(zhuǎn)變。
很多研究人員開始承認(rèn)人類的決策過程比原來想象的要神秘的多?!霸谌斯ぶ悄茴I(lǐng)域存在著文化偏見,” Koller表示。“人們現(xiàn)在承認(rèn)他們并不知道他們的腦子是如何工作的?!?
即便在他的時(shí)代,Bayes發(fā)現(xiàn)他自己置身于主流之外。他于1702年出生于倫敦,后來他成為了一名Presbyterian
minister。雖然他看到了自己的兩篇論文被發(fā)表了,他的理論很有效,但是《Essay Toward Solving a Problem in
the Doctrine of Chances》卻一直到他死后的第三年,也就是1764年才被發(fā)表。
他的王室成員身份一直是個(gè)謎,直到最近幾年,新發(fā)現(xiàn)的一些信件表明他私下和英格蘭其他一些思想家看法一致。
“就我所知,他從來沒有寫下貝葉斯定理,” Howard表示。
神學(xué)家Richard Price和法國的數(shù)學(xué)家Pierre Simon
LaPlace成為了早期的支持者。該理論和后來George Boole,布爾數(shù)學(xué)之父,的理論背道而馳。George
Boole的理論是基于代數(shù)邏輯的,并最終導(dǎo)致了二進(jìn)制系統(tǒng)的誕生。也是皇室成員之一的Boole死于1864年。
雖然概率的重要性不容置疑,可是關(guān)于它的應(yīng)用的爭論卻沒有停止過。批評者周期性地聲稱Bayes模型依賴于主觀的數(shù)據(jù),而讓人類去判斷答案是否正確。而概率論模型沒有完全解決在人類思維過程中存在的細(xì)微差別的問題。
“兒童如何學(xué)習(xí)現(xiàn)在還不是很清楚,”IBM研究部門的科學(xué)和軟件副總裁 Alfred
Spector這樣表示。他計(jì)劃把統(tǒng)計(jì)學(xué)方法和邏輯系統(tǒng)在他的Combination
Hypothesis之中結(jié)合起來?!拔易畛跸嘈攀墙y(tǒng)計(jì)學(xué)的范疇,但是從某方面說,你將會發(fā)現(xiàn)不僅僅是統(tǒng)計(jì)學(xué)的問題?!?
但是,很有可能概率論是基礎(chǔ)。
“這是個(gè)基礎(chǔ),” Horvitz表示?!八缓雎粤艘欢螘r(shí)間,但是它是推理的基礎(chǔ)?!?/p>
posted @
2006-05-30 12:51 混沌中立 閱讀(437) |
評論 (0) |
編輯 收藏
最近在看<
敏捷軟件開發(fā):原則、模式與實(shí)踐
>在網(wǎng)上找了一些資料,就把他們集合到了一起,便于自己學(xué)習(xí)
此篇內(nèi)容來自一下兩處
http://blog.joycode.com/microhelper/archive/2004/11/30/40013.aspx
http://www.aygfsteel.com/ghawk/
另:關(guān)于面向?qū)ο笤O(shè)計(jì)的原則比較權(quán)威的是Uncle Bob--
Robert C. Martin的
http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign
單一職責(zé)原則——SRP
就一個(gè)類而言,應(yīng)該僅有一個(gè)引起它的變化的原因?
原則
最簡單,最單純的事情最容易控制,最有效
類的職責(zé)簡單而且集中,避免相同的職責(zé)分散到不同的類之中,避免一個(gè)類承擔(dān)過多的職責(zé)
減少類之間的耦合
當(dāng)需求變化時(shí),只修改一個(gè)地方
組件
每個(gè)組件集中做好一件事情
組件的顆粒度
發(fā)布的成本
可重用的成本
?
方法
避免寫臃腫的方法
Extract Method
?
重構(gòu)
Move Field/Move Class
Extract Method/Extract Class
?
最簡單的,也是最難以掌握的原則
?
實(shí)例分析
單一職責(zé)很容易理解,也很容易實(shí)現(xiàn)。所謂單一職責(zé),就是一個(gè)設(shè)計(jì)元素只做一件事。什么是“只做一件事”?簡單說就是少管閑事?,F(xiàn)實(shí)中就是如此,如果要你專心做一件事情,任何人都有信心可以做得很出色。但如果,你整天被亂七八糟的事所累,還有心思和精力把每件事都作好么?

?????
“單一職責(zé)”就是要在設(shè)計(jì)中為每種職責(zé)設(shè)計(jì)一個(gè)類,彼此保持正交,互不干涉。這個(gè)雕塑(二重奏)就是正交的一個(gè)例子,鋼琴家和小提琴家各自演奏自己的樂
譜,而結(jié)果就是一個(gè)和諧的交響樂。當(dāng)然,真實(shí)世界中,演奏小提琴和彈鋼琴的必須是兩個(gè)人,但是在軟件中,我們往往會把兩者甚至更多攪和到一起,很多時(shí)候只
是為了方便或是最初設(shè)計(jì)的時(shí)候沒有想到。?
??????這樣的例子在設(shè)計(jì)中很常見,書中就給了一個(gè)很好的例子:調(diào)制解調(diào)器。這是一個(gè)調(diào)制
解調(diào)器最基本的功能。但是這個(gè)類事實(shí)上完成了兩個(gè)職責(zé):連接的建立和中斷、數(shù)據(jù)的發(fā)送和接收。顯然,這違反了SRP。這樣做會有潛在的問題:當(dāng)僅需要改變
數(shù)據(jù)連接方式時(shí),必須修改Modem類,而修改Modem類的結(jié)果就是使得任何依賴Modem類的元素都需要重新編譯,不管它是不是用到了數(shù)據(jù)連接功能。
解決的辦法,書中也已經(jīng)給出:重構(gòu)Modem類,從中抽出兩個(gè)接口,一個(gè)專門負(fù)責(zé)連接、另一個(gè)專門負(fù)責(zé)數(shù)據(jù)發(fā)送。依賴Modem類的元素也要做相應(yīng)的細(xì)
化,根據(jù)職責(zé)的不同分別依賴不同的接口。最后由ModemImplementation類實(shí)現(xiàn)這兩個(gè)接口。

??????從這個(gè)例子中,我們不難發(fā)現(xiàn),違反SRP通常是由于過于“真實(shí)”地設(shè)計(jì)了一個(gè)類所造成的。因此,解決辦法是往更高一層進(jìn)行抽象
化提取,將對某個(gè)具體類的依賴改變?yōu)閷σ唤M接口或抽象類的依賴。當(dāng)然,這個(gè)抽象化的提取應(yīng)該根據(jù)需要設(shè)計(jì),而不是盲目提取。比如剛才這個(gè)Modem的例子
中,如果有必要,還可以把DataChannel抽象為DataSender和DataReceiver兩個(gè)接口。
開放封閉原則——OCP
軟件實(shí)體(類,模塊,函數(shù))應(yīng)該是可以擴(kuò)展的,但是不可修改的?
原則
?
對擴(kuò)展是開放的,當(dāng)需求改變時(shí)我們可以對模塊進(jìn)行擴(kuò)展,使其具有新的功能
對更改是封閉的,對模塊擴(kuò)展時(shí),不需要改動原來的代碼
面對抽象而不是面對細(xì)節(jié),抽象比細(xì)節(jié)活的更長
僵化的設(shè)計(jì)——如果程序中一處改動產(chǎn)生連鎖反應(yīng)。
方法
條件case?? if/else 語句
?
重構(gòu)
Replace Type Code With Class
Replace Type Code With State/Strategy
Replace Conditional with polymorphism
?
實(shí)例
開閉原則很簡單,一句話:“Closed for Modification; Open for Extension”——“對變更關(guān)閉;對擴(kuò)展開放”。開閉原則其實(shí)沒什么好講的,我將其歸結(jié)為一個(gè)高層次的設(shè)計(jì)總則。就這一點(diǎn)來講,OCP的地位應(yīng)該比SRP優(yōu)先。
OCP的動機(jī)很簡單:軟件是變化的。不論是優(yōu)質(zhì)的設(shè)計(jì)還是低劣的設(shè)計(jì)都無法回避這一問題。OCP說明了軟件設(shè)計(jì)應(yīng)該盡可能地使架構(gòu)穩(wěn)定而又容易滿足不同的需求。
為什么要OCP?答案也很簡單——重用。
“重用”,并不是什么軟件工程的專業(yè)詞匯,它是工程界所共用的詞匯。早在軟件出現(xiàn)前,工程師們就在實(shí)踐“重用”了。比如機(jī)械產(chǎn)品,通過零部
件的組裝得到最終的能夠使用的工具。由于機(jī)械部件的設(shè)計(jì)和制造過程是極其復(fù)雜的,所以互換性是一個(gè)重要的特性。一輛車可以用不同的發(fā)動機(jī)、不同的變速箱、
不同的輪胎……很多東西我們直接買來裝上就可以了。這也是一個(gè)OCP的例子。(可能是由于我是搞機(jī)械出身的吧,所以就舉些機(jī)械方面的例子^_^)。
如何在OO中引入OCP原則?把對實(shí)體的依賴改為對抽象的依賴就行了。下面的例子說明了這個(gè)過程:
05賽季的時(shí)候,一輛F1賽車有一臺V10引擎。但是到了06賽季,國際汽聯(lián)修改了規(guī)則,一輛F1賽車只能安裝一臺V8引擎。車隊(duì)很快投入了新賽車
的研發(fā),不幸的是,從工程師那里得到消息,舊車身的設(shè)計(jì)不能夠裝進(jìn)新研發(fā)的引擎。我們不得不為新的引擎重新打造車身,于是一輛新的賽車誕生了。但是,麻煩
的事接踵而來,國際汽聯(lián)頻頻修改規(guī)則,搞得設(shè)計(jì)師在“賽車”上改了又改,最終變得不成樣子,只能把它廢棄。

為了能夠重用這輛昂貴的賽車,工程師們提出了解決方案:首先,在車身的設(shè)計(jì)上預(yù)留出安裝引擎的位置和管線。然后,根據(jù)這些設(shè)計(jì)好的規(guī)范設(shè)計(jì)引擎(或是引擎的適配器)。于是,新的賽車設(shè)計(jì)方案就這樣誕生了。
?
顯然,通過重構(gòu),這里應(yīng)用的是一個(gè)典型的Bridge模式。這個(gè)實(shí)現(xiàn)的關(guān)鍵之處在于我們預(yù)先給引擎留出了位置!我們不必因?yàn)閷σ娴囊?guī)則的頻頻變更而制造相當(dāng)多的車身,而是盡可能地沿用和改良現(xiàn)有的車身。
說到這里,想說一說OO設(shè)計(jì)的一個(gè)誤區(qū)。
學(xué)
習(xí)OO語言的時(shí)候,為了能夠說明“繼承”(或者說“is-a”)這個(gè)概念,教科書上經(jīng)常用實(shí)際生活中的例子來解釋。比如汽車是車,電車是車,F(xiàn)1賽車是汽
車,所以車是汽車、電車、F1賽車的上層抽象。這個(gè)例子并沒有錯(cuò)。問題是,這樣的例子過于“形象”了!如果OO設(shè)計(jì)直接就可以將現(xiàn)實(shí)生活中的概念引用過
來,那也就不需要什么軟件工程師了!OO設(shè)計(jì)的關(guān)鍵概念是抽象。如果沒有抽象,那所有的軟件工程師的努力都是徒勞的。因?yàn)槿绻麤]有抽象,我們只能去構(gòu)造世
界中每一個(gè)對象。上面這個(gè)例子中,我們應(yīng)該看到“引擎”這個(gè)抽象的存在,因?yàn)檐囮?duì)的工程師們?yōu)樗A(yù)留了位置,為它制定了設(shè)計(jì)規(guī)范。
上面這個(gè)設(shè)計(jì)也
實(shí)現(xiàn)了后面要說的DIP(依賴倒置原則)。但是請記住,OCP是OO設(shè)計(jì)原則中高層次的原則,其余的原則對OCP提供了不同程度的支持。為了實(shí)現(xiàn)OCP,
我們會自覺或者不自覺地用到其它原則或是諸如Bridge、Decorator等設(shè)計(jì)模式。然而,對于一個(gè)應(yīng)用系統(tǒng)而言,實(shí)現(xiàn)OCP并不是設(shè)計(jì)目的,我們
所希望的只是一個(gè)穩(wěn)定的架構(gòu)。所以對OCP的追求也應(yīng)該適可而止,不要陷入過渡設(shè)計(jì)。正如Martin本人所說:“No significant
program can be 100% closed.”“Closure not complete but strategic”Liskov替換原則—— LSP?
子類型必須能夠替換它的基類型
原則
主要針對繼承的設(shè)計(jì)原則
所有派生類的行為功能必須和客戶程序?qū)ζ浠愃谕谋3忠恢隆?br />派生類必須滿足基類和客戶程序的約定
IS-A是關(guān)于行為方式的,依賴客戶程序的調(diào)用方式
?
重構(gòu)
Extract Supper Class
?
實(shí)例
依賴倒置原則—— DIP?
a:高層模塊不應(yīng)依賴于底層模塊,兩者都應(yīng)該依賴于抽象
b:抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象
?
原則
如何解釋倒置
高層依賴底層,重用變得困難,而最經(jīng)常重用的就是framework和各個(gè)獨(dú)立的功能組件
高層依賴底層,底層的改動直接反饋到高層,形成依賴的傳遞
面向接口的編程
?
實(shí)例
Ioc模式
DomainObject / DomianObjectDataService
?
接口隔離原則—— ISP?
使用多個(gè)專門的接口比使用單一的總接口總要好。換而言之,從一個(gè)客戶類的角度來講:一個(gè)類對另外一個(gè)類的依賴性應(yīng)當(dāng)是建立在最小接口上的。
原則過于臃腫的接口是對接口的污染。不應(yīng)該強(qiáng)迫客戶依賴于它們不用的方法。
My object-oriented umbrella(摘自Design Patterns Explained)
Let me tell you about my great umbrella. It is large enough to get
into! In fact, three or four other people can get in it with me. While
we are in it, staying out of the rain, I can move it from one place to
another. It has a stereo system to keep me entertained while I stay
dry. Amazingly enough, it can also condition the air to make it warmer
or colder. It is one cool umbrella.
My umbrella is convenient. It sits there waiting for me. It has
wheels on it so that I do not have to carry it around. I don't even
have to push it because it can propel itself. Sometimes, I will open
the top of my umbrella to let in the sun. (Why I am using my umbrella
when it is sunny outside is beyond me!)
In Seattle, there are hundreds of thousands of these umbrellas in all kinds of colors. Most people call them cars.
實(shí)現(xiàn)方法:
1、?使用委托分離接口
2、?使用多重繼承分離接口
想到一個(gè)朋友說的話:所有的接口都只有一個(gè)方法,具體的類根據(jù)自己需要什么方法去實(shí)現(xiàn)接口
posted @
2006-04-09 14:06 混沌中立 閱讀(589) |
評論 (0) |
編輯 收藏
工作了幾年,在不同的公司進(jìn)入了幾個(gè)不同的團(tuán)隊(duì).感覺團(tuán)隊(duì)之間的差異很大.
1.一個(gè)好的團(tuán)隊(duì),是需要時(shí)間來培養(yǎng)的.團(tuán)隊(duì)中的成員需要時(shí)間來互相熟悉,這個(gè)熟悉不單是平常說的認(rèn)識,還要包括熟悉其他的編程方式設(shè)計(jì)傾向,工作習(xí)慣.只有這樣以后,在討論問題討論方案的時(shí)候,可以形成默契,基本簡單幾句就會明白在說什么問題.團(tuán)隊(duì)也需要時(shí)間來形成團(tuán)隊(duì)的風(fēng)格,一個(gè)有團(tuán)隊(duì)所有成員的風(fēng)格組合在一起形成的風(fēng)格.包括文檔,編碼,設(shè)計(jì),溝通等方面上的一致風(fēng)格.中間需要不斷進(jìn)行review,按照review的結(jié)果,對所有成果物進(jìn)行修改.
2.一個(gè)好的團(tuán)隊(duì)的人員流動應(yīng)該是良性的.這個(gè)良性流動指的是有人員的變化,但是變化的數(shù)量和范圍不會使得團(tuán)隊(duì)的風(fēng)格發(fā)生大的變化,如果一個(gè)10人的團(tuán)隊(duì),突然發(fā)生的5人的變化,就是說調(diào)整到其他團(tuán)隊(duì)5個(gè)人,又調(diào)整進(jìn)來5個(gè)人,那對于這個(gè)團(tuán)隊(duì)基本可以算是重新形成一個(gè)新的團(tuán)隊(duì)了.
3.一個(gè)好的團(tuán)隊(duì),不單需要團(tuán)隊(duì)內(nèi)部成員的努力,同時(shí)也需要SPEG和QA在團(tuán)隊(duì)之外對團(tuán)隊(duì)的開發(fā)流程的監(jiān)督和規(guī)范.如果沒有了解開發(fā)流程和開發(fā)規(guī)范的SPEG對流程進(jìn)行監(jiān)督,即使團(tuán)隊(duì)形成了風(fēng)格,那這個(gè)風(fēng)格很有可能不是健康的風(fēng)格,可能會導(dǎo)致團(tuán)隊(duì)在以后的開發(fā)的過程中產(chǎn)生問題.
4.一個(gè)好的團(tuán)隊(duì),需要比較有控制力的PM,能力強(qiáng)的PSM,設(shè)計(jì)能力優(yōu)秀的SA.正因?yàn)橛羞@樣的人,才能快速的將加入團(tuán)隊(duì)的新成員,融入團(tuán)隊(duì).
好像具備了上面這些條件想不形成一個(gè)好的團(tuán)隊(duì)也是很不容易的事情了:)
posted @
2006-04-08 20:01 混沌中立 閱讀(1041) |
評論 (2) |
編輯 收藏
最近一直在想這個(gè)事情,從近幾年的web application的發(fā)展情況和工作項(xiàng)目的用戶需求來看,rich client應(yīng)該又要成為一個(gè)潮流了。
主要原因有兩點(diǎn):
一是網(wǎng)速的提高,過去使用browser是因?yàn)檫^去的網(wǎng)絡(luò)速度比較慢,所以只能給客戶端傳送很少的信息量,讓客戶通過網(wǎng)絡(luò)傳輸?shù)男畔⒈M可能少的完成操作。而現(xiàn)在網(wǎng)絡(luò)速度的提高,讓這樣的要求變少了,網(wǎng)速慢的這個(gè)瓶頸也不再存在了。
二是用戶的要求,用戶實(shí)際上不在意什么client還是brower,用戶在意的是使用是否方便,響應(yīng)是否迅速,能否滿足業(yè)務(wù)需要。如果網(wǎng)速慢,機(jī)器配置差的瓶頸在今天的技術(shù)條件下不存在了,用戶對于易用性和快速響應(yīng)的要求就要提高了。這個(gè)快速響應(yīng)不是指那種客戶端<----->服務(wù)器的響應(yīng),而已一個(gè)操作之后快速的出現(xiàn)結(jié)果,這個(gè)就要求有一部分在C/S模式下在客戶端實(shí)現(xiàn)的功能但是在B/S情況下被轉(zhuǎn)移到服務(wù)器上的一些功能需要在客戶端實(shí)現(xiàn)。
但是這個(gè)rich client不是幾年前的那種臃腫的不行的方式了,應(yīng)該是比現(xiàn)在的應(yīng)用的client包含的內(nèi)容多,但是比以前的client的內(nèi)容要少。主要解決的問題是,快速響應(yīng)用戶的操作,讓用戶的操作更簡單。
(思路不是很清晰,暫時(shí)是這樣,之后再修改)
posted @
2006-03-17 10:12 混沌中立 閱讀(268) |
評論 (0) |
編輯 收藏