參考資料https://gitee.com/mengning997/se
第一章、代碼中的軟件工程
軟件工程瀑布模型
需求分析:分析現(xiàn)有軟件,? 用你們寫的軟件的用戶量來證明你了解用戶的需求
設(shè)計階段:用快速發(fā)布來證明設(shè)計是有效的,? 能適應(yīng)變化的始赎。
實現(xiàn)階段:用各種軟件工程的衡量手段來證明大家實現(xiàn)的能力湖饱。
穩(wěn)定階段:證明測試能否覆蓋代碼的大部分啥纸。
發(fā)布階段: 如期發(fā)布, 用戶量,? 用戶評價简识。
維護(hù)階段:網(wǎng)上的觀眾或下一個年級的同學(xué)能很愿意接手你們的軟件冲秽。
第二章、必備技能
1畸冲、vscode
簡單使用
打開文件夾( Ctrl/?+O)和關(guān)閉文件夾工作區(qū)( Ctrl/?+K F)
新建文件(Ctrl/?+N)嫉髓、關(guān)閉文件(Ctrl/?+W)、編輯文件和保存文件(Ctrl/?+S)
文件內(nèi)搜索(Ctrl/?+F)
關(guān)閉所有文件(Ctrl/?+K W)
關(guān)閉已保存的文件(Ctrl/?+K U)
Ctrl+/用于單行代碼注釋和取消注釋邑闲,Ctrl+Shift+A用于代碼塊注釋和取消注釋
文件資源管理器(Ctrl/?+Shift+E)
跨文件搜索 (Ctrl+Shift+F)
源代碼管理 (Ctrl+Shift+G)
啟動和調(diào)試 (Ctrl/?+Shift+D)
管理擴展插件 (Ctrl/?+Shift+X)
顯示命令面板 (Ctrl/?+Shift+P)
顯示問題面板 (查看錯誤和警告)(Ctrl/?+Shift+M)
顯示集成終端 (Ctrl+`)
快捷鍵
2、Git
1梧油、git本地版本庫的基本用法
git init # 初始化一個本地版本庫
git status # 查看當(dāng)前工作區(qū)(workspace)的狀態(tài)
git add [FILES] # 把文件添加到暫存區(qū)(Index)
git commit -m "wrote a commit log infro” # 把暫存區(qū)里的文件提交到倉庫
git log # 查看當(dāng)前HEAD之前的提交記錄苫耸,便于回到過去
git reset —hard HEAD^^/HEAD~100/commit-id/commit-id的頭幾個字符 # 回退
git reflog # 可以查看當(dāng)前HEAD之后的提交記錄,便于回到未來
git reset —hard commit-id/commit-id的頭幾個字符 # 回退
要是在本地對源代碼進(jìn)行基本的版本控制儡陨,主要通過git add和git commit -m提交版本褪子,有了提交記錄之后可以靈活地將當(dāng)前工作區(qū)里的源代碼回退到過去的某個版本,也就是回到過去骗村∠油剩回到過去之后,也有可能發(fā)現(xiàn)之前撤銷的某個版本是有價值的胚股,希望找回來笼痛,這就需要回到未來。過去和未來之間的分界點就是HEAD琅拌,即當(dāng)前工作區(qū)所依賴的版本缨伊。
2、git遠(yuǎn)程版本庫的基本用法
git clone命令官方的解釋是“Clone a repository into a new directory”进宝,即克隆一個存儲庫到一個新的目錄下刻坊。
git fetch命令官方的解釋是“Download objects and refs from another repository”,即下載一個遠(yuǎn)程存儲庫數(shù)據(jù)對象等信息到本地存儲庫党晋。
git push命令官方的解釋是“Update remote refs along with associated objects”谭胚,即將本地存儲庫的相關(guān)數(shù)據(jù)對象更新到遠(yuǎn)程存儲庫。
git merge命令官方的解釋是“Join two or more development histories together”未玻,即合并兩個或多個開發(fā)歷史記錄灾而。
git pull命令官方的解釋是“Fetch from and integrate with another repository or a local branch”,即從其他存儲庫或分支抓取并合并到當(dāng)前存儲庫的當(dāng)前分支深胳。
3绰疤、git的設(shè)計理念和時間線
line diff是形成增量補丁的技術(shù)方法,即一個文件按行對比(line diff)將差異的部分制作成一個增量補丁舞终。
commit是存儲到倉庫里的一個版本轻庆,是整個項目范圍內(nèi)的一個或多個文件的增量補丁合并起來癣猾,形成項目的增量補丁,是一次提交記錄余爆。每個提交(commit)都生成一個唯一的commit ID纷宇。
branch是按時間線依次排列的一組提交記錄(commit),理論上可以通過當(dāng)前branch上最初的提交(commit)依次打補丁直到HEAD得到當(dāng)前工作區(qū)里的源代碼蛾方。
tag標(biāo)簽就是某次提交(commit)的commit ID的別名
4像捶、團(tuán)隊的分叉與合并
建議團(tuán)隊項目的每一個開發(fā)者都采用的工作流程大致如下:
1 克隆或同步最新的代碼到本地存儲庫;
2 為自己的工作創(chuàng)建一個分支桩砰,該分支應(yīng)該只負(fù)責(zé)單一功能模塊或代碼模塊的版本控制拓春;
3 在該分支上完成某單一功能模塊或代碼模塊的開發(fā)工作;
4 最后亚隅,將該分支合并到主分支硼莽。
5、合并方法
默認(rèn)的合并方式為"快進(jìn)式合并"(fast-farward merge)煮纵,會將分支里commit合并到主分支里懂鸵,合并成一條時間線,與我們期望的呈現(xiàn)為一段獨立的分支線段不符行疏,因此合并時需要使用--no-ff參數(shù)關(guān)閉"快進(jìn)式合并"(fast-farward merge)匆光。
一、克隆或同步最新的代碼到本地存儲庫
git clonehttps://DOMAIN_NAME/YOUR_NAME/REPO_NAME.git
git pull
二酿联、為自己的工作創(chuàng)建一個分支终息,該分支應(yīng)該只負(fù)責(zé)單一功能模塊或代碼模塊的版本控制;
git checkout -b mybranch
git branch
三货葬、在該分支上完成某單一功能模塊或代碼模塊的開發(fā)工作采幌;多次進(jìn)行如下操作:
git add FILES
git commit -m "commit log"
四、最后震桶,先切換回master分支休傍,將遠(yuǎn)程origin/master同步最新到本地存儲庫,再合并mybranch到master分支蹲姐,推送到遠(yuǎn)程origin/master之后即完成了一項開發(fā)工作磨取。
git checkout master
git pull
git merge --no-ff mybranch
git push
6、Git Rebase
一般我們在軟件開發(fā)的流程中柴墩,有一個樸素的版本管理哲學(xué):開發(fā)者的提交要盡量干凈忙厌、簡單。開發(fā)者要把自己的代碼修改按照功能拆分成一個個相對獨立的提交江咳,一個提交對應(yīng)一個功能點逢净,而且要在對應(yīng)的 commit log message 里面描述清楚。因此在合并和 push 之前檢查修改一下 commit 記錄時常需要。
團(tuán)隊項目工作流程中增加一步Git Rebase爹土,即在mybranch分支上完成自己的工作之后甥雕,為了讓 log 記錄將來更容易回顧參考,用 git rebase 重新整理一下提交記錄胀茵。注意不要通過rebase對任何已經(jīng)提交到遠(yuǎn)程倉庫中的commit進(jìn)行修改社露。
git rebase命令格式大致如下:
git rebase -i [startpoint] [endpoint]
其中-i的意思是--interactive,即彈出交互式的界面讓用戶編輯完成合并操作琼娘,[startpoint] [endpoint]則指定了一個編輯區(qū)間峭弟,如果不指定[endpoint],則該區(qū)間的終點默認(rèn)是當(dāng)前分支的HEAD脱拼。
一般只指定[startpoint] 瞒瘸,即指定從某一個commit節(jié)點開始,可以使用HEAD^^熄浓、HEAD~100挨务、commit ID或者commit ID的頭幾個字符來指定一個commit節(jié)點,比如下面的代碼指定重新整理HEAD之前的三個commit節(jié)點玉组。
$ git rebase -i HEAD^^^
git rebase —abort
git rebase --continue
7、Fork + Pull request
為了解決開源社區(qū)松散團(tuán)隊的協(xié)作問題丁侄,Github提供了Fork+ Pull request的協(xié)作開發(fā)工作流程惯雳。
當(dāng)你想更正別人倉庫里的Bug或者向別人倉庫里貢獻(xiàn)代碼時,要走Fork+ Pull request的協(xié)作開發(fā)工作流程:
1 先 fork(分叉) 別人的倉庫鸿摇,相當(dāng)于拷貝一份石景;
2 做一些 bug fix或其他的代碼貢獻(xiàn);
3 發(fā)起 Pull request 給原倉庫拙吉;
4 原倉庫的所有者 review Pull request潮孽,如果沒有問題的話,就會 merge Pull request 到原倉庫中筷黔。
3往史、Vim
1、安裝Vim
It is included as "vi" with most UNIX systems and with Apple OS X.
使用VSCode則可以在Linux佛舱、Windows和OS X上都能使用Vim
在VSCode中Ctrl/?+Shift+X管理擴展插件中搜索vim即可安裝使用
命令模式(Command mode)椎例,用戶剛剛啟動vi/vim,便進(jìn)入了命令模式请祖。此狀態(tài)下敲擊鍵盤動作會被vim識別為命令订歪,而非輸入字符。比如我們此時按下i肆捕,并不會輸入一個字符刷晋,i被當(dāng)作了一個命令。命令模式只有一些最基本的命令,因此仍要依靠底線命令模式輸入更多命令
輸入模式(Insert mode)眼虱,在命令模式下按下i就進(jìn)入了輸入模式喻奥,按ESC退出輸入模式,切換到命令模式蒙幻。
底線命令模式(Last line mode)映凳,在命令模式下按下:(英文冒號)就進(jìn)入了底線命令模式。底線命令模式可以輸入單個或多個字符的命令邮破,可用的命令非常多诈豌。基本的命令有q(退出程序)抒和、w(保存文件)等矫渔。按ESC鍵可隨時退出底線命令模式。
2摧莽、三種模式之間的切換
?命令模式(Command mode)庙洼,用戶剛剛啟動vi/vim,便進(jìn)入了命令模式镊辕。此狀態(tài)下敲擊鍵盤動作會被vim識別為命令油够,而非輸入字符。比如我們此時按下i征懈,并不會輸入一個字符石咬,i被當(dāng)作了一個命令。命令模式只有一些最基本的命令卖哎,因此仍要依靠底線命令模式輸入更多命令
?輸入模式(Insert mode)鬼悠,在命令模式下按下i就進(jìn)入了輸入模式,按ESC退出輸入模式亏娜,切換到命令模式焕窝。
?底線命令模式(Last line mode),在命令模式下按下:(英文冒號)就進(jìn)入了底線命令模式维贺。底線命令模式可以輸入單個或多個字符的命令它掂,可用的命令非常多⌒衣疲基本的命令有q(退出程序)群发、w(保存文件)等。按ESC鍵可隨時退出底線命令模式发乔。
3熟妓、移動光標(biāo)的基本方法
h 或 向左箭頭鍵(←) 光標(biāo)向左移動一個字符
j 或 向下箭頭鍵(↓) 光標(biāo)向下移動一個字符
k 或 向上箭頭鍵(↑) 光標(biāo)向上移動一個字符
l 或 向右箭頭鍵(→) 光標(biāo)向右移動一個字符
如果你將右手放在鍵盤上的話,你會發(fā)現(xiàn) hjkl 是排列在一起的栏尚,因此可以使用這四個按鈕來移動光標(biāo)起愈。 如果想要進(jìn)行多次移動的話,例如向下移動 30 行,可以使用 "30j" 或 "30↓" 的組合按鍵抬虽, 亦即加上想要進(jìn)行的次數(shù)(數(shù)字)后官觅,按下動作即可!
4阐污、移動光標(biāo)的更多方法
n 那個 n 表示『數(shù)字』休涤,例如 20 。按下數(shù)字后再按空格鍵笛辟,光標(biāo)會向右移動這一行的 n 個字符功氨。例如 20 則光標(biāo)會向后面移動 20 個字符距離。
0 或功能鍵[Home] 這是數(shù)字『 0 』:移動到這一行的最前面字符處 (常用)
$ 或功能鍵[End] 移動到這一行的最后面字符處(常用)
H 光標(biāo)移動到這個屏幕的最上方那一行的第一個字符
M 光標(biāo)移動到這個屏幕的中央那一行的第一個字符
L 光標(biāo)移動到這個屏幕的最下方那一行的第一個字符
G 移動到這個檔案的最后一行(常用)
nG n為數(shù)字手幢。移動到這個檔案的第 n 行捷凄。例如 20G 則會移動到這個檔案的第 20 行
gg 移動到這個檔案的第一行,相當(dāng)于 1G 拔Ю础跺涤! (常用)
n n 為數(shù)字。光標(biāo)向下移動 n 行(常用)
5监透、刪除
x, X 在一行字當(dāng)中桶错,x 為向后刪除一個字符 (相當(dāng)于 [del] 按鍵), X 為向前刪除一個字符(相當(dāng)于 [backspace] 亦即是退格鍵) (常用)
nx n 為數(shù)字胀蛮,連續(xù)向后刪除 n 個字符牛曹。舉例來說,我要連續(xù)刪除 10 個字符醇滥, 『10x』。
dd 刪除游標(biāo)所在的那一整行(常用)
ndd n 為數(shù)字超营。刪除光標(biāo)所在的向下 n 行鸳玩,例如 20dd 則是刪除 20 行 (常用)
d1G 刪除光標(biāo)所在到第一行的所有數(shù)據(jù)
dG 刪除光標(biāo)所在到最后一行的所有數(shù)據(jù)
d$ 刪除游標(biāo)所在處,到該行的最后一個字符
d0 那個是數(shù)字的0 演闭,刪除游標(biāo)所在處不跟,到該行的最前面一個字符
6、復(fù)制與粘貼
yy 復(fù)制游標(biāo)所在的那一行(常用)
p, P p為將已復(fù)制的數(shù)據(jù)在光標(biāo)下一行貼上米碰,P則為貼在游標(biāo)上一行窝革! 舉例來說,我目前光標(biāo)在第 20 行吕座,且已經(jīng)復(fù)制了 10 行數(shù)據(jù)虐译。則按下 p 后, 那 10 行數(shù)據(jù)會貼在原本的 20 行之后吴趴,亦即由 21 行開始貼漆诽。但如果是按下 P 呢? 那么原本的第 20 行會被推到變成 30 行。 (常用)
nyy n 為數(shù)字厢拭。復(fù)制光標(biāo)所在的向下 n 行兰英,例如 20yy 則是復(fù)制 20 行(常用)
y1G 復(fù)制游標(biāo)所在行到第一行的所有數(shù)據(jù)
yG 復(fù)制游標(biāo)所在行到最后一行的所有數(shù)據(jù)
y0 復(fù)制光標(biāo)所在的那個字符到該行行首的所有數(shù)據(jù)
y$ 復(fù)制光標(biāo)所在的那個字符到該行行尾的所有數(shù)據(jù)
7、復(fù)原和重做
u 復(fù)原前一個動作供鸠。(常用)
[Ctrl]+r 重做上一個動作畦贸。(常用)
這個 u 與 [Ctrl]+r 是很常用的指令!一個是復(fù)原楞捂,另一個則是重做一次
8薄坏、自動化執(zhí)行宏命令
J 將光標(biāo)所在行與下一行的數(shù)據(jù)結(jié)合成同一行,2Jj則把下面的2行合并為一行并將光標(biāo)下移一行
在normal mode下q[a-z]開始錄制宏命令泡一,再次按q結(jié)束宏命令定義颤殴。
qa2Jjq,q-開始錄制宏鼻忠;a-宏的編號是a涵但,最后一個q-結(jié)束宏定義
3@a,執(zhí)行三次a宏
9帖蔓、基本搜索
/word 向光標(biāo)之下尋找一個名稱為 word 的字符串矮瘟。例如要在檔案內(nèi)搜尋 vbird 這個字符串,就輸入 /vbird 即可塑娇! (常用)
?word 向光標(biāo)之上尋找一個字符串名稱為 word 的字符串澈侠。
n 這個 n 是英文按鍵。代表重復(fù)前一個搜尋的動作埋酬。舉例來說哨啃, 如果剛剛我們執(zhí)行 /vbird 去向下搜尋 vbird 這個字符串,則按下 n 后写妥,會向下繼續(xù)搜尋下一個名稱為 vbird 的字符串拳球。如果是執(zhí)行 ?vbird 的話,那么按下 n 則會向上繼續(xù)搜尋名稱為 vbird 的字符串珍特!
N 這個 N 是英文按鍵祝峻。與 n 剛好相反,為『反向』進(jìn)行前一個搜尋動作扎筒。 例如 /vbird 后莱找,按下 N 則表示『向上』搜尋 vbird 。
使用 /word 配合 n 及 N 是非常有幫助的嗜桌!可以讓你重復(fù)的找到一些你搜尋的關(guān)鍵詞奥溺!
10、基本搜索替換
:n1,n2s/word1/word2/g n1 與 n2 為數(shù)字骨宠。在第 n1 與 n2 行之間尋找 word1 這個字符串谚赎,并將該字符串取代為 word2 淫僻!舉例來說,在 100 到 200 行之間搜尋 vbird 并取代為 VBIRD 則:『:100,200s/vbird/VBIRD/g』壶唤。(常用)
s是substitute的簡寫雳灵,表示執(zhí)行替換字符串操作
g(global)表示全局替換;c(comfirm)表示操作時需要確認(rèn);i(ignorecase)表示不區(qū)分大小寫
:1,s/word1/word2/g 或 :%s/word1/word2/g 從第一行到最后一行尋找 word1 字符串,并將該字符串取代為 word2 闸盔!(常用)
:1,s/word1/word2/gc 或 :%s/word1/word2/gc 從第一行到最后一行尋找 word1 字符串悯辙,并將該字符串取代為 word2 !且在取代前顯示提示字符給用戶確認(rèn) (confirm) 是否需要取代迎吵!(常用)
11躲撰、切換到編輯模式
i, I 進(jìn)入輸入模式(Insert mode):
i 為『從目前光標(biāo)所在處輸入』, I 為『在目前所在行的第一個非空格符處開始輸入』击费。 (常用)
a, A 進(jìn)入輸入模式(Insert mode):
a 為『從目前光標(biāo)所在的下一個字符處開始輸入』拢蛋, A 為『從光標(biāo)所在行的最后一個字符處開始輸入』。(常用)
o, O 進(jìn)入輸入模式(Insert mode):
這是英文字母 o 的大小寫蔫巩。o 為『在目前光標(biāo)所在的下一行處輸入新的一行』谆棱; O 為在目前光標(biāo)所在處的上一行輸入新的一行!(常用)
r, R 進(jìn)入取代模式(Replace mode):
r 只會取代光標(biāo)所在的那一個字符一次圆仔;R會一直取代光標(biāo)所在的文字垃瞧,直到按下 ESC 為止;(常用)
[Esc] 退出編輯模式坪郭,回到一般模式中(常用)
編輯模式在vi畫面的左下角處會出現(xiàn)『--INSERT--』或『--REPLACE--』的字樣
12个从、命令行模式
:w 將編輯的數(shù)據(jù)寫入硬盤檔案中(常用)
:w! 若文件屬性為『只讀』時,強制寫入該檔案歪沃。不過丐巫,到底能不能寫入捅伤, 還是跟你對該檔案的檔案權(quán)限有關(guān)扮凸恰裆甩!
:w [filename] 將編輯的數(shù)據(jù)儲存成另一個檔案(類似另存新檔)
:q 離開 vi (常用)
:q! 若曾修改過檔案司训,又不想儲存剖效,使用 ! 為強制離開不儲存檔案远寸。
注意一下啊覆糟,那個驚嘆號 (!) 在 vi 當(dāng)中外驱,常常具有『強制』的意思~
:wq 儲存后離開育灸,若為 :wq! 則為強制儲存后離開 (常用)
13、代碼中批量添加注釋
批量注釋:Ctrl + v 進(jìn)入塊選擇模式昵宇,然后移動光標(biāo)選中你要注釋的行(VSCode可以鼠標(biāo)選擇代碼塊)磅崭,再按大寫的 I 進(jìn)入行首插入模式輸入注釋符號如 // 或 #,輸入完畢之后瓦哎,按兩下 ESC砸喻,Vim 會自動將你選中的所有行首都加上注釋柔逼,保存退出完成注釋。
取消注釋:Ctrl + v 進(jìn)入塊選擇模式割岛,選中你要刪除的行首的注釋符號愉适,注意 // 要選中兩個,選好之后按 d 即可刪除注釋癣漆,ESC 保存退出维咸。
批量注釋:使用下面命令在指定的行首添加注釋。使用命令格式: :起始行號,結(jié)束行號s/^/注釋符/g(注意冒號)惠爽,如:10,20s#^#//#g癌蓖,:10,20s/^/#/g
取消注釋:使用名命令格式: :起始行號,結(jié)束行號s/^注釋符//g(注意冒號),如:10,20s#^//##g婚肆,:10,20s/#//g
14租副、命令行環(huán)境下vim的配置
:set nu 顯示行號,設(shè)定之后较性,會在每一行的前綴顯示該行的行號
:set nonu 與 set nu 相反用僧,為取消行號!
4两残、正則
1永毅、基本概念
正則表達(dá)式是對字符串操作的一種邏輯公式。
正則表達(dá)式的應(yīng)用范圍非常之廣泛人弓,最初是由Unix普及開來的沼死,后來在廣泛運用于Scala 、PHP崔赌、C# 意蛀、Java、C++ 健芭、 Objective-c县钥、Perl 、Swift慈迈、VBScript 若贮、Javascript、Ruby 以及Python等等
使用正則表達(dá)式的原因
測試字符串內(nèi)的模式痒留。例如谴麦,可以測試輸入字符串,以查看字符串內(nèi)是否出現(xiàn)電話號碼模式或信用卡號碼模式伸头。這稱為數(shù)據(jù)驗證匾效。
替換文本⌒袅祝可以使用正則表達(dá)式來識別文檔中的特定文本面哼,完全刪除該文本或者用其他文本替換它野宜。
基于模式匹配從字符串中提取子字符串∧Р撸可以查找文檔內(nèi)或輸入域內(nèi)特定的文本匈子。
例如,您可能需要搜索整個網(wǎng)站代乃,刪除過時的材料旬牲,以及替換某些 HTML 格式標(biāo)記。在這種情況下搁吓,可以使用正則表達(dá)式來確定在每個文件中是否出現(xiàn)該材料或該 HTML 格式標(biāo)記原茅。此過程將受影響的文件列表縮小到包含需要刪除或更改的材料的那些文件。然后可以使用正則表達(dá)式來刪除過時的材料堕仔。最后擂橘,可以使用正則表達(dá)式來搜索和替換標(biāo)記。
2摩骨、基本的字符串搜索方法
在VS Code中跨文件搜索(Ctrl+Shift+F)和文件內(nèi)搜索(Ctrl+F)的輸入框輸入字符串即可進(jìn)行基本的字符串搜索通贞。
文件內(nèi)搜索(Ctrl+F)可以使用Enter鍵代表繼續(xù)搜索下一個,Shift+Enter鍵代表繼續(xù)搜索上一個恼五。這兩個操作在文件內(nèi)搜索面板上有對應(yīng)的兩個上下箭頭昌罩,箭頭右側(cè)三條橫線的小按鈕是指在選定內(nèi)容中查找(Alt+L)≡致跨文件搜索(Ctrl+Shift+F)和文件內(nèi)搜索(Ctrl+F)的輸入框內(nèi)部右側(cè)都有三個小按鈕:
第一個選中的話就是搜索時區(qū)分大小寫(Alt+C)茎用;
第二個選中的話表示搜索時全字匹配(Alt+W);
第三個選中的話表示搜索時采用正則表達(dá)式(Alt+R)睬罗,如果輸入框中使用了正則表達(dá)式的語法規(guī)則轨功,則需要選中第三個按鈕或使用Alt+R快捷鍵。顯然上圖中還沒有使用正則表達(dá)式容达。
在 Vim 一般命令模式(Normal Mode)下輸入/word 向光標(biāo)之下尋找一個名稱為 word 的字符串古涧。例如要在檔案內(nèi)搜尋 vbird 這個字符串,就輸入 /vbird 即可花盐! (常用)
?word 向光標(biāo)之上尋找一個字符串名稱為 word 的字符串羡滑。
n 這個 n 是英文按鍵。代表重復(fù)前一個搜尋的動作算芯。舉例來說柒昏, 如果剛剛我們執(zhí)行 /vbird 去向下搜尋 vbird 這個字符串,則按下 n 后也祠,會向下繼續(xù)搜尋下一個名稱為 vbird 的字符串。如果是執(zhí)行 ?vbird 的話近速,那么按下 n 則會向上繼續(xù)搜尋名稱為 vbird 的字符串诈嘿!
N 這個 N 是英文按鍵堪旧。與 n 剛好相反,為『反向』進(jìn)行前一個搜尋動作奖亚。 例如 /vbird 后淳梦,按下 N 則表示『向上』搜尋 vbird 。
使用 /word 配合 n 及 N 是非常有幫助的昔字!可以讓你重復(fù)的找到一些你搜尋的關(guān)鍵詞
3爆袍、同時搜索多個字符串的方法
在VS Code跨文件搜索(Ctrl+Shift+F)或文件內(nèi)搜索(Ctrl+F)時,只要將多個字符串之間增加或運算符“|”作郭,比如"main|int" 陨囊,同時選中輸入框最右側(cè)使用正則表達(dá)式(Alt+R)的小圖標(biāo),即可同時搜索多個字符串夹攒。
在 Vim 中搜索多個字符串的用法基本一致蜘醋。如果你想匹配"yes"或"no",你需要的正則表達(dá)式是/yes|no
你也可以搜索超過兩種模式咏尝,通過添加更多的模式來添加更多的或運算符來分隔它們压语,如/yes|no|maybe
4、在匹配字符串時的大小寫問題
在VS Code跨文件搜索(Ctrl+Shift+F)和文件內(nèi)搜索(Ctrl+F)中编检,默認(rèn)是忽略大小寫的胎食,只有通過選中搜索輸入框中區(qū)分大小寫(Alt+C)小按鈕,才會按照字符串的大小寫嚴(yán)格匹配允懂。
在 Vim 中通過底線命令方式:set ignorecase 設(shè)置為忽略大小寫厕怜;通過:set noignorecase 恢復(fù)到大小寫敏感的狀態(tài),Vim 環(huán)境下默認(rèn)是大小寫敏感的累驮。
Unix類的系統(tǒng)默認(rèn)都是大小寫敏感的酣倾,而Windows系統(tǒng)下默認(rèn)是大小寫不敏感的。這大概是VS Code和Vim在大小寫的默認(rèn)設(shè)置上不同的原因吧谤专。
在 Vim 中也可以通過快捷方式\c 表示大小寫不敏感躁锡,\C 表示大小寫敏感,比如/ignorecase\c置侍,這個正則表達(dá)式可以匹配”ignorecase”映之,"igNoreCase"和"IgnoreCase"。
在VS Code跨文件搜索(Ctrl+Shift+F)和文件內(nèi)搜索(Ctrl+F)中不支持在正則表達(dá)式中使用\c這種快捷方式
5蜡坊、通配符的基本用法
通配符“.”將匹配任意一個字符杠输。通配符也可稱為 dot 和 period。你可以像正則表達(dá)式中的任何其他字符一樣使用通配符秕衙。例如蠢甲,如果你想匹配“hug”,“huh”据忘,“hut”和“hum”鹦牛,可以使用正則表達(dá)式hu.來匹配這所有四個字符串搞糕。
通配符“+”用來查找出現(xiàn)一次或多次的字符,例如hahhhhh曼追,可以使用正則表達(dá)式hah+來匹配窍仰。
通配符“* ”匹配零次或多次出現(xiàn)的字符,使用正則表達(dá)式hah*來匹配礼殊,還可以匹配ha字符串驹吮。
通配符“?”指定可能存在的元素,也就是檢查前一個元素存在與否晶伦,如正則表達(dá)式colou?r碟狞、favou?rite中通配符“?”前面的u字符存在和不存在兩種情況的字符串都會匹配。
簡要總結(jié)一下通配符“.”表示任意一個字符坝辫;“?”表示前一個字符是否存在篷就,也就是存在 0 次或 1 次;“+”表示前一個字符出現(xiàn)一次或多次近忙;“*”表示前一個字符出現(xiàn) 0 次竭业、1 次或多次。
如果是指定只查找某個字符出現(xiàn)3次到5次的情況怎么辦呢及舍?可以使用 quantity specifiers 數(shù)量說明符指定模式的下限和上限數(shù)未辆。數(shù)量說明符使用大括號{and}。你將兩個數(shù)字放在大括號之間用逗號“,”隔開表示上限和下限數(shù)锯玛。
要匹配字符串"aaah"中出現(xiàn) 3 到 5 次的 a咐柜,你的正則表達(dá)式將是a{3,5}h;
僅匹配字符串"haaah"與至少出現(xiàn) 3 次的字母 a攘残,正則表達(dá)式將是/ha{3,}h拙友;
為了僅匹配"hah"中出現(xiàn) 3 次的字母 a,你的正則表達(dá)式將是/ha{3}h歼郭。
6遗契、匹配具有多種可能性的字符集
[]
方括號[and]中來定義一組你希望匹配的字符。character sets 字符集允許你通過將其放在方括號[and]中來定義一組你希望匹配的字符病曾。例如牍蜂,你要匹配"bag","big"和"bug"泰涂,而不是"bog"鲫竞。你可以創(chuàng)建正則表達(dá)式/b[aiu]g 來執(zhí)行此操作。[aiu]是只匹配字符"a","i"或"u"的 character sets 字符集逼蒙。
[ - ]
在 character sets 字符集中从绘,你可以使用連字符“-”定義要匹配的字符范圍。例如,要匹配小寫字母 a 到 e僵井,你將使用[a-e]赁还。使用連字符“-”匹配一系列字符并不只限于字母,它也可以匹配一系列數(shù)字驹沿。例如character sets 字符集[0-5]匹配 0 和 5 之間的所有數(shù)字,包括 0 和 5蹈胡。
字符“^”定義不想要匹配的字符渊季,稱為negated character sets 否定字符集。要創(chuàng)建一個 否定字符集罚渐,你可以在方括號的開括號之后放置一個插入字符“^”却汉。例如[^aeiou]排除元音的所有字符。
如果匹配的可能的字符太多荷并,寫起來不是很方便合砂,因而字符集還提供快捷方式的寫法。
快捷方式\w 匹配字母數(shù)字[A-Za-z0-9_ ]源织。這個character sets 字符集匹配大小寫字母加數(shù)字翩伪。注意,這個character sets 字符集還包括下劃線字符“_”谈息。
快捷方式\W 搜索\w 的相反方向缘屹。需要注意相反的模式使用大寫字母。此快捷方式與 [^A-Za-z0-9_]相同侠仇。
快捷方式\d 搜索數(shù)字字符集[0-9]轻姿。
快捷方式\D查找非數(shù)字字符,等于字符集[^0-9]逻炊。
7互亮、貪婪匹配 默認(rèn) vs. 懶惰匹配 ?
在正則表達(dá)式中,greedy 貪婪匹配找到符合正則表達(dá)式模式的字符串的最長可能部分余素,并將其作為匹配返回豹休。相反還有 lazy 懶惰匹配,是找到符合正則表達(dá)式模式的字符串的最小可能部分溺森。你可以將正則表達(dá)式t[a-z]i應(yīng)用于字符串"titanic"慕爬。這個正則表達(dá)式基本上是以 t 開始的模式,以 i 結(jié)尾屏积,并且之間有0個医窿、1個或多個字母。
正則表達(dá)式是默認(rèn)的是 greedy 貪婪匹配炊林,所以匹配將返回"titani"姥卢。它可以找到最大的子字符串,以符合該模式。
但是可以使用?字符將其更改為 lazy 懶惰匹配独榴∩妫“titanic”匹配調(diào)整后的t[a-z]?i正則表達(dá)式會返回["ti"]。注意這時字符“?”表示 lazy 懶惰匹配棺榔,字符“?”還可以作為通配符表示檢查前一個元素存在與否瓶堕。
8、一些特殊位置和特殊字符
插入字符“^”用于表示字符串的開頭症歇。
美元字符“$”表示字符串的末尾郎笆。
如在"Ricky is first and can be found”查找開頭的 Ricky 則為^Ricky,查找結(jié)尾的 found 則為/found$忘晤。
可以使用\s 搜索空格宛蚓,這是一個小寫的 s 即 space 之意。此模式不僅匹配空格设塔,還包括回車凄吏、制表符、換頁和新行字符闰蛔。你可以將其看作與字符集[\r\t\f\n\v]類似痕钢。
使用\S 搜索非空格,這是一個大寫的 S序六。此模式將不匹配空格盖喷、回車符、制表符难咕、換頁和新行字符课梳。你可以想象它類似于字符類[^\r\t\f\n\v]。
\n:換行(光標(biāo)到下行行首)余佃;
\r:回車(光標(biāo)到本行行首)暮刃;
\f:換頁;
\t:水平跳格(水平制表)爆土;
\v:垂直跳格(垂直制表)椭懊。
9、使用捕獲組復(fù)用模式
可能搜索的某些模式在字符串中多次出現(xiàn)步势,手動重復(fù)這些正則表達(dá)式是浪費時間的氧猬。有一個更好的方法可在你的字符串中有多個重復(fù)子串時進(jìn)行指定,那就是capture groups 捕獲組坏瘩。
用括號(and)可以定義capture groups 捕獲組盅抚,用于查找重復(fù)的子串,即把會重復(fù)的模式的正則表達(dá)式放在括號內(nèi)倔矾。
要指定重復(fù)字符串的出現(xiàn)位置妄均,可以使用反斜杠“\”柱锹,然后使用數(shù)字。該數(shù)字從 1 開始丰包,并隨著用括號定義的捕獲組數(shù)量而增加禁熏。比如\1 來匹配前面通過括號定義的第一個捕獲組。
使用 capture groups 捕獲組來匹配字符串中連續(xù)出現(xiàn)三次的數(shù)字邑彪,每個數(shù)字由空格分隔瞧毙,如(\d+)\s\1\s\1。
10寄症、基本的字符串搜索替換方法
在VS Code中基本的字符串搜索替換方法比較簡單升筏,只要點擊查找輸入框左側(cè)的“>”小按鈕就可以打開替換輸入框,如下圖所示瘸爽。也可以使用快捷鍵跨文件替換(Ctrl+Shift+H)和文件內(nèi)替換(Ctrl+H),與跨文件搜索(Ctrl+Shift+F)和文件內(nèi)搜索(Ctrl+F)相對應(yīng)铅忿。
在 Vim 中基本的字符串搜索替換方法為:n1,n2s/word1/word2/g剪决,以:開頭,n1 與 n2 為數(shù)字檀训,即在第 n1 與 n2 行之間尋找 word1 這個字符串柑潦,并將該字符串取代為 word2 字符串。舉例來說峻凫,在 100 到 200 行之間搜尋 regex 并取代為 RegEx 則為:100,200s/regex/RegEx/g渗鬼。
其中 s 是 substitute 的簡寫,表示執(zhí)行替換字符串操作荧琼;最后的/g 是 global 的簡寫譬胎,表示全局替換。另外與/g 的用法相似命锄,/c 是 comfirm 的簡寫堰乔,表示操作時需要確認(rèn);/i 是 ignorecase 的簡寫,表示不區(qū)分大小寫脐恩。
:1,$s/word1/word2/g 或 :%s/word1/word2/g 從第一行到最后一行尋找 word1 字符串镐侯,并將該字符串取代為 word2 字符串。
:1,$s/word1/word2/gc 或 :%s/word1/word2/gc 從第一行到最后一行尋找 word1 字符串驶冒,并將該字符串取代為 word2 字符串苟翻,且在取代前顯示提示信息給用戶確認(rèn) (confirm) 是否需要取代。
11骗污、復(fù)用捕獲組的方式進(jìn)行替換
如果我們在搜索替換中希望保留搜索字符串中的某些字符串作為替換字符串的一部分崇猫,可以使用美元符號$訪問替換字符串中的捕獲組。
比如在搜索正則表達(dá)式中的捕獲組為(capture groups)需忿,則替換的正則表達(dá)式中可以直接使用$1復(fù)用搜索正則表達(dá)式中的捕獲組為(capture groups)邓尤。
在VS Code中,如果想將項目中所有的HTML標(biāo)題標(biāo)簽中h改為大寫H,搜索正則表達(dá)式<h(\d)>可以查找出所有標(biāo)題標(biāo)簽汞扎。
替換的正則表達(dá)式<H1>使用1復(fù)用了搜索正則表達(dá)式中定義的捕獲組(\d)季稳。
在Vim中,復(fù)用捕獲組的方式進(jìn)行替換的用法為:1,s/(capture groups)/1/g
如果想在當(dāng)前文件中將所有的HTML標(biāo)題標(biāo)簽中h改為大寫H則正則表達(dá)式為:
1,$s/<h(\d)>/<H$1>/g
第三章澈魄、從需求分析到軟件設(shè)計
需求分析就是需求分析師對用戶期望的軟件行為進(jìn)行表述景鼠,并進(jìn)一步用對象或?qū)嶓w的狀態(tài)、屬性和行為來定義需求痹扇。
1.對需求進(jìn)行分析和建模
原型化方法(Prototyping)和建模的方法(Modeling)
用例建模(Use Case Modeling)
面向?qū)ο蠓治錾婕暗幕靖拍?/b>
業(yè)務(wù)領(lǐng)域建模(Domain Modeling)
關(guān)聯(lián)類及關(guān)系數(shù)據(jù)模型
關(guān)系數(shù)據(jù)模型的MongoDB設(shè)計與實現(xiàn)
需求分析的兩類基本方法
原型化方法(Prototyping)和建模的方法(Modeling)是整理需求的兩類基本方法铛漓。
原型化方法可以很好地整理出用戶接口方式(UI,User Interface)鲫构,比如界面布局和交互操作過程浓恶。
建模的方法可以快速給出有關(guān)事件發(fā)生順序或活動同步約束的問題,能夠在邏輯上形成模型來整頓繁雜的需求細(xì)節(jié)结笨。
用例
用例(Use Case)的核心概念中首先它是一個業(yè)務(wù)過程(business process)包晰,經(jīng)過邏輯整理抽象出來的一個業(yè)務(wù)過程,這是用例的實質(zhì)炕吸。什么是業(yè)務(wù)過程伐憾?在待開發(fā)軟件所處的業(yè)務(wù)領(lǐng)域內(nèi)完成特定業(yè)務(wù)任務(wù)(business task)的一系列活動就是業(yè)務(wù)過程。
用例的幾個基本要素
A use case is initiated by (or begins with) an actor. 一個用例應(yīng)該由業(yè)務(wù)領(lǐng)域內(nèi)的某個參與者(Actor)所觸發(fā)赫模。
A use case must accomplish a business task (for the actor).用例必須能為特定的參與者完成一個特定的業(yè)務(wù)任務(wù)树肃。
A use case must end with an actor. 一個用例必須終止于某個特定參與者,也就是特定參與者明確地或者隱含地得到了業(yè)務(wù)任務(wù)完成的結(jié)果瀑罗。
這里的參與者是業(yè)務(wù)領(lǐng)域內(nèi)的參與者或者業(yè)務(wù)實體胸嘴。
參與者不是待開發(fā)軟件系統(tǒng)的一部分,但參與者需要和待開發(fā)軟件系統(tǒng)交互斩祭。
參與者常常是人酬蹋,比如客戶爱咬,但也可以是一個外部的硬件或軟件妓羊,甚至是待開發(fā)軟件系統(tǒng)內(nèi)部的一個組件可婶,比如內(nèi)部計時器可以觸發(fā)某個業(yè)務(wù)過程。
某個參與者觸發(fā)某個用例為相應(yīng)的參與者完成一個業(yè)務(wù)任務(wù)席赂。
用例的三個抽象層級
在準(zhǔn)確理解用例概念的基礎(chǔ)上吮铭,我們可以進(jìn)一步將用例劃分為三個抽象層級:
抽象用例(Abstract use case)。只要用一個干什么颅停、做什么或完成什么業(yè)務(wù)任務(wù)的動名詞短語谓晌,就可以非常精簡地指明一個用例;
高層用例(High level use case)癞揉。需要給用例的范圍劃定一個邊界纸肉,也就是用例在什么時候什么地方開始溺欧,以及在什么時候什么地方結(jié)束;
擴展用例(Expanded use case)柏肪。需要將參與者和待開發(fā)軟件系統(tǒng)為了完成用例所規(guī)定的業(yè)務(wù)任務(wù)的交互過程一步一步詳細(xì)地描述出來姐刁,一般我們使用一個兩列的表格將參與者和待開發(fā)軟件系統(tǒng)之間從用例開始到用例結(jié)束的所有交互步驟都列舉出來。
用例建模的基本步驟
第一步烦味,從需求表述中找出用例聂使,往往是動名詞短語表示的抽象用例;
第二步谬俄,描述用例開始和結(jié)束的狀態(tài)柏靶,用TUCBW和TUCEW表示的高層用例;
第三步溃论,對用例按照子系統(tǒng)或不同的方面進(jìn)行分類屎蜓,描述用例與用例、用例與參與者之間的上下文關(guān)系钥勋,并畫出用例圖炬转;
第四步,進(jìn)一步逐一分析用例與參與者的詳細(xì)交互過程笔诵,完成一個兩列的表格將參與者和待開發(fā)軟件系統(tǒng)之間從用例開始到用例結(jié)束的所有交互步驟都列舉出來擴展用例。
其中第一步到第三步是計劃階段姑子,第四步是增量實現(xiàn)階段乎婿。
用例圖的基本畫法
關(guān)聯(lián)關(guān)系是用一條直線表示的,一般不強調(diào)關(guān)聯(lián)的方向街佑。關(guān)聯(lián)關(guān)系是一種靜態(tài)關(guān)系谢翎,是由常識、規(guī)則和法律等因素前置約定的沐旨。
一對一的關(guān)聯(lián)關(guān)系可以在直線的兩端都標(biāo)上1表示一對一森逮;一對多的關(guān)聯(lián)關(guān)系可以在直線的兩端分別標(biāo)上1和*(代表任意數(shù))表示一對多;多對多的關(guān)聯(lián)關(guān)系可以在直線的兩端都標(biāo)上表示多對多磁携。
單向關(guān)聯(lián)關(guān)系褒侧,是用一條直線加箭頭表示的。比如在用例圖中參與者和用例就是一種單向關(guān)聯(lián)關(guān)系谊迄,參與者總是“知道”用例闷供,而用例“不知道”參與者,所以箭頭可以從參與者指向用例统诺,不過在UML建模工具中歪脏,關(guān)聯(lián)方向是不被強調(diào)的。
包含關(guān)系是用一條帶箭頭的虛線加<>來表示的粮呢。包含關(guān)系特別用于用例模型中婿失,是指在執(zhí)行基本用例的過程中插入包含用例钞艇。
擴展關(guān)系是用一條帶箭頭的虛線加<>來表示的。擴展用例特別用于用例模型中豪硅,表示向基本用例中的某個擴展點插入擴展用例哩照。
自動售貨機的用例圖
2、面向?qū)ο蠓治錾婕暗幕靖拍?/p>
對象(Object)和屬性(Attribute)
繼承關(guān)系(Inheritance Relationship)
繼承關(guān)系表達(dá)著兩個概念之間具有概括化/具體化(generalization/specialization)的關(guān)系
一般用三角形箭頭連線表示兩個類之間的繼承關(guān)系
聚合關(guān)系(Aggregation Relationship)
聚合關(guān)系表示一個對象是另一個對象的一部分的情況舟误。比如發(fā)動機引擎是小汽車的一部分葡秒。也被稱為“部分與整體”(part-of)的關(guān)系。
聚合關(guān)系使用一個平行四邊形的箭頭表示
關(guān)聯(lián)關(guān)系(Association Relationship)
關(guān)聯(lián)關(guān)系表示繼承和聚合以外的一般關(guān)系嵌溢,是業(yè)務(wù)領(lǐng)域內(nèi)特定的兩個概念之間的關(guān)系眯牧,
既不是繼承關(guān)系也不是聚合關(guān)系。比如教授參與了退休計劃赖草、講師教授課程学少、用戶擁有賬戶等都是兩個概念之間一般關(guān)系,我們用一個直線連起來來表示教授和退休計劃兩個業(yè)務(wù)領(lǐng)域概念之間的關(guān)聯(lián)關(guān)系秧骑,
業(yè)務(wù)領(lǐng)域建模(Domain Modeling)
業(yè)務(wù)領(lǐng)域建模是開發(fā)團(tuán)隊用于獲取業(yè)務(wù)領(lǐng)域知識的過程版确。因為軟件工程師往往需要工作在不同的業(yè)務(wù)領(lǐng)域或者不同項目中,他們需要業(yè)務(wù)領(lǐng)域知識來開發(fā)軟件系統(tǒng)乎折。軟件工程師往往來自不同的專業(yè)背景绒疗,這可能會影響他們對業(yè)務(wù)領(lǐng)域的認(rèn)知。因此業(yè)務(wù)領(lǐng)域建模有助于開發(fā)團(tuán)隊獲取業(yè)務(wù)領(lǐng)域知識形成統(tǒng)一的業(yè)務(wù)認(rèn)知
關(guān)聯(lián)類及數(shù)據(jù)模型
關(guān)聯(lián)關(guān)系是業(yè)務(wù)數(shù)據(jù)建模的關(guān)鍵骂澄,我們來專門研究一下關(guān)聯(lián)關(guān)系吓蘑,并引入一個關(guān)聯(lián)類(Association Class)的概念,而且關(guān)聯(lián)類為兩個類的關(guān)聯(lián)關(guān)系定義了一些屬性和方法坟冲。
關(guān)系數(shù)據(jù)模型的MongoDB設(shè)計與實現(xiàn)
3磨镶、從需求分析到軟件設(shè)計
敏捷統(tǒng)一過程(Agile Unified Process)
對象交互建模(Object Interaction Modeling)
形成軟件設(shè)計方案的基本方法
統(tǒng)一過程(Unified Process)
統(tǒng)一過程(UP,Unified Process)的核心要義是用例驅(qū)動(Use case driven)健提、以架構(gòu)為中心(Architecture centric)琳猫、增量且迭代(Incremental and Iterative)的過程。用例驅(qū)動就是我們前文中用例建模得到的用例作為驅(qū)動軟件開發(fā)的目標(biāo)私痹;以架構(gòu)為中心的架構(gòu)是后續(xù)軟件設(shè)計的結(jié)果脐嫂,就是保持軟件架構(gòu)相對穩(wěn)定,減小軟件架構(gòu)層面的重構(gòu)造成的混亂紊遵;增量且迭代體現(xiàn)在下圖中雹锣。
結(jié)合瀑布模型我們可以將統(tǒng)一過程模型簡單理解為如圖所示。
敏捷統(tǒng)一過程(Agile Unified Process)進(jìn)一步將軟件過程中每一次迭代過程劃分為計劃階段和增量階段癞蚕。
瀑布模型
在繼續(xù)進(jìn)行從需求分析到軟件設(shè)計的后續(xù)部分之前蕊爵,我們有必要從整體上探討一下我們所遵循的軟件過程——敏捷統(tǒng)一過程。為了理解敏捷統(tǒng)一過程桦山,我們先從瀑布模型(Waterfall Process)說起攒射。
瀑布模型是最基本的過程模型醋旦,它把整個軟件過程按順序劃分成了需求、設(shè)計会放、編碼饲齐、測試和部署五個階段。瀑布模型的根本特點是按順序劃分階段咧最,至于是像我們這樣劃分成五階段捂人,還是劃分三個階段或八個階段,并不是關(guān)鍵矢沿。這一點需要讀者注意滥搭,以免在閱讀其他資料時產(chǎn)生困惑。
敏捷統(tǒng)一過程的計劃階段
在項目正式動手開工之前捣鲸,敏捷統(tǒng)一過程要求進(jìn)行精心周密的構(gòu)思完成計劃階段瑟匆。計劃階段要做的工作有如下幾點:
首先明確項目的動機、業(yè)務(wù)上的實際需求栽惶,
以及對項目動機和業(yè)務(wù)需求可供替代選擇的多種可能性愁溜;
然后充分調(diào)研獲取需求并明確定義需求規(guī)格;
在明確需求規(guī)格的基礎(chǔ)上進(jìn)行項目的可行性研究外厂;
如果項目可行冕象,接下來接著進(jìn)行用例建模并給出用例圖;
同時明確需求和用例之間的可跟蹤矩陣汁蝶;
從而形成項目的概念模型草案渐扮;
以及項目可能的日程安排、需要的資源以及大致的預(yù)算范圍穿仪。
敏捷統(tǒng)一過程的四個關(guān)鍵步驟
第一席爽,確定需求意荤;
第二啊片,通過用例的方式來滿足這些需求;
第三玖像,分配這些用例到各增量階段紫谷;
第四,具體完成各增量階段所計劃的任務(wù)捐寥。
顯然笤昨,第一到第三步主要是計劃階段的工作,第四步是接下來要進(jìn)一步詳述的增量階段的工作握恳。
敏捷統(tǒng)一過程的增量階段
在每一次增量階段的迭代過程中瞒窒,都要進(jìn)行從需求分析到軟件設(shè)計實現(xiàn)的過程,具體敏捷統(tǒng)一過程將增量階段分為五個步驟:
用例建模(Use case modeling)乡洼;
業(yè)務(wù)領(lǐng)域建模(Domain modeling)崇裁;
對象交互建模(Object Interaction modeling)匕坯;
形成設(shè)計類圖(design class diagram);
軟件的編碼實現(xiàn)和軟件應(yīng)用部署拔稳;
對象交互建模的基本步驟
找出關(guān)鍵步驟進(jìn)行劇情描述(scenario)
將劇情描述(scenario)轉(zhuǎn)換成劇情描述表(scenario table)
將劇情描述表轉(zhuǎn)換成序列圖的基本方法
從分析序列圖到設(shè)計序列圖
一個完整用例的對象交互建模
?第一步葛峻,在擴展用例中右側(cè)一列中找出關(guān)鍵步驟(nontrivial steps)。關(guān)鍵步驟是那些需要在背后進(jìn)行業(yè)務(wù)過程處理的步驟巴比,而不是僅僅在表現(xiàn)層(presentation layer, i.e., the Graphical User Interface or GUI)與參與者進(jìn)行用戶接口層面交互的瑣碎步驟术奖。
?第二步,對于每一個關(guān)鍵步驟轻绞,從關(guān)鍵步驟在擴展用例兩列表格中的左側(cè)作為開始采记,完成劇情描述(scenario),描述一步一步的對象交互過程铲球,直到執(zhí)行完該關(guān)鍵步驟挺庞。
?第三步,如果需要的話稼病,將劇情描述(scenario)進(jìn)一步轉(zhuǎn)換成劇情描述表(scenario table)选侨。
?第四步,將劇情描述(scenario)或劇情描述表(scenario table)轉(zhuǎn)換成序列圖然走。
?對象交互建模的四個基本步驟以某個用例的擴展用例為輸入援制,中間借助業(yè)務(wù)領(lǐng)域知識及業(yè)務(wù)領(lǐng)域建模中的相關(guān)對象、屬性等芍瑞,最終產(chǎn)出結(jié)果為序列圖晨仑。
將劇情描述表轉(zhuǎn)換成序列圖的基本方法
情形一:主體(Subject)是一個參與者(Actor)
情形二:主體(Subject)是一個對象(Object)
情形三:主體(Subject)需要接收返回值的情形
情形四:主體(Subject)和主體行為的作用對象(object acted upon)是同一個對象的情形
形成軟件設(shè)計方案的基本方法
軟件產(chǎn)品龐大復(fù)雜,前面的形成的設(shè)計類圖只是其中一個用例得到的設(shè)計結(jié)果拆檬,我們需要對每一個用例進(jìn)行分析和設(shè)計洪己,最終再將各用例得到的設(shè)計結(jié)果綜合成一個軟件產(chǎn)品的整體設(shè)計方案。其中涉及兩個基本的方法:分析(analysis)和綜合(synthesis)竟贯。
分析是分解大問題變成易于理解的小問題答捕。比如用例建模是將錯綜復(fù)雜的需求分解成一個一個的用例。在分析的過程中除了“分而治之”的切分分解的方法外屑那,抽象方法的運用是一個關(guān)鍵
綜合是將一個個小問題的解決方案組合起來構(gòu)建軟件的整體解決方案拱镐。我們對每一個用例的關(guān)鍵步驟進(jìn)行對象交互建模逐步形成了用例對應(yīng)的解決方案,如何將多個用例的小解決方案組合起來構(gòu)建軟件整體設(shè)計方案持际?這在軟件設(shè)計中是一個非常有挑戰(zhàn)性的問題沃琅,一般我們通過參考已有的軟件設(shè)計模式提供一個思路從而綜合出一個軟件整體解決方案
關(guān)系數(shù)據(jù)模型的MongoDB設(shè)計與實現(xiàn)
MongoDB簡介
MongoDB是一個通用的、基于文檔的蜘欲、分布式的數(shù)據(jù)庫益眉,為云計算時代的現(xiàn)代應(yīng)用程序開發(fā)者而生,沒有數(shù)據(jù)庫比MongoDB在應(yīng)用開發(fā)效率上更加高效姥份。
MongoDB是一種文檔數(shù)據(jù)庫郭脂,也就是說MongoDB用類似JSON格式的文檔來存儲數(shù)據(jù)空繁。目前普遍認(rèn)為JSON格式是理解和存儲數(shù)據(jù)最自然的方式,JSON格式比傳統(tǒng)的關(guān)系數(shù)據(jù)模型有更強大的數(shù)據(jù)表達(dá)能力朱庆。
MongoDB中存儲的JSON格式文檔范例如下所示盛泡。每一個JSON文檔對應(yīng)一個ID即下圖中“_id"的值,除“_id"外的數(shù)據(jù)按照“key:value”的方式可以任意定義數(shù)據(jù)的結(jié)構(gòu)
在一個MongoDB數(shù)據(jù)庫中娱颊,可以創(chuàng)建多個集合(Collection)傲诵,集合的概念類似于關(guān)系數(shù)據(jù)庫中的表(Table),只是比表更加靈活箱硕。下圖是在users集合中檢索郵政編碼為90404的數(shù)據(jù)拴竹,可見其檢索方式比傳統(tǒng)的SQL語言更加強大靈活
內(nèi)嵌,子引用剧罩,父引用
三種基本的設(shè)計方案:內(nèi)嵌栓拜,子引用,父引用
在選擇方案時需要考慮的兩個關(guān)鍵因素:
一對多中的多是否需要一個單獨的實體惠昔;
這個關(guān)系中集合的規(guī)模是一對很少幕与,很多,還是非常多镇防。
一對很少且不需要單獨訪問內(nèi)嵌內(nèi)容的情況下可以使用內(nèi)嵌多的一方啦鸣。
一對很多且很多的一端內(nèi)容因為各種理由需要單獨存在的情況下可以通過數(shù)組的方式引用多的一方的。
一對非常多的情況下来氧,請將一的那端引用嵌入進(jìn)多的一端對象中
反范式化
?反范式化在節(jié)省你讀的代價的同時會帶來更新的代價:如果你將零件的名字冗余到產(chǎn)品的文檔對象中诫给,那么你想更改某個零件的名字你就必須同時更新所有包含這個零件的產(chǎn)品對象。
?在一個讀比寫頻率高的多的系統(tǒng)里啦扬,反范式是有使用的意義的中狂。如果你很經(jīng)常的需要高效的讀取冗余的數(shù)據(jù),但是幾乎不去變更他的話扑毡,那么付出更新上的代價還是值得的胃榕。更新的頻率越高,這種設(shè)計方案的帶來的好處越少僚楞。
?例如:假設(shè)零件的名字變化的頻率很低勤晚,但是零件的庫存變化很頻繁枉层,那么你可以冗余零件的名字到產(chǎn)品對象中泉褐,但是別冗余零件的庫存。
?需要注意的是鸟蜡,一旦你冗余了一個字段膜赃,那么對于這個字段的更新將不再是原子的。和上面雙向引用的例子一樣揉忘,如果你在零件對象中更新了零件的名字跳座,那么更新產(chǎn)品對象中保存的名字字段前將會存在短時間的不一致端铛。
使用雙向引用來優(yōu)化你的數(shù)據(jù)庫架構(gòu),前提是你能接受無法原子更新的代價疲眷。
可以在引用關(guān)系中冗余數(shù)據(jù)到one端或者N端禾蚕。
在決定是否采用反范式化時需要考慮下面的因素:
你將無法對冗余的數(shù)據(jù)進(jìn)行原子更新。
只有讀寫比比較高的情況下才應(yīng)該采取反范式化的設(shè)計
關(guān)系數(shù)據(jù)模型的MongoDB設(shè)計與實現(xiàn)總結(jié)
優(yōu)先考慮內(nèi)嵌狂丝,除非有什么迫不得已的原因换淆。
需要單獨訪問一個對象,那這個對象就不適合被內(nèi)嵌到其他對象中几颜。
數(shù)組不應(yīng)該無限制增長倍试。如果many端有數(shù)百個文檔對象就不要去內(nèi)嵌他們可以采用引用ObjectID的方案;如果有數(shù)千個文檔對象蛋哭,那么就不要內(nèi)嵌ObjectID的數(shù)組县习。該采取哪些方案取決于數(shù)組的大小。
不要害怕應(yīng)用層級別的join:如果索引建的正確并且通過投影條件限制返回的結(jié)果谆趾,那么應(yīng)用層級別的join并不會比關(guān)系數(shù)據(jù)庫中join開銷大多少躁愿。
在進(jìn)行反范式設(shè)計時請先確認(rèn)讀寫比。一個幾乎不更改只是讀取的字段才適合冗余到其他對象中沪蓬。
在mongodb中如何對你的數(shù)據(jù)建模攘已,取決于你的應(yīng)用程序如何去訪問它們。數(shù)據(jù)的結(jié)構(gòu)要去適應(yīng)你的程序的讀寫場景怜跑。
第四章样勃、軟件科學(xué)基礎(chǔ)概論
軟件的基本架構(gòu)
?? 順序結(jié)構(gòu)
?? 分支結(jié)構(gòu)
?? 循環(huán)結(jié)構(gòu)
?? 函數(shù)調(diào)用框架
?? 繼承和對象組合
軟件中的一些特殊機制
回調(diào)函數(shù)
回調(diào)函數(shù)是一個面向過程的概念,是代碼執(zhí)行過程的一種特殊流程性芬∠靠簦回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù)植锉,當(dāng)這個指針調(diào)用其所指向的函數(shù)時辫樱,就稱這是回調(diào)函數(shù)】”樱回調(diào)函數(shù)不是該函數(shù)的實現(xiàn)方直接調(diào)用狮暑,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)辉饱。
//回調(diào)函數(shù)
int SearchCondition(tLinkTableNode * pLinkTableNode, void * args)
{
? ? char * cmd = (char*) args;
? ? tDataNode * pNode = (tDataNode *)pLinkTableNode;
? ? if(strcmp(pNode->cmd, cmd) == 0)
? ? {
? ? ? ? return? SUCCESS;?
? ? }
? ? return FAILURE;? ? ? ? ?
}
int main()
{
? ? ...
? ? //傳遞回調(diào)函數(shù)
? ? SearchLinkTableNode(head, SearchCondition, (void*)cmd);
? ? …
}
閉包
閉包是變量作用域的一種特殊情形搬男,一般用在將函數(shù)作為返回值時,該函數(shù)執(zhí)行所需的上下文環(huán)境也作為返回的函數(shù)對象的一部分彭沼,這樣該函數(shù)對象就是一個閉包缔逛。
更嚴(yán)謹(jǐn)?shù)亩x是,函數(shù)和對其周圍狀態(tài)(lexical environment,詞法環(huán)境)的引用捆綁在一起構(gòu)成閉包(closure)褐奴。也就是說按脚,閉包可以讓你從內(nèi)部函數(shù)訪問外部函數(shù)作用域。在JavaScript中敦冬,每當(dāng)函數(shù)被創(chuàng)建辅搬,就會在函數(shù)生成時生成閉包。
function makeFunc() {
? ? var name = "Mozilla";
? ? function displayName() {
? ? ? ? alert(name);
? ? }
? ? return displayName;
}
var myFunc = makeFunc();
myFunc();
多態(tài)
多態(tài)(Polymorphism)按字面的意思就是“多種狀態(tài)”脖旱。在面向?qū)ο笳Z言中伞辛,接口的多種不同的實現(xiàn)方式即為多態(tài)。多態(tài)是實例化變量可以指向不同的實例對象夯缺,這樣同一個實例化變量在不同的實例對象上下文環(huán)境中執(zhí)行不同的代碼表現(xiàn)出不同的行為狀態(tài)蚤氏,而通過實例化變量調(diào)用實例對象的方法的那一塊代碼卻是完全相同的,這就顧名思義踊兜,同一段代碼執(zhí)行時卻表現(xiàn)出不同的行為狀態(tài)竿滨,因而叫多態(tài)。簡單的說捏境,可以理解為允許將不同的子類類型的對象動態(tài)賦值給父類類型的變量于游,通過父類的變量調(diào)用方法在執(zhí)行時實際執(zhí)行的可能是不同的子類對象方法,因而表現(xiàn)出不同的執(zhí)行效果
異步調(diào)用
Promise對象可以將異步調(diào)用以同步調(diào)用的流程表達(dá)出來垫言,避免了通過嵌套回調(diào)函數(shù)實現(xiàn)異步調(diào)用贰剥。
Promise對象的基本用法
Promise對象實際上是對回調(diào)函數(shù)機制的封裝,也就是通過then方法定義的函數(shù)與resolve/reject函數(shù)綁定筷频,簡化了回調(diào)函數(shù)傳入的接口實現(xiàn)蚌成,在邏輯上也更加通順,看起來像是個同步接口凛捏。
var promise = new Promise(function(resolve, reject) {
? if (/* 異步操作成功 */){
? ? resolve(value);
? } else {
? ? reject(error);
? }
});
promise.then(function(value) { // resolve(value)
? // success
}, function(value) { // reject(error)
? // failure
});
匿名函數(shù)
lamda函數(shù)是函數(shù)式編程中的高階函數(shù)
設(shè)計模式
設(shè)計模式的本質(zhì)是面向?qū)ο笤O(shè)計原則的實際運用總結(jié)出的經(jīng)驗?zāi)P偷S恰︻惖姆庋b性、繼承性和多態(tài)性以及類的關(guān)聯(lián)關(guān)系和組合關(guān)系的充分理解的基礎(chǔ)上才能準(zhǔn)確理解設(shè)計模式坯癣。
設(shè)計模式的優(yōu)點
正確使用設(shè)計模式具有以下優(yōu)點瓶盛。
可以提高程序員的思維能力、編程能力和設(shè)計能力示罗。
使程序設(shè)計更加標(biāo)準(zhǔn)化惩猫、代碼編制更加工程化,使軟件開發(fā)效率大大提高蚜点,從而縮短軟件的開發(fā)周期轧房。
使設(shè)計的代碼可重用性高、可讀性強禽额、可靠性高锯厢、靈活性好、可維護(hù)性強脯倒。
用模塊化來包容變化实辑,使用模塊化封裝的方法,按照模塊化追求的高內(nèi)聚低耦合目標(biāo)藻丢,借助于抽象思維對模塊內(nèi)部信息的隱藏并使用封裝接口對外只暴露必要的可見信息剪撬,利用多態(tài)、閉包悠反、lamda函數(shù)残黑、回調(diào)函數(shù)等特殊的機制方法,將變化的部分和不變的部分進(jìn)行適當(dāng)隔離斋否。這些都是設(shè)計模式的拿手好戲
設(shè)計模式的分類
根據(jù)模式是主要用于類上還是主要用于對象上來劃分的話梨水,可分為類模式和對象模式兩種類型的設(shè)計模式:
類模式:用于處理類與子類之間的關(guān)系,這些關(guān)系通過繼承來建立茵臭,是靜態(tài)的疫诽,在編譯時刻便確定下來了。比如模板方法模式等屬于類模式旦委。
對象模式:用于處理對象之間的關(guān)系奇徒,這些關(guān)系可以通過組合或聚合來實現(xiàn),在運行時刻是可以變化的缨硝,更具動態(tài)性摩钙。由于組合關(guān)系或聚合關(guān)系比繼承關(guān)系耦合度低,因此多數(shù)設(shè)計模式都是對象模式查辩。
根據(jù)設(shè)計模式可以完成的任務(wù)類型來劃分的話胖笛,可以分為創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式 3 種類型的設(shè)計模式:
創(chuàng)建型模式:用于描述“怎樣創(chuàng)建對象”宜岛,它的主要特點是“將對象的創(chuàng)建與使用分離”匀钧。比如單例模式、原型模式谬返、建造者模式等屬于創(chuàng)建型模式之斯。
結(jié)構(gòu)型模式:用于描述如何將類或?qū)ο蟀茨撤N布局組成更大的結(jié)構(gòu),比如代理模式遣铝、適配器模式佑刷、橋接模式、裝飾模式酿炸、外觀模式瘫絮、享元模式、組合模式等屬于結(jié)構(gòu)型模式填硕。結(jié)構(gòu)型模式分為類結(jié)構(gòu)型模式和對象結(jié)構(gòu)型模式麦萤,前者采用繼承機制來組織接口和類鹿鳖,后者釆用組合或聚合來組合對象。由于組合關(guān)系或聚合關(guān)系比繼承關(guān)系耦合度低壮莹,所以對象結(jié)構(gòu)型模式比類結(jié)構(gòu)型模式具有更大的靈活性翅帜。
行為型模式:**用于描述程序在運行時復(fù)雜的流程控制,即描述多個類或?qū)ο笾g怎樣相互協(xié)作共同完成單個對象都無法單獨完成的任務(wù)命满,它涉及算法與對象間職責(zé)的分配涝滴。**比如模板方法模式、策略模式胶台、命令模式歼疮、職責(zé)鏈模式、觀察者模式等屬于行為型模式诈唬。行為型模式分為類行為模式和對象行為模式韩脏,前者采用繼承在類間分配行為,后者采用組合或聚合在對象間分配行為铸磅。由于組合關(guān)系或聚合關(guān)系比繼承關(guān)系耦合度低骤素,所以對象行為模式比類行為模式具有更大的靈活性
常用的設(shè)計模式
單例(Singleton)模式:某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例愚屁,典型的應(yīng)用如數(shù)據(jù)庫實例济竹。
原型(Prototype)模式:將一個對象作為原型,通過對其進(jìn)行復(fù)制而克隆出多個和原型類似的新實例霎槐,原型模式的應(yīng)用場景非常多送浊,幾乎所有通過復(fù)制的方式創(chuàng)建新實例的場景都有原型模式。
建造者(Builder)模式:將一個復(fù)雜對象分解成多個相對簡單的部分丘跌,然后根據(jù)不同需要分別創(chuàng)建它們袭景,最后構(gòu)建成該復(fù)雜對象炮温。主要應(yīng)用于復(fù)雜對象中的各部分的建造順序相對固定或者創(chuàng)建復(fù)雜對象的算法獨立于各組成部分
代理(Proxy)模式:為某對象提供一種代理以控制對該對象的訪問膊毁。即客戶端通過代理間接地訪問該對象,從而限制姨蟋、增強或修改該對象的一些特性报辱。代理模式是不要和陌生人說話原則的體現(xiàn)与殃,典型的應(yīng)用如外部接口本地化將外部的輸入和輸出封裝成本地接口,有效降低模塊與外部的耦合度碍现。
適配器(Adapter)模式:將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口幅疼,使得原本由于接口不兼容而不能一起工作的那些類能一起工作。繼承和對象組合都可以實現(xiàn)適配器模式昼接,但由于組合關(guān)系或聚合關(guān)系比繼承關(guān)系耦合度低爽篷,所以對象組合方式的適配器模式比較常用。
裝飾(Decorator)模式:在不改變現(xiàn)有對象結(jié)構(gòu)的情況下慢睡,動態(tài)地給對象增加一些職責(zé)逐工,即增加其額外的功能铡溪。裝飾模式實質(zhì)上是用對象組合的方式擴展功能,因為比繼承的方式擴展功能耦合度低泪喊。裝飾模式在 Java 語言中的最著名的應(yīng)用莫過于 Java I/O 標(biāo)準(zhǔn)庫的設(shè)計了棕硫。例如,InputStream 的子類 FilterInputStream窘俺,OutputStream 的子類 FilterOutputStream饲帅,Reader 的子類 BufferedReader 以及 FilterReader复凳,還有 Writer 的子類 BufferedWriter瘤泪、FilterWriter 以及 PrintWriter 等,它們都是抽象裝飾類育八。
外觀(Facade)模式:為復(fù)雜的子系統(tǒng)提供一個一致的接口对途,使這些子系統(tǒng)更加容易被訪問。
享元(Flyweight)模式:運用共享技術(shù)來有效地支持大量細(xì)粒度對象的復(fù)用髓棋。比如線程池实檀、固定分配存儲空間的消息隊列等往往都是該模式的應(yīng)用場景。
策略(Strategy)模式:定義了一系列算法按声,并將每個算法封裝起來膳犹,使它們可以相互替換,且算法的改變不會影響使用算法的客戶签则。策略 模式是多態(tài)和對象組合的綜合應(yīng)用须床。
命令(Command)模式:將一個請求封裝為一個對象,使發(fā)出請求的責(zé)任和執(zhí)行請求的責(zé)任分割開渐裂。這樣兩者之間通過命令對象進(jìn)行溝通豺旬,這樣方便將命令對象進(jìn)行儲存、傳遞柒凉、調(diào)用族阅、增加與管理。
模板方法(TemplateMethod)模式:定義一個操作中的算法骨架膝捞,而將算法的一些步驟延遲到子類中坦刀,使得子類可以不改變該算法結(jié)構(gòu)的情況下重定義該算法的某些特定步驟。**模版方法是繼承和重載機制的應(yīng)用蔬咬,屬于類模式求泰。
職責(zé)鏈(Chain of Responsibility)模式:為了避免請求發(fā)送者與多個請求處理者耦合在一起,將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈计盒;當(dāng)有請求發(fā)生時渴频,可將請求沿著這條鏈傳遞,直到有對象處理它為止北启。通過這種方式將多個請求處理者串聯(lián)為一個鏈表卜朗,去除請求發(fā)送者與它們之間的耦合拔第。
中介者(Mediator)模式:定義一個中介對象來簡化原有對象之間的交互關(guān)系,降低系統(tǒng)中對象間的耦合度场钉,使原有對象之間不必相互了解蚊俺。在現(xiàn)實生活中,常常會出現(xiàn)好多對象之間存在復(fù)雜的交互關(guān)系逛万,這種交互關(guān)系常常是“網(wǎng)狀結(jié)構(gòu)”泳猬,它要求每個對象都必須知道它需要交互的對象。如果把這種“網(wǎng)狀結(jié)構(gòu)”改為“星形結(jié)構(gòu)”的話宇植,將大大降低它們之間的“耦合性”得封,這時只要找一個“中介者”就可以了。在軟件的開發(fā)過程中指郁,這樣的例子也很多忙上,例如,在 MVC 框架中闲坎,控制器(C)就是模型(M)和視圖(V)的中介者疫粥,采用“中介者模式”大大降低了對象之間的耦合性,提高系統(tǒng)的靈活性腰懂。
觀察者(Observer)模式:指多個對象間存在一對多的依賴關(guān)系梗逮,當(dāng)一個對象的狀態(tài)發(fā)生改變時,把這種改變通知給其他多個對象绣溜,從而影響其他對象的行為慷彤,這樣所有依賴于它的對象都得到通知并被自動更新。這種模式有時又稱作發(fā)布-訂閱模式
設(shè)計模式背后的設(shè)計原則
開閉原則(Open Closed Principle涮毫,OCP)
Liskov替換原則(Liskov Substitution Principle瞬欧,LSP)
依賴倒置原則(Dependence Inversion Principle,DIP)
單一職責(zé)原則(Single Responsibility Principle罢防,SRP)
迪米特法則(Law of Demeter艘虎,LoD)
合成復(fù)用原則(Composite Reuse Principle,CRP)
開閉原則(Open Closed Principle咒吐,OCP)
軟件應(yīng)當(dāng)對擴展開放野建,對修改關(guān)閉。
遵守開閉原則使軟件擁有一定的適應(yīng)性和靈活性的同時具備穩(wěn)定性和延續(xù)性恬叹。統(tǒng)一過程以架構(gòu)為中心增量且迭代的過程和開閉原則具有內(nèi)在的一致性候生,它們都追求軟件結(jié)構(gòu)上的穩(wěn)定性。當(dāng)我們理解了軟件結(jié)構(gòu)模型本質(zhì)上具有不穩(wěn)定性的時候绽昼,一個小小的需求變更便很可能會觸動軟件結(jié)構(gòu)的靈魂唯鸭,瞬間讓軟件結(jié)構(gòu)崩塌,即便通過破壞軟件結(jié)構(gòu)的內(nèi)在邏輯模型打上丑陋的補丁程序硅确,也會使得軟件內(nèi)在結(jié)構(gòu)惡化加速軟件的死亡目溉。因此開閉原則在基本需求穩(wěn)定且被充分理解的前提下才具有一定的價值明肮。
Liskov替換原則(Liskov Substitution Principle,LSP)
Liskov替換原則主要闡述了繼承用法的原則缭付,也就是什么時候應(yīng)該使用繼承柿估,什么時候不應(yīng)該使用繼承,以及其中蘊含的原理陷猫。通俗來講就是:子類可以擴展父類的功能秫舌,但不能改變父類原有的功能。也就是說兒子和父母要在DNA基因上一脈相承绣檬,盡管程序員是自己的代碼的上帝足陨,但也不能胡來,要做一個遵守自然規(guī)律的上帝
Liskov替換原則如今看來其價值也大大折扣河咽,因為為了降低耦合度我們往往使用對象組合來替代繼承關(guān)系钠右。反而是Liskov替換原則不推薦的多態(tài)成為諸多設(shè)計模式的基礎(chǔ)赋元。
依賴倒置原則(Dependence Inversion Principle忘蟹,DIP)
依賴倒置原則的原始定義為:高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象搁凸;抽象不應(yīng)該依賴細(xì)節(jié)媚值,細(xì)節(jié)應(yīng)該依賴抽象。其核心思想是:要面向接口編程护糖,不要面向?qū)崿F(xiàn)編程褥芒。
單一職責(zé)原則(Single Responsibility Principle,SRP)
單一職責(zé)原則(Single Responsibility Principle嫡良,SRP)又稱單一功能原則锰扶,單一職責(zé)原則規(guī)定一個類應(yīng)該有且僅有一個引起它變化的原因,否則類應(yīng)該被拆分寝受。
單一職責(zé)原則的核心就是控制類的粒度大小坷牛、提高其內(nèi)聚度。如果遵循單一職責(zé)原則可以降低類的復(fù)雜度很澄,因為一個類只負(fù)責(zé)一項職責(zé)京闰,其邏輯肯定要比負(fù)責(zé)多項職責(zé)簡單得多;同時可以提高類的內(nèi)聚度甩苛,符合模塊化設(shè)計的高內(nèi)聚低耦合的設(shè)計原則
迪米特法則(Law of Demeter蹂楣,LoD)
迪米特法則的定義是:只與你的直接朋友交談,不跟“陌生人”說話(Talk only to your immediate friends and not to strangers)讯蒲。其含義是:如果兩個軟件實體無須直接通信痊土,那么就不應(yīng)當(dāng)發(fā)生直接的相互調(diào)用,可以通過第三方轉(zhuǎn)發(fā)該調(diào)用墨林。其目的是降低類之間的耦合度赁酝,提高模塊的相對獨立性反浓。
合成復(fù)用原則(Composite Reuse Principle,CRP)
合成復(fù)用原則(Composite Reuse Principle赞哗,CRP)又叫組合/聚合復(fù)用原則(Composition/Aggregate Reuse Principle雷则,CARP)。它要求在軟件復(fù)用時肪笋,要盡量先使用組合或者聚合關(guān)系來實現(xiàn)月劈,其次才考慮使用繼承關(guān)系來實現(xiàn)。如果要使用繼承關(guān)系藤乙,則必須嚴(yán)格遵循Liskov替換原則猜揪。
通常類的復(fù)用分為繼承復(fù)用和對象組合復(fù)用兩種。
繼承復(fù)用的缺點
繼承復(fù)用破壞了類的封裝性坛梁。因為繼承會將父類的實現(xiàn)細(xì)節(jié)暴露給子類而姐,父類對子類是透明的,所以這種復(fù)用又稱為“白箱”復(fù)用划咐。
子類與父類的耦合度高拴念。父類的實現(xiàn)的任何改變都會導(dǎo)致子類的實現(xiàn)發(fā)生變化,這不利于類的擴展與維護(hù)褐缠。
繼承復(fù)用限制了復(fù)用的靈活性政鼠。從父類繼承而來的實現(xiàn)是靜態(tài)的,在編譯時已經(jīng)定義队魏,所以在運行時不可能發(fā)生變化公般。
合成復(fù)用的優(yōu)點
采用組合或聚合復(fù)用時,可以將已有對象納入新對象中胡桨,使之成為新對象的一部分官帘,新對象可以調(diào)用已有對象的功能,它有以下優(yōu)點昧谊。
組合或聚合復(fù)用維持了類的封裝性刽虹。因為屬性對象的內(nèi)部細(xì)節(jié)是新對象看不見的,所以這種復(fù)用又稱為“黑箱”復(fù)用揽浙。
新舊類之間的耦合度低状婶。這種復(fù)用所需的依賴較少,新對象存取屬性對象的唯一方法是通過屬性對象的接口馅巷。
復(fù)用的靈活性高膛虫。這種復(fù)用可以在運行時動態(tài)進(jìn)行,新對象可以動態(tài)地引用與屬性對象類型相同的對象钓猬。
常見的軟件架構(gòu)舉例
三層架構(gòu)
層次化架構(gòu)是利用面向接口編程的原則將層次化的結(jié)構(gòu)型設(shè)計模式作為軟件的主體結(jié)構(gòu)稍刀。比如三層架構(gòu)是層次化架構(gòu)中比較典型的代表,如下圖所示我們以層次化架構(gòu)為例來介紹
MVC架構(gòu)
MVC即為Model-View-Controller(模型-視圖-控制器),MVC是一種設(shè)計模式账月,以MVC設(shè)計模式為主體結(jié)構(gòu)實現(xiàn)的基礎(chǔ)代碼框架一般稱為MVC框架综膀,如果MVC設(shè)計模式?jīng)Q定了整個軟件的架構(gòu),不管是直接實現(xiàn)了MVC模式還是以某一種MVC框架為基礎(chǔ)局齿,只要軟件的整體結(jié)構(gòu)主要表現(xiàn)為MVC模式剧劝,我們就稱為該軟件的架構(gòu)為MVC架構(gòu)。
MVC中M抓歼、V和C所代表的含義如下:
Model(模型)代表一個存取數(shù)據(jù)的對象及其數(shù)據(jù)模型讥此。
View(視圖)代表模型包含的數(shù)據(jù)的表達(dá)方式,一般表達(dá)為可視化的界面接口谣妻。
Controller(控制器)作用于模型和視圖上萄喳,控制數(shù)據(jù)流向模型對象,并在數(shù)據(jù)變化時更新視圖蹋半∷蓿控制器可以使視圖與模型分離開解耦合。
MVC模式通常用開發(fā)具有人機交互界面的軟件减江,這類軟件的最大特點就是用戶界面容易隨著需求變更而發(fā)生改變染突,例如,當(dāng)你要擴展一個應(yīng)用程序的功能時您市,通常需要修改菜單和添加頁面來反映這種變化觉痛。如果用戶界面和核心功能邏輯緊密耦合在一起役衡,要擴展功能通常是非常困難的茵休,因為任何改動很容易在其他功能上產(chǎn)生錯誤。
為了包容需求上的變化而導(dǎo)致的用戶界面的修改不會影響軟件的核心功能代碼手蝎,可以采用將模型(Model)榕莺、視圖(View)和控制器(Controller)相分離的思想。采用MVC設(shè)計模式的話往往決定了整個軟件的主體結(jié)構(gòu)棵介,因此我們稱該軟件為MVC架構(gòu)钉鸯。
MVC架構(gòu) vs. 三層架構(gòu)
模型和視圖有著業(yè)務(wù)層面的業(yè)務(wù)數(shù)據(jù)緊密耦合關(guān)系,控制器的核心工作就是業(yè)務(wù)邏輯處理邮辽,顯然MVC架構(gòu)和三層架構(gòu)有著某種對應(yīng)關(guān)系唠雕,但又不是層次架構(gòu)的抽象接口依賴關(guān)系,因此為了體現(xiàn)它們的區(qū)別和聯(lián)系吨述,我們在MVC的結(jié)構(gòu)示意圖中將模型和視圖上下垂直對齊表示它們內(nèi)在的業(yè)務(wù)層次及業(yè)務(wù)數(shù)據(jù)的對應(yīng)關(guān)系岩睁,而將控制器放在左側(cè)表示控制器處于優(yōu)先重要位置,放在模型和視圖的中間位置是為了與三層架構(gòu)對應(yīng)與業(yè)務(wù)邏輯層處于相似的層次
應(yīng)用MVC架構(gòu)的軟件其基本的實現(xiàn)過程
控制器創(chuàng)建模型揣云;
控制器創(chuàng)建一個或多個視圖捕儒,并將它們與模型相關(guān)聯(lián);
控制器負(fù)責(zé)改變模型的狀態(tài);
當(dāng)模型的狀態(tài)發(fā)生改變時刘莹,模型會通知與之相關(guān)的視圖進(jìn)行更新阎毅。
可以看到這與抽象簡化的MVC設(shè)計模式已經(jīng)有了明顯的區(qū)別,變得更為復(fù)雜点弯,但這與實際軟件結(jié)構(gòu)相比還是極其簡化的模型扇调,實際情況可能會有更多合理的和不合理的復(fù)雜聯(lián)系,要保持軟件結(jié)構(gòu)在概念上的完整性極為困難抢肛。
MVC架構(gòu)中的模型肃拜、視圖與控制器
在MVC架構(gòu)下,模型用來封裝核心數(shù)據(jù)和功能雌团,它獨立于特定的輸出表示和輸入行為燃领,是執(zhí)行某些任務(wù)的代碼,至于這些任務(wù)以什么形式顯示給用戶锦援,并不是模型所關(guān)注的問題猛蔽。模型只有純粹的功能性接口,也就是一系列的公開方法灵寺,這些方法有的是取值方法曼库,讓系統(tǒng)其它部分可以得到模型的內(nèi)部狀態(tài),有的則是寫入更新數(shù)據(jù)的方法略板,允許系統(tǒng)的其它部分修改模型的內(nèi)部狀態(tài)毁枯。
在MVC架構(gòu)下,視圖用來向用戶顯示信息叮称,它獲得來自模型的數(shù)據(jù)种玛,決定模型以什么樣的方式展示給用戶。同一個模型可以對應(yīng)于多個視圖瓤檐,這樣對于視圖而言赂韵,模型就是可重用的代碼。一般來說挠蛉,模型內(nèi)部必須保留所有對應(yīng)視圖的相關(guān)信息祭示,以便在模型的狀態(tài)發(fā)生改變時,可以通知所有的視圖進(jìn)行更新谴古。
在MVC架構(gòu)下质涛,控制器是和視圖聯(lián)合使用的,它捕捉鼠標(biāo)移動掰担、鼠標(biāo)點擊和鍵盤輸入等事件汇陆,將其轉(zhuǎn)化成服務(wù)請求,然后再傳給模型或者視圖恩敌。軟件的用戶是通過控制器來與系統(tǒng)交互的瞬测,他通過控制器來操縱模型,從而向模型傳遞數(shù)據(jù),改變模型的狀態(tài)月趟,并最后導(dǎo)致視圖的更新灯蝴。
什么是MVVM?
Vue.js框架的MVVM架構(gòu)
?在前端頁面中孝宗,把Model用純JavaScript對象表示穷躁,View負(fù)責(zé)顯示,兩者做到了最大限度的分離因妇。把Model和View關(guān)聯(lián)起來的就是ViewModel问潭。ViewModel負(fù)責(zé)把Model的數(shù)據(jù)同步到View顯示出來,還負(fù)責(zé)把View的修改同步回Model婚被。以比較流行的Vue.js框架為例狡忙,MVVM架構(gòu)示意圖如下:
MVVM的優(yōu)點
MVVM模式和MVC模式一樣,主要目的是分離視圖(View)和模型(Model)址芯,有幾大優(yōu)點:
低耦合灾茁。視圖(View)可以獨立于Model變化和修改,一個ViewModel可以綁定到不同的"View"上谷炸,當(dāng)View變化的時候Model可以不變北专,當(dāng)Model變化的時候View也可以不變。
可重用性旬陡。你可以把一些視圖邏輯放在一個ViewModel里面拓颓,讓很多View重用這段視圖邏輯。
獨立開發(fā)描孟。開發(fā)人員可以專注于業(yè)務(wù)邏輯和數(shù)據(jù)的開發(fā)(ViewModel)驶睦,設(shè)計人員可以專注于頁面設(shè)計。
可測試画拾。界面素來是比較難于測試的啥繁,測試可以針對ViewModel來寫。
兩種不同層級的軟件架構(gòu)復(fù)用方法
克虑嗯住(Cloning),完整地借鑒相似項目的設(shè)計方案酬核,甚至代碼蜜另,只需要完成一些細(xì)枝末節(jié)處的修改適配工作。
重構(gòu)(Refactoring)嫡意,構(gòu)建軟件架構(gòu)模型的基本方法举瑰,通過指引我們?nèi)绾芜M(jìn)行系統(tǒng)分解,并在參考已有的軟件架構(gòu)模型的基礎(chǔ)上逐步形成系統(tǒng)軟件架構(gòu)的一種基本建模方法蔬螟。
分解的常見方法
面向功能的分解方法此迅,用例建模即是一種面向功能的分解方法;
面向特征的分解方法,根據(jù)數(shù)量眾多的某種系統(tǒng)顯著特征在不同抽象層次上劃分模塊的方法耸序;
面向數(shù)據(jù)的分解方法忍些,在業(yè)務(wù)領(lǐng)域建模中形成概念業(yè)務(wù)數(shù)據(jù)模型即應(yīng)用了面向數(shù)據(jù)的分解方法;
面向并發(fā)的分解方法坎怪,在一些系統(tǒng)中具有多種并發(fā)任務(wù)的特點罢坝,那么我們可以將系統(tǒng)分解到不同的并發(fā)任務(wù)中(進(jìn)程或線程),并描述并發(fā)任務(wù)的時序交互過程搅窿;
面向事件的分解方法嘁酿,當(dāng)系統(tǒng)中需要處理大量的事件,而且往往事件會觸發(fā)復(fù)雜的狀態(tài)轉(zhuǎn)換關(guān)系男应,這時系統(tǒng)就要考慮面向事件的分解方法闹司,并內(nèi)在狀態(tài)轉(zhuǎn)換關(guān)系進(jìn)行清晰的描述;
面向對象的分解方法沐飘,是一種通用的分析設(shè)計范式开仰,是基于系統(tǒng)中抽象的對象元素在不同抽象層次上分解的系統(tǒng)的方法。
管道-過濾器
管道-過濾器風(fēng)格的軟件架構(gòu)是面向數(shù)據(jù)流的軟件體系結(jié)構(gòu)薪铜,最典型的應(yīng)用是編譯系統(tǒng)众弓。 一個普通的編譯系統(tǒng)包括詞法分析器、語法分析器隔箍、語義分析與中間代碼生成器谓娃、目標(biāo)代碼生成器等一系列對源代碼進(jìn)行處理的過程。就像如圖:管道-過濾器風(fēng)格示意圖蜒滩,對源代碼處理的過濾器通過管道連接起來滨达,實現(xiàn)了端到端的從源代碼到編譯目標(biāo)的完整系統(tǒng)
客戶-服務(wù)
Client/Server(C/S)和Browser/Server(B/S)是我們常用的對軟件的網(wǎng)絡(luò)結(jié)構(gòu)特點的表述方式,但它們背后蘊含著一種普遍存在的軟件架構(gòu)風(fēng)格俯艰,即客戶-服務(wù)模式的架構(gòu)風(fēng)格捡遍。
客戶-服務(wù)模式的架構(gòu)風(fēng)格是指客戶代碼通過請求和應(yīng)答的方式訪問或者調(diào)用服務(wù)代碼。這里的請求和應(yīng)答可以是函數(shù)調(diào)用和返回值竹握,也可以是TCP Socket中的send和recv画株,還可以是HTTP協(xié)議中的GET請求和響應(yīng)。
在客戶-服務(wù)模式中啦辐,客戶是主動的谓传,服務(wù)是被動的∏酃兀客戶知道它向哪個服務(wù)發(fā)出請求续挟,而服務(wù)卻不知道它正在為哪個客戶提供服務(wù),甚至不知道正在為多少客戶提供服務(wù)侥衬。
客戶-服務(wù)模式的架構(gòu)風(fēng)格具有典型的模塊化特征诗祸,降低了系統(tǒng)中客戶和服務(wù)構(gòu)件之間耦合度跑芳,提高了服務(wù)構(gòu)件的可重用性。
P2P
P2P(peer-to-peer)架構(gòu)是客戶-服務(wù)模式的一種特殊情形直颅,P2P架構(gòu)中每一個構(gòu)件既是客戶端又是服務(wù)端博个,即每一個構(gòu)件都有一種接口,該接口不僅定義了構(gòu)件提供的服務(wù)际乘,同時也指定了向同類構(gòu)件發(fā)送的服務(wù)請求坡倔。這樣眾多構(gòu)件一起形成了一種對等的網(wǎng)絡(luò)結(jié)構(gòu),如圖:P2P網(wǎng)絡(luò)結(jié)構(gòu)示意圖脖含。
P2P架構(gòu)典型的應(yīng)用有文件共享網(wǎng)絡(luò)罪塔、比特幣網(wǎng)絡(luò)等。
發(fā)布-訂閱
在發(fā)布-訂閱架構(gòu)中养葵,有兩類構(gòu)件:發(fā)布者和訂閱者征堪。如果訂閱者訂閱了某一事件,則該事件一旦發(fā)生关拒,發(fā)布者就會發(fā)布通知給該訂閱者佃蚜。觀察者模式體現(xiàn)了發(fā)布-訂閱架構(gòu)的基本結(jié)構(gòu)。
在實際應(yīng)用中往往會需要不同的訂閱組着绊,以及不同的發(fā)布者谐算。由于訂閱者數(shù)量龐大往往在消息推送時采用消息隊列的方式延時推送。如圖:包含消息隊列的發(fā)布-訂閱架構(gòu)示意圖
CRUD
CRUD 是創(chuàng)建(Create)归露、 讀戎拗(Read)、更新(Update)和刪除(Delete)四種數(shù)據(jù)庫持久化信息的基本操作的助記符剧包,表示對于存儲的信息可以進(jìn)行這四種持久化操作恐锦。CRUD也代表了一種圍繞中心化管理系統(tǒng)關(guān)鍵數(shù)據(jù)的軟件架構(gòu)風(fēng)格。一般常見的各類信息系統(tǒng)疆液,比如ERP一铅、CRM、醫(yī)院信息化平臺等都可以用CRUD架構(gòu)來概括堕油。
層次化
?較為復(fù)雜的系統(tǒng)中的軟件單元潘飘,僅僅從平面展開的角度進(jìn)行模塊化分解是不夠的,還需要從垂直縱深的角度將軟件單元按層次化組織馍迄,每一層為它的上一層提供服務(wù)福也,同時又作為下一層的客戶。
?通信網(wǎng)絡(luò)中的OSI(Open System Interconnection)參考模型是典型的層次化架構(gòu)風(fēng)格攀圈,如圖:OSI參考模型示意圖。在OSI參考模型中每一層都將相鄰底層提供的通信服務(wù)抽象化峦甩,隱藏它的實現(xiàn)細(xì)節(jié)赘来,同時為相鄰的上一層提供服務(wù)现喳。
軟件架構(gòu)的描述方法
軟件架構(gòu)模型是通過一組關(guān)鍵視圖來描述的,同一個軟件架構(gòu)犬辰,由于選取的視角(Perspective)和抽象層次不同可以得到不同的視圖嗦篱,這樣一組關(guān)鍵視圖搭配起來可以完整地描述一個邏輯自洽的軟件架構(gòu)模型。一般來說幌缝,我們常用的幾種視圖有分解視圖灸促、依賴視圖、泛化視圖涵卵、執(zhí)行視圖浴栽、實現(xiàn)視圖、部署視圖和工作任務(wù)分配視圖轿偎。
幾種重要的軟件質(zhì)量屬性
易于修改維護(hù)(Modifiability)
良好的性能表現(xiàn)(Performance)
安全性(Security)
可靠性(Reliability)
健壯性(Robustness)
易用性(Usability)
商業(yè)目標(biāo)(Business goals)
第五章典鸡、軟件危機和軟件過程
?? 軟件危機
????????他體會到開發(fā)大型軟件過程中的根本問題是難以匯集眾多參與人員的設(shè)計理念形成完整的、一致的軟件復(fù)雜概念結(jié)構(gòu)坏晦,從而使得大型軟件項目往往會進(jìn)展緩慢萝玷、成本暴漲及錯誤百出,就是所謂的軟件危機(software
crisis)的典型表現(xiàn)昆婿。
????????沒有銀彈
?? 軟件過程模型
?????????? 2.1.軟件的生命周期概述
????????????????我們將軟件的生命周期劃分為:分析球碉、設(shè)計、實現(xiàn)仓蛆、交付和維護(hù)這么五個階段
?????????? 2.2.瀑布模型
????????????????因為瀑布模型假定需求不會發(fā)生任何變化睁冬。由此看來,瀑布模型將軟件開發(fā)過程看作類似于工業(yè)生產(chǎn)制造的過程多律,而不是一個創(chuàng)造性的開發(fā)過程痴突。
?????????? 2.3.帶原型的瀑布模型
?????????? 2.4.V模型
????????????????V模型也是在瀑布模型基礎(chǔ)上發(fā)展出來的,我們發(fā)現(xiàn)單元測試狼荞、集成測試和系統(tǒng)測試是為了在不同層面驗證設(shè)計辽装,而交付測試則是確認(rèn)需求是否得到滿足。也就是瀑布模型中前后兩端的過程活動具有內(nèi)在的緊密聯(lián)系相味,如果將模塊化設(shè)計的思想拿到軟件開發(fā)過程活動的組織中來拾积,可以發(fā)現(xiàn)通過將瀑布模型前后兩端的過程活動結(jié)合起來,可以提高過程活動的內(nèi)聚度丰涉,從而改善軟件開發(fā)效率拓巧。這就是V模型
?????????? 2.5.分階段增量和迭代
?????????? 2.6.螺旋模型
????????????????螺旋模型最大的特點在于引入了其他模型不具備的風(fēng)險管理,使軟件在無法排除重大風(fēng)險時有機會停止
?? PSP和TSP
??CMM/CMMI
?????CMMI一級一死,初始級肛度。沒有包含任何過程域。
?????CMMI二級投慈,管理級承耿。包含的過程域有需求管理 RM冠骄、項目計劃PP、項目監(jiān)督與控制PMC加袋、供應(yīng)協(xié)議管理SAM凛辣、過程與產(chǎn)品質(zhì)量保證PPQA、配置管理CM和度量與分析 MA职烧。
?????CMMl三級扁誓,已定義級。包含的過程域有需求制定RD蚀之、技術(shù)方案TS蝗敢、產(chǎn)品集成PI、驗證VER恬总、確認(rèn)VAL前普、組織過程聚焦OPF、組織過程定義OPD壹堰、組織培訓(xùn)OT拭卿、集成項目管理IPM、風(fēng)險管理RSKM贱纠、決策分析與決定DAR峻厚、集成供應(yīng)商管理ISM、組織集成環(huán)境OEI和集成組隊IT谆焊。
?????CMMI四級惠桃,量化管理級。包含的過程域有組織過程性能OPP和定量項目管理QPM辖试。
?????CMMI五級辜王,持續(xù)優(yōu)化級。包含的過程域有組織革新與部署OID和原因分析與決策CAR罐孝。
?? 敏捷方法
?我們一直在實踐中探尋更好的軟件開發(fā)方法呐馆,身體力行的同時也幫助他人。由此我們建立了如下價值觀:
? ?? 個體和互動 高于 流程和工具
?? 工作的軟件 高于 詳盡的文檔
? ?? 客戶合作 高于 合同談判
? ?? 響應(yīng)變化 高于 遵循計劃
?? DevOps
學(xué)習(xí)感想:
????????一款軟件的需求分析在設(shè)計之初尤為重要莲兢,這是地基初肉。所以我們在“考勤助手”的設(shè)計當(dāng)中也是盡可能地把用戶的需求完善膝藕,做到每個用戶各司其職。結(jié)合需求分析的ER圖的設(shè)計其實是比較復(fù)雜的隘梨,因為必須要考慮清楚每個實體集之間的聯(lián)系情況氨淌,是多對多拼苍、多對一等等玖姑。其次是用例圖端朵,如果需求能夠定好,那用例圖的設(shè)計自然不會太難承疲。最后就是時序圖和類圖酣溃,其實從ER圖開始瘦穆,我認(rèn)為接下來的時序圖和UML類圖也同樣需要對敲和斟酌纪隙,一個小的疏忽可能在設(shè)計的某個時刻被發(fā)現(xiàn)赊豌,從而帶來“翻天覆地”的變化,所以需要不斷地返工和完善這兩項設(shè)計绵咱。