Big Ben

一个半吊子的编码爱好者

0%

Edit

Linear Regression

Linear Regression = 线性回归。

Single Feature Hypothesis:

通过求cost function的最小值,来估算
列出单feature的cost function,不做多介绍。重点放在Multiple Feature Linear Regression。

Cost Function:

Cost Function & Gradient Descent

Multiple Feature Hypothesis:

Multiple Feature Cost Function:

Gradient Descent:

  • j := 0…m
  • - Learning rate.

How to choose learning rate - ?

  • If is too small: slow convergence
  • If is too large: J() may not decrease on every iteration; may not converge.

To choose , try:
…, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, …
每次取3倍。

Feature Scaling

We can speed up gradient descent by having each of our input values in roughly the same range. This is because θ will descend quickly on small ranges and slowly on large ranges, and so will oscillate inefficiently down to the optimum when the variables are very uneven.

用下面的公式预处理我们的training set,就是Feature Scaling

  • is the average of all the values for feature (i)
  • is the range of values (max - min)
  • or is the standard deviation.

* standard deviation (标准差)=

Normal Equation正规解

  • 注1:training set的数量要大于feature数量,否则会不可逆,导致没有解
  • 注2:正规解不需要feature scaling

Logistic Regression

Hypothesis:

Sigmoid Function / Logistic Function

The following image shows us what the sigmoid function looks like:

这里的Hypothesis方程是不平滑的,会导致很多的local optimization,导致Gradient Descent不能成功收敛。

用条件概率表示Hypothesis:
y=1的条件下,x,的取值概率。

Cost Function



这其中用Cost函数取代了线性回归中的

将Cost函数代入整个Cost Function中可得:

Vectorized implementation:

进一步计算Gradient Descent的迭代算法为:

矢量化写法:

Overfitting过拟合

Regularized Linear Regression

The λ, or lambda, is the regularization parameter. It determines how much the costs of our theta parameters are inflated.

Regularized Logistic Regression

The second sum, means to explicitly exclude the bias term

!!注意:这里的regularized项,不包含,如果在Matlab/Octave中就是

%23Machine%20Learning%20%281%29%20-%20Linear%20%26%20Logistic%20Regression%0A%0A@%28%u5B66%u4E60%u7B14%u8BB0%29%0A%0A%0A%5BTOC%5D%0A%0A%21%5BAlt%20text%5D%28./1491028424509.png%29%0A%0A%23%23Linear%20Regression%0ALinear%20Regression%20%3D%20%u7EBF%u6027%u56DE%u5F52%u3002%0A%0ASingle%20Feature%20**Hypothesis**%3A%0A%24%24h_%7B%5Ctheta%7D%28x%29%20%20%3D%20%5Ctheta_%7B0%7D%20+%20%5Ctheta_%7B1%7Dx%24%24%0A%u901A%u8FC7%u6C42cost%20function%u7684%u6700%u5C0F%u503C%uFF0C%u6765%u4F30%u7B97%24%5Ctheta_%7Bi%7D%24%u3002%0A%u5217%u51FA%u5355feature%u7684cost%20function%uFF0C%u4E0D%u505A%u591A%u4ECB%u7ECD%u3002%u91CD%u70B9%u653E%u5728Multiple%20Feature%20Linear%20Regression%u3002%0A%0A**Cost%20Function**%3A%0A%24%24J%28%5Ctheta%29%20%3D%20%5Cdfrac%20%7B1%7D%7B2m%7D%20%5Csum_%7Bi%3D1%7D%5Em%20%28h_%5Ctheta%28x_%7Bi%7D%29%20-%20y_%7Bi%7D%29%5E2%24%24%0A%0A%23%23%23Cost%20Function%20%26%20Gradient%20Descent%0AMultiple%20Feature%20**Hypothesis**%3A%0A%24%24h_%5Ctheta%28x%29%20%3D%20%5Cbegin%20%7Bbmatrix%7D%5Ctheta_0%20%5Chspace%7B1em%7D%20%5Ctheta_1%20%5Chspace%7B1em%7D...%20%5Chspace%7B1em%7D%5Ctheta_n%20%5Cend%7Bbmatrix%7D%20%5Cbegin%7Bbmatrix%7Dx_0%20%5Cnewline%20x_1%20%5Cnewline%20%5Cvdots%20%5Cnewline%20x_n%5Cend%7Bbmatrix%7D%20%3D%20%5Ctheta%5ETx%24%24%0A%0AMultiple%20Feature%20**Cost%20Function**%3A%0A%24%24J%28%5Ctheta%29%20%3D%20%5Cdfrac%20%7B1%7D%7B2m%7D%5Csum_%7Bi%3D1%7D%5Em%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29-y%5E%7B%28i%29%7D%29%5E2%24%24%0A%0AGradient%20Descent%3A%0A%24%24%5Ctheta_j%20%3A%3D%20%5Ctheta_j%20-%20%5Calpha%5Cdfrac%20%7B%5Cpartial%7D%7B%5Cpartial%5Ctheta_j%7D%20J%28%5Ctheta%29%20%3D%20%5Ctheta_j%20-%20%5Calpha%5Cdfrac%20%7B1%7D%7Bm%7D%5Csum_%7Bi%3D1%7D%5Em%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29%20-%20y%5E%7B%28i%29%7D%29%5Ccenterdot%20x_j%5E%7B%28i%29%7D%24%24%20%0A-%20j%20%3A%3D%200...m%0A-%20%24%5Calpha%24%20-%20Learning%20rate.%0A%0A%23%23%23How%20to%20choose%20learning%20rate%20-%20%24%5Calpha%24%20%3F%0A-%20If%20%24%5Calpha%24%20is%20too%20small%3A%20slow%20convergence%0A-%20If%20%24%5Calpha%24%20is%20too%20large%3A%20J%28%24%5Ctheta%24%29%20may%20not%20decrease%20on%20every%20iteration%3B%20may%20not%20converge.%0A%0ATo%20choose%20%24%5Calpha%24%2C%20try%3A%0A%09...%2C%200.001%2C%200.003%2C%200.01%2C%200.03%2C%200.1%2C%200.3%2C%201%2C%20...%0A%u6BCF%u6B21%u53D63%u500D%u3002%0A%0A%23%23%23Feature%20Scaling%0A%3EWe%20can%20speed%20up%20gradient%20descent%20by%20having%20each%20of%20our%20input%20values%20in%20**roughly%20the%20same%20range**.%20This%20is%20because%20%u03B8%20will%20descend%20quickly%20on%20small%20ranges%20and%20slowly%20on%20large%20ranges%2C%20and%20so%20will%20oscillate%20inefficiently%20down%20to%20the%20optimum%20when%20the%20variables%20are%20very%20uneven.%0A%0A%u7528%u4E0B%u9762%u7684%u516C%u5F0F%u9884%u5904%u7406%u6211%u4EEC%u7684training%20set%uFF0C%u5C31%u662FFeature%20Scaling%0A%24%24x_i%20%3A%3D%20%5Cdfrac%7Bx_i%20-%20%5Cmu_i%7D%7Bs_i%7D%20%24%24%0A-%20%24%5Cmu_i%24%20is%20the%20average%20of%20all%20the%20values%20for%20feature%20%28i%29%0A-%20%24s_i%24%20is%20the%20range%20of%20values%20%28max%20-%20min%29%0A-%20**or**%20%24s_i%24%20is%20the%20standard%20deviation.%0A%0A%5C*%20*standard%20deviation%20%28%u6807%u51C6%u5DEE%29%3D%20%24%5Csqrt%7B%5Cdfrac%7B1%7D%7BN%7D%5Csum_%7Bi%3D1%7D%5EN%28x_i%20-%20%5Cmu%292%7D%24*%0A%0A%23%23%23Normal%20Equation%u6B63%u89C4%u89E3%0A%24%24%5Ctheta%20%3D%20%28X%5ETX%29%5E%7B-1%7DX%5ETy%24%24%0A*%20%u6CE81%uFF1Atraining%20set%u7684%u6570%u91CF%u8981%u5927%u4E8Efeature%u6570%u91CF%uFF0C%u5426%u5219%24X%5ETX%24%u4F1A%u4E0D%u53EF%u9006%uFF0C%u5BFC%u81F4%u6CA1%u6709%u89E3%0A*%20%u6CE82%uFF1A%u6B63%u89C4%u89E3%u4E0D%u9700%u8981feature%20scaling%0A%0A%23%23Logistic%20Regression%0A**Hypothesis**%3A%0A%24%24h_%5Ctheta%28x%29%20%3D%20g%28%5Ctheta%5ETx%29%24%24%0A**Sigmoid%20Function%20/%20Logistic%20Function**%0A%24%24g%28z%29%20%3D%20%5Cdfrac%20%7B1%7D%7B1+e%5E%7B-z%7D%7D%24%24%0A%24z%20%3D%20%5Ctheta%5ETx%24%0A%0AThe%20following%20image%20shows%20us%20what%20the%20sigmoid%20function%20looks%20like%3A%0A%21%5BAlt%20text%5D%28./1491033397652.png%29%0A%0A%u8FD9%u91CC%u7684Hypothesis%u65B9%u7A0B%u662F%u4E0D%u5E73%u6ED1%u7684%uFF0C%u4F1A%u5BFC%u81F4%u5F88%u591A%u7684local%20optimization%uFF0C%u5BFC%u81F4Gradient%20Descent%u4E0D%u80FD%u6210%u529F%u6536%u655B%u3002%0A%0A%u7528%u6761%u4EF6%u6982%u7387%u8868%u793AHypothesis%3A%0Ay%3D1%u7684%u6761%u4EF6%u4E0B%uFF0Cx%2C%24%5Ctheta%24%u7684%u53D6%u503C%u6982%u7387%u3002%0A%24%24h_%5Ctheta%28x%29%3DP%28y%3D1%5Cmid%20x%3B%u03B8%29%3D1%u2212P%28y%3D0%20%5Cmid%20x%3B%u03B8%29%24%24%0A%24%24P%28y%3D0%20%5Cmid%20x%3B%u03B8%29+P%28y%3D1%20%5Cmid%20x%3B%u03B8%29%3D1%24%24%0A%0A%0A%0A%23%23%23%20Cost%20Function%0A%24%24J%28%5Ctheta%29%20%3D%20-%5Cdfrac%20%7B1%7D%7Bm%7D%20%5Csum_%7Bi%3D1%7D%5EmCost%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29%2C%20y%5E%7B%28i%29%7D%29%24%24%0A%24%24Cost%28h_%5Ctheta%28x%29%2C%20y%29%29%20%3D%20-log%28h_%5Ctheta%28x%29%29%20%20%5Chspace%7B10em%7Dif%20y%20%3D%201%24%24%0A%24%24Cost%28h_%5Ctheta%28x%29%2C%20y%29%29%20%3D%20-log%281-h_%5Ctheta%28x%29%29%20%5Chspace%7B8em%7D%20if%20y%20%3D%200%24%24%0A%0A%24Cost%28h_%5Ctheta%28x%29%2C%20y%29%29%20%3D%200%20%5Chspace%7B3em%7D%20if%20%5Chspace%7B1em%7D%20h_%5Ctheta%28x%29%20%3D%20y%24%0A%24Cost%28h_%5Ctheta%28x%29%2C%20y%29%29%20%5Crightarrow%20%5Cinfty%20%5Chspace%7B2em%7D%20if%20y%3D0%20%5Chspace%7B0.5em%7D%20and%20%5Chspace%7B0.5em%7D%20h_%5Ctheta%28x%29%20%5Crightarrow%201%24%0A%24Cost%28h_%5Ctheta%28x%29%2C%20y%29%29%20%5Crightarrow%20%5Cinfty%20%5Chspace%7B2em%7D%20if%20y%3D1%20%5Chspace%7B0.5em%7D%20and%20%5Chspace%7B0.5em%7D%20h_%5Ctheta%28x%29%20%5Crightarrow%200%24%0A%0A%u8FD9%u5176%u4E2D%u7528Cost%u51FD%u6570%u53D6%u4EE3%u4E86%u7EBF%u6027%u56DE%u5F52%u4E2D%u7684%24%5Cdfrac%20%7B1%7D%7B2%7D%28h_%5Ctheta%28x_i%29-y_i%29%5E2%24%0A%0A%u5C06Cost%u51FD%u6570%u4EE3%u5165%u6574%u4E2ACost%20Function%u4E2D%u53EF%u5F97%uFF1A%0A%24J%28%5Ctheta%29%20%3D%20-%5Cdfrac%20%7B1%7D%7Bm%7D%5Csum_%7Bi%3D1%7D%5Em%5By%5E%7B%28i%29%7Dlog%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29%29%20+%20%281-y%5E%7B%28i%29%7D%29log%281-h_%5Ctheta%28x%5E%7B%28i%29%7D%29%29%5D%24%0A%0A**Vectorized%20implementation**%3A%0A%24h%3Dg%28X%5Ctheta%29%20%3D%20%5Cdfrac%20%7B1%7D%7B1+e%5E%7B-%5Ctheta%5ETx%7D%7D%24%0A%24J%28%5Ctheta%29%20%3D%20%5Cdfrac%20%7B1%7D%7Bm%7D%5Ccenterdot%20%28-y%5ETlog%28h_%5Ctheta%29-%281-y%29%5ETlog%281-h_%5Ctheta%29%29%24%0A%0A%u8FDB%u4E00%u6B65%u8BA1%u7B97Gradient%20Descent%u7684%u8FED%u4EE3%u7B97%u6CD5%u4E3A%uFF1A%0A%24%24%5Ctheta_j%20%3A%3D%20%5Ctheta_j%20-%20%5Cdfrac%20%7B%5Calpha%7D%7Bm%7D%5Csum_%7Bi%3D1%7D%5Em%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29-y%5E%7B%28i%29%7D%29%5Ccenterdot%20x_j%5E%7B%28i%29%7D%24%24%0A%0A%u77E2%u91CF%u5316%u5199%u6CD5%uFF1A%0A%24%24%5Ctheta%20%3A%3D%20%5Ctheta%20-%20%5Cdfrac%7B%5Calpha%7D%7Bm%7DX%5ET%28g%28X%5Ctheta%29%20-%20%5Cvec%7By%7D%29%24%24%0A%0A%23%23Overfitting%u8FC7%u62DF%u5408%0A%23%23%23Regularized%20Linear%20Regression%0A%24%24J%28%5Ctheta%29%20%3D%20%5Cdfrac%7B1%7D%7B2m%7D%5Csum_%7Bi%3D1%7D%5Em%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29-y%5E%7Bi%7D%29%5E2+%5Clambda%5Csum_%7Bj%3D1%7D%5En%5Ctheta_j%5E2%24%24%0A%3EThe%20%u03BB%2C%20or%20lambda%2C%20is%20the%20regularization%20parameter.%20It%20determines%20how%20much%20the%20costs%20of%20our%20theta%20parameters%20are%20inflated.%0A%23%23%23Regularized%20Logistic%20Regression%0A%24%24J%28%5Ctheta%29%20%3D%20-%5Cdfrac%20%7B1%7D%7Bm%7D%5Csum_%7Bi%3D1%7D%5Em%5By%5E%7B%28i%29%7Dlog%28h_%5Ctheta%28x%5E%7B%28i%29%7D%29%29%20+%20%281-y%5E%7B%28i%29%7D%29log%281-h_%5Ctheta%28x%5E%7B%28i%29%7D%29%29%5D%20+%20%5Cdfrac%20%7B%5Clambda%7D%7B2m%7D%5Csum_%7Bj%3D1%7D%5En%5Ctheta_j%5E2%24%24%0AThe%20second%20sum%2C%24%5Csum_%7Bj%3D1%7D%5En%5Ctheta_j%5E2%24%20means%20to%20**explicitly%20exclude%20the%20bias%20term**%20%24%5Ctheta_0%24%0A%0A%21%21%u6CE8%u610F%uFF1A%u8FD9%u91CC%u7684regularized%u9879%uFF0C%u4E0D%u5305%u542B%24%5Ctheta_0%24%uFF0C%u5982%u679C%u5728Matlab/Octave%u4E2D%u5C31%u662F%24%5Ctheta_1%24%u3002

Edit


本篇从这里开始
跟我一起学习VIM - The Life Changing Editor
然后到这里进入高潮
spf13/spf13-vim
第一篇看似是一篇普普通通介绍Vim插件的博客文。但是他在介绍一些顶级插件的同时,引入了spf13这个GitHub上的开源项目。这其实就是一个很全的vimrc配置。玩家可以根据自己的需求进行定制。这一下打开了潘多拉魔盒,本来怕麻烦折腾的我,一下就入坑了。

" Use fork vimrc if available {
if filereadable(expand("~/.vimrc.fork"))
source ~/.vimrc.fork
endif
" }

" Use local vimrc if available {
if filereadable(expand("~/.vimrc.local"))
source ~/.vimrc.local
endif
" }

" Use local gvimrc if available and gui is running {
if has('gui_running')
if filereadable(expand("~/.gvimrc.local"))
source ~/.gvimrc.local
endif
endif
" }
  • .vimrc.before - spf13-vim before configuration
  • .vimrc.before.fork - fork before configuration
  • .vimrc.before.local - before user configuration
  • .vimrc.bundles - spf13-vim bundle configuration
  • .vimrc.bundles.fork - fork bundle configuration
  • .vimrc.bundles.local - local user bundle configuration
  • .vimrc - spf13-vim vim configuration
  • .vimrc.fork - fork vim configuration
  • .vimrc.local - local user configuration

低端玩家可以用.vimrc.*.local来做本地化定制,高端玩家可以fork repo,然后添加自己的.vimrc.*.fork做定制,然后commit,然后所有你的Vim环境就都可以用到这一份配置了。
完工后的Vim看起来这样

问题

powerline fonts

Windows

要完成这样的效果,最纠结的就是powerline的字体。如果字体不正确,是没法出现这样的小尖角样式的。

" .vimrc.bundles
Bundle 'powerline/fonts'

所有的字体文件都被安装到$HOME\.vim\bundle\fonts\。然后我们再调用其中的power script脚本install.ps1,就会安装到系统字体目录。然后在Vim中选择对应的字体就好了。

Linux

在Linux,尤其是通过putty访问Linux的时候就没这么简单了。因为我全是用putty ssh访问Linux,所以一开始以为是putty的问题,网上搜出来一堆,都是这样的解释。

  1. Download the patched fonts. I chose DejaVuSansMono as my font since I like it most.
  2. Install this font in Windows to make it accessible for all programs.
  3. Open PuTTY and make changes to the settings:
  4. Under appearance select the patched font
  5. Select font quality Clear Type
  6. Under Translation select character set UTF-8
  7. Apply settings and restart the PuTTY session

但按照这样做完,却并不起效果。后来发现在Linux本机的图形界面下用Terminal开Vim也是一样的情况。
在终端的profile中配置字体还是一样,没有效果。
然后找到Powerline的官方文档——Powerline

  1. Move the patched font to a valid X font path. Valid font paths can be listed with xset q:

    mv 'SomeFont for Powerline.otf' ~/.fonts/

  2. Update font cache for the path the font was moved to (root priveleges may be needed for updating font cache for some paths):

    fc-cache -vf ~/.fonts/

颇受启发。
经过分析,得出原因是:

  1. Linux的桌面系统分为GNome,KDE等等。不同 的桌面系统所采用的字体目录是不同的。我们目前采用的字体目录在
[benzhou@plslx111 phx]$ xset q|grep font
catalogue:/etc/X11/fontpath.d,built-ins
  1. 不同的桌面环境也对应不同的终端,比如我们目前使用的就是KDE下的Konsole。
  2. 修改install.sh,将字体安装到对应的字体目录下,并刷新字体缓存
  3. 配置好Konsole
  4. putty下面一切完美

Update - 20170606
Linux上的字体安装始终不成功,在Terminal里面无法找到powerline字体。
最后的解决办法是,字体安装目录在/usr/share/fonts。把~/.vim/bundles/fonts/install.sh中的font_dir设置为对应的路径,再运行就OK了

字体问题

Windows下使用Courier New字体感觉怪怪的,原因是设置了let g:spf13_no_big_font,但因为后面采用了Source Code Pro for Powerline字体,所以就还是保持1。

neocomplete不支持

装完spf13并没有深究每一个插件的用法,偶尔看到对neocomplete的推荐,所以想试一试。在命令行中输入:NeoCompleteEnable,发现竟然不支持,原来neocomplete需要Vim对lua的支持。有两条路可以走:

  1. 安装vim-nox/vim-athena/vim-gtk/vim-gnome其中之一
  2. 自行编译Vim,并使能lua支持
    因为我们使用的发行版过于陈旧,上面提到的四个包都没有,所以只能走第二条路了。
    命令只有两条:
[benzhou@plslx111 vim]$ ./configure  --enable-rubyinterp \
--enable-pythoninterp \
--with-python-config-dir=/usr/bin/python2.6-config \ # 这一行python的配置也要对
--enable-perlinterp \
--enable-gui=gtk2 \
--enable-cscope \
--prefix=/usr/local \
--enable-luainterp \ # 下面两行最重要
--with-lua-prefix=/usr/bn #
[benzhou@plslx111 vim]$ make

编译Vim,在configure的时候,发现找不到lua的头文件,搜索一番,原因是没有安装lua-devel的包,于是在网上找了一个Fedora的RPM包,运行rpm -i安装,再configure就成了。
打开Vim命令行,运行echo has("lua"),结果是1,就大功告成了。

Error 523

在写Vim脚本的时候,一个很简单的函数出现了E523: Not allowed here。最后查明原因是在被map的命令中不能调用execute和normal函数,据说是为了安全。详情查看:help e523。下面是错误的.vimrc代码

function CscopeFind()
execute "cscope add cscope.out"
endfunction

nmap <space>s :<C-R>=CscopeFind()<CR>cscope find s <C-R>=expand('<cword>')<CR>

if 判断字符串

这是一个坑,和Python等主流语言不同,Vim脚本里,if后面的字符串会被强制转换成bool变量,再进行判断。而字符串对应的bool值为0。所以下面的echo语句永远也执行不到。

if (glob('/existing/file'))
echo ('yes')
endif

正确的写法应当是

if (!empty(glob('...'))
...
endif

插件

ctrlP

有了这个插件,cscope find f就没啥大用了。看官网的基本用法:

  • Press <F5> to purge the cache for the current directory to get new files, remove deleted files and apply new ignore options.
  • Press <c-f> and <c-b> to cycle between modes. (Ben: 在搜索文件,buffer, funky之间循环跳转)
  • Press <c-d> to switch to filename only search instead of full path. (Ben: 这个对于我比较有用,因为我们的路径太长)
  • Press <c-r> to switch to regexp mode.
  • Use <c-j>, <c-k> or the arrow keys to navigate the result list.
  • Use <c-t> or <c-v>, <c-x> to open the selected entry in a new tab or in a new split.
  • Use <c-n>, <c-p> to select the next/previous string in the prompt’s history.
  • Use <c-y> to create a new file and its parent directories.
  • Use <c-z> to mark/unmark multiple files and to open them.

目前我的配置

  • <leader>-f: 模糊搜索最近打开的文件(MRU)
  • <leader>-p: 模糊搜索当前目录及其子目录下的所有文件
  • <leader>fu: 进入当前文件的函数列表搜索
  • <leader>fU: 搜索当前光标下单词对应的函数

neocomplete

omni-complete

这是在Vim 7.0引入的自动补全功能,不依赖于任何插件。在没有neocomplete的时候,比如Windows下装neocomplete和ycm都很麻烦,就只能用原生的补全。其实也够用了,只是没有那么方便。
所有帮助命令入口:

:help ins-completion
:help compl-omni
:help ‘omnifunc’
:help i_CTRL-X_CTRL-O
:help ins-completion-menu
:help popupmenu-keys
:help ‘completeopt’
:help compl-omni-filetypes
:help omnicppcomplete.txt

看spf13的.vimrc中有这么一句:Automatically open and close the popup menu / preview window
本来以为omni-complete会像neocomplete一样自动弹出下拉菜单,但是经过一番Google和help研读。这个理解是错误的。

  • <C-N>/<C-P> 这就不提了,最基本的功能,N=next,P=previous
  • <CTRL-K> 字典补全,查询dictionary参数中对应的文件,进行补全
  • <CTRL-I> 当前文件和包含文件补全,I=include
  • <CTRL-]> tag补全
  • <CTRL-F> 文件名补全
  • <CTRL-D> 宏补全
  • <CTRL-V> Vim命令补全,V=Vim
  • <CTRL-U> User defined补全,U=User,补全函数通过set completefunc=xxx传入
  • <CTRL-O> omni补全,O=Omni,补全函数通过set omnifunc=xxx传入,这个Vim自带的脚本都已写好,spf13的vimrc也有参考设置了

UltiSnips

在折腾半天snipMate无果的情况下,转投UltiSnips。语法复杂度以及灵活性要强于snipMate。注意以下几点即可

  • UltiSnips搜索所有runtimepath下的UltiSnips目录中的.snippet结尾的文件
  • UltiSnips通过一个全局变量决定是否支持snipMate
  • UltiSnips用<tab>补全,与omni-complete冲突,不过omni-complete还有一种用法是<C-N>/<C-P>来切换选项,也凑合能用了
%23Vim%u7EC8%u6781%u6298%u817E%0A@%28%u5B66%u4E60%u7B14%u8BB0%29%5Bvim%5D%0A%u672C%u7BC7%u4ECE%u8FD9%u91CC%u5F00%u59CB%0A%5B%u8DDF%u6211%u4E00%u8D77%u5B66%u4E60VIM%20-%20The%20Life%20Changing%20Editor%5D%28http%3A//ju.outofmemory.cn/entry/79671%29%0A%u7136%u540E%u5230%u8FD9%u91CC%u8FDB%u5165%u9AD8%u6F6E%0A%5Bspf13/spf13-vim%5D%28https%3A//github.com/spf13/spf13-vim%29%0A%u7B2C%u4E00%u7BC7%u770B%u4F3C%u662F%u4E00%u7BC7%u666E%u666E%u901A%u901A%u4ECB%u7ECDVim%u63D2%u4EF6%u7684%u535A%u5BA2%u6587%u3002%u4F46%u662F%u4ED6%u5728%u4ECB%u7ECD%u4E00%u4E9B%u9876%u7EA7%u63D2%u4EF6%u7684%u540C%u65F6%uFF0C%u5F15%u5165%u4E86spf13%u8FD9%u4E2AGitHub%u4E0A%u7684%u5F00%u6E90%u9879%u76EE%u3002%u8FD9%u5176%u5B9E%u5C31%u662F%u4E00%u4E2A%u5F88%u5168%u7684vimrc%u914D%u7F6E%u3002%u73A9%u5BB6%u53EF%u4EE5%u6839%u636E%u81EA%u5DF1%u7684%u9700%u6C42%u8FDB%u884C%u5B9A%u5236%u3002%u8FD9%u4E00%u4E0B%u6253%u5F00%u4E86%u6F58%u591A%u62C9%u9B54%u76D2%uFF0C%u672C%u6765%u6015%u9EBB%u70E6%u6298%u817E%u7684%u6211%uFF0C%u4E00%u4E0B%u5C31%u5165%u5751%u4E86%u3002%0A%21%5BAlt%20text%5D%28./1490225064940.png%29%0A%u9488%u5BF9%u5404%u4E2A%u63D2%u4EF6%u7684%u914D%u7F6E%u90FD%u7528fold%u5904%u7406%u597D%u4E86%uFF0C%u4E00%u76EE%u4E86%u7136%u3002%u4F5C%u8005%u4E5F%u63D0%u4F9B%u597D%u4E86%u5B9A%u5236%u7684%u63A5%u53E3%0A%60%60%60%0A%22%20Use%20fork%20vimrc%20if%20available%20%7B%0A%20%20%20%20if%20filereadable%28expand%28%22%7E/.vimrc.fork%22%29%29%0A%20%20%20%20%20%20%20%20source%20%7E/.vimrc.fork%0A%20%20%20%20endif%0A%22%20%7D%0A%0A%22%20Use%20local%20vimrc%20if%20available%20%7B%0A%20%20%20%20if%20filereadable%28expand%28%22%7E/.vimrc.local%22%29%29%0A%20%20%20%20%20%20%20%20source%20%7E/.vimrc.local%0A%20%20%20%20endif%0A%22%20%7D%0A%0A%22%20Use%20local%20gvimrc%20if%20available%20and%20gui%20is%20running%20%7B%0A%20%20%20%20if%20has%28%27gui_running%27%29%0A%20%20%20%20%20%20%20%20if%20filereadable%28expand%28%22%7E/.gvimrc.local%22%29%29%0A%20%20%20%20%20%20%20%20%20%20%20%20source%20%7E/.gvimrc.local%0A%20%20%20%20%20%20%20%20endif%0A%20%20%20%20endif%0A%22%20%7D%0A%60%60%60%0A-%20.vimrc.before%20-%20spf13-vim%20before%20configuration%0A-%20.vimrc.before.fork%20-%20fork%20before%20configuration%0A-%20.vimrc.before.local%20-%20before%20user%20configuration%0A-%20.vimrc.bundles%20-%20spf13-vim%20bundle%20configuration%0A-%20.vimrc.bundles.fork%20-%20fork%20bundle%20configuration%0A-%20.vimrc.bundles.local%20-%20local%20user%20bundle%20configuration%0A-%20.vimrc%20-%20spf13-vim%20vim%20configuration%0A-%20.vimrc.fork%20-%20fork%20vim%20configuration%0A-%20.vimrc.local%20-%20local%20user%20configuration%0A%0A%u4F4E%u7AEF%u73A9%u5BB6%u53EF%u4EE5%u7528.vimrc.*.local%u6765%u505A%u672C%u5730%u5316%u5B9A%u5236%uFF0C%u9AD8%u7AEF%u73A9%u5BB6%u53EF%u4EE5fork%20repo%uFF0C%u7136%u540E%u6DFB%u52A0%u81EA%u5DF1%u7684.vimrc.%5C*.fork%u505A%u5B9A%u5236%uFF0C%u7136%u540Ecommit%uFF0C%u7136%u540E%u6240%u6709%u4F60%u7684Vim%u73AF%u5883%u5C31%u90FD%u53EF%u4EE5%u7528%u5230%u8FD9%u4E00%u4EFD%u914D%u7F6E%u4E86%u3002%0A%u5B8C%u5DE5%u540E%u7684Vim%u770B%u8D77%u6765%u8FD9%u6837%0A%21%5BAlt%20text%5D%28./1490225459173.png%29%0A%0A%23%23%20%u95EE%u9898%0A%23%23%23powerline%20fonts%0A%23%23%23%23Windows%0A%u8981%u5B8C%u6210%u8FD9%u6837%u7684%u6548%u679C%uFF0C%u6700%u7EA0%u7ED3%u7684%u5C31%u662Fpowerline%u7684%u5B57%u4F53%u3002%u5982%u679C%u5B57%u4F53%u4E0D%u6B63%u786E%uFF0C%u662F%u6CA1%u6CD5%u51FA%u73B0%u8FD9%u6837%u7684%u5C0F%u5C16%u89D2%u6837%u5F0F%u7684%u3002%0A%21%5BAlt%20text%5D%28./1490235175286.png%29%0A%u5B9E%u73B0%u8FD9%u4E2A%u6837%u5F0F%u7684%u63D2%u4EF6%u662F%60vim-airline%60%u3002%u5B83%u4F9D%u8D56%u4E8Epowerline%20fonts%u3002%u5728Windows%u4E0B%u8FD8%u662F%u6BD4%u8F83%u597D%u89E3%u51B3%u7684%u3002spf13%u5DF2%u7ECF%u5E2E%u6211%u4EEC%u88C5%u597D%u4E86powerline-fonts%u3002%0A%60%60%60%0A%22%20.vimrc.bundles%0ABundle%20%27powerline/fonts%27%0A%60%60%60%0A%u6240%u6709%u7684%u5B57%u4F53%u6587%u4EF6%u90FD%u88AB%u5B89%u88C5%u5230%60%24HOME%5C.vim%5Cbundle%5Cfonts%5C%60%u3002%u7136%u540E%u6211%u4EEC%u518D%u8C03%u7528%u5176%u4E2D%u7684power%20script%u811A%u672C%60install.ps1%60%uFF0C%u5C31%u4F1A%u5B89%u88C5%u5230%u7CFB%u7EDF%u5B57%u4F53%u76EE%u5F55%u3002%u7136%u540E%u5728Vim%u4E2D%u9009%u62E9%u5BF9%u5E94%u7684%u5B57%u4F53%u5C31%u597D%u4E86%u3002%0A%23%23%23%23Linux%0A%u5728Linux%uFF0C%u5C24%u5176%u662F%u901A%u8FC7putty%u8BBF%u95EELinux%u7684%u65F6%u5019%u5C31%u6CA1%u8FD9%u4E48%u7B80%u5355%u4E86%u3002%u56E0%u4E3A%u6211%u5168%u662F%u7528putty%20ssh%u8BBF%u95EELinux%uFF0C%u6240%u4EE5%u4E00%u5F00%u59CB%u4EE5%u4E3A%u662Fputty%u7684%u95EE%u9898%uFF0C%u7F51%u4E0A%u641C%u51FA%u6765%u4E00%u5806%uFF0C%u90FD%u662F%u8FD9%u6837%u7684%u89E3%u91CA%u3002%0A%3E1.%20Download%20the%20patched%20fonts.%20I%20chose%20DejaVuSansMono%20as%20my%20font%20since%20I%20like%20it%20most.%0A%3E2.%20Install%20this%20font%20in%20Windows%20to%20make%20it%20accessible%20for%20all%20programs.%0A%3E3.%20Open%20PuTTY%20and%20make%20changes%20to%20the%20settings%3A%0A%3E4.%20Under%20appearance%20select%20the%20patched%20font%0A%3E5.%20Select%20font%20quality%20Clear%20Type%0A%3E6.%20Under%20Translation%20select%20character%20set%20UTF-8%0A%3E7.%20Apply%20settings%20and%20restart%20the%20PuTTY%20session%0A%0A%u4F46%u6309%u7167%u8FD9%u6837%u505A%u5B8C%uFF0C%u5374%u5E76%u4E0D%u8D77%u6548%u679C%u3002%u540E%u6765%u53D1%u73B0%u5728Linux%u672C%u673A%u7684%u56FE%u5F62%u754C%u9762%u4E0B%u7528Terminal%u5F00Vim%u4E5F%u662F%u4E00%u6837%u7684%u60C5%u51B5%u3002%0A%u5728%u7EC8%u7AEF%u7684profile%u4E2D%u914D%u7F6E%u5B57%u4F53%u8FD8%u662F%u4E00%u6837%uFF0C%u6CA1%u6709%u6548%u679C%u3002%0A%u7136%u540E%u627E%u5230Powerline%u7684%u5B98%u65B9%u6587%u6863%u2014%u2014%5BPowerline%5D%28http%3A//powerline.readthedocs.io/en/master/installation/linux.html%23fonts-installation%29%0A%3E%201.%20Move%20the%20patched%20font%20to%20a%20valid%20X%20font%20path.%20Valid%20font%20paths%20can%20be%20listed%20with%20%60xset%20q%60%3A%0A%3E%0A%09%60mv%20%27SomeFont%20for%20Powerline.otf%27%20%7E/.fonts/%60%0A%09%0A%3E%202.%20Update%20font%20cache%20for%20the%20path%20the%20font%20was%20moved%20to%20%28root%20priveleges%20may%20be%20needed%20for%20updating%20font%20cache%20for%20some%20paths%29%3A%0A%3E%0A%09%60fc-cache%20-vf%20%7E/.fonts/%60%0A%09%0A%u9887%u53D7%u542F%u53D1%u3002%0A%u7ECF%u8FC7%u5206%u6790%uFF0C%u5F97%u51FA%u539F%u56E0%u662F%uFF1A%0A1.%20Linux%u7684%u684C%u9762%u7CFB%u7EDF%u5206%u4E3AGNome%uFF0CKDE%u7B49%u7B49%u3002%u4E0D%u540C%20%u7684%u684C%u9762%u7CFB%u7EDF%u6240%u91C7%u7528%u7684%u5B57%u4F53%u76EE%u5F55%u662F%u4E0D%u540C%u7684%u3002%u6211%u4EEC%u76EE%u524D%u91C7%u7528%u7684%u5B57%u4F53%u76EE%u5F55%u5728%0A%60%60%60bash%0A%5Bbenzhou@plslx111%20phx%5D%24%20xset%20q%7Cgrep%20font%0A%20%20catalogue%3A/etc/X11/fontpath.d%2Cbuilt-ins%0A%60%60%60%0A2.%20%u4E0D%u540C%u7684%u684C%u9762%u73AF%u5883%u4E5F%u5BF9%u5E94%u4E0D%u540C%u7684%u7EC8%u7AEF%uFF0C%u6BD4%u5982%u6211%u4EEC%u76EE%u524D%u4F7F%u7528%u7684%u5C31%u662FKDE%u4E0B%u7684Konsole%u3002%0A3.%20%u4FEE%u6539install.sh%uFF0C%u5C06%u5B57%u4F53%u5B89%u88C5%u5230%u5BF9%u5E94%u7684%u5B57%u4F53%u76EE%u5F55%u4E0B%uFF0C%u5E76%u5237%u65B0%u5B57%u4F53%u7F13%u5B58%0A4.%20%u914D%u7F6E%u597DKonsole%0A5.%20putty%u4E0B%u9762%u4E00%u5207%u5B8C%u7F8E%0A%0A%3E%20Update%20-%2020170606%0A%3E%20Linux%u4E0A%u7684%u5B57%u4F53%u5B89%u88C5%u59CB%u7EC8%u4E0D%u6210%u529F%uFF0C%u5728Terminal%u91CC%u9762%u65E0%u6CD5%u627E%u5230powerline%u5B57%u4F53%u3002%0A%3E%20%u6700%u540E%u7684%u89E3%u51B3%u529E%u6CD5%u662F%uFF0C%u5B57%u4F53%u5B89%u88C5%u76EE%u5F55%u5728/usr/share/fonts%u3002%u628A%7E/.vim/bundles/fonts/install.sh%u4E2D%u7684font_dir%u8BBE%u7F6E%u4E3A%u5BF9%u5E94%u7684%u8DEF%u5F84%uFF0C%u518D%u8FD0%u884C%u5C31OK%u4E86%0A%0A%23%23%23%u5B57%u4F53%u95EE%u9898%0AWindows%u4E0B%u4F7F%u7528Courier%20New%u5B57%u4F53%u611F%u89C9%u602A%u602A%u7684%uFF0C%u539F%u56E0%u662F%u8BBE%u7F6E%u4E86%60let%20g%3Aspf13_no_big_font%60%uFF0C%u4F46%u56E0%u4E3A%u540E%u9762%u91C7%u7528%u4E86Source%20Code%20Pro%20for%20Powerline%u5B57%u4F53%uFF0C%u6240%u4EE5%u5C31%u8FD8%u662F%u4FDD%u63011%u3002%0A%0A%23%23%23neocomplete%u4E0D%u652F%u6301%0A%u88C5%u5B8Cspf13%u5E76%u6CA1%u6709%u6DF1%u7A76%u6BCF%u4E00%u4E2A%u63D2%u4EF6%u7684%u7528%u6CD5%uFF0C%u5076%u5C14%u770B%u5230%u5BF9neocomplete%u7684%u63A8%u8350%uFF0C%u6240%u4EE5%u60F3%u8BD5%u4E00%u8BD5%u3002%u5728%u547D%u4EE4%u884C%u4E2D%u8F93%u5165%3ANeoCompleteEnable%uFF0C%u53D1%u73B0%u7ADF%u7136%u4E0D%u652F%u6301%uFF0C%u539F%u6765neocomplete%u9700%u8981Vim%u5BF9lua%u7684%u652F%u6301%u3002%u6709%u4E24%u6761%u8DEF%u53EF%u4EE5%u8D70%uFF1A%0A1.%20%u5B89%u88C5vim-nox/vim-athena/vim-gtk/vim-gnome%u5176%u4E2D%u4E4B%u4E00%0A2.%20%u81EA%u884C%u7F16%u8BD1Vim%uFF0C%u5E76%u4F7F%u80FDlua%u652F%u6301%0A%u56E0%u4E3A%u6211%u4EEC%u4F7F%u7528%u7684%u53D1%u884C%u7248%u8FC7%u4E8E%u9648%u65E7%uFF0C%u4E0A%u9762%u63D0%u5230%u7684%u56DB%u4E2A%u5305%u90FD%u6CA1%u6709%uFF0C%u6240%u4EE5%u53EA%u80FD%u8D70%u7B2C%u4E8C%u6761%u8DEF%u4E86%u3002%0A%u547D%u4EE4%u53EA%u6709%u4E24%u6761%uFF1A%0A%60%60%60bash%0A%5Bbenzhou@plslx111%20vim%5D%24%20./configure%20%20--enable-rubyinterp%20%5C%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--enable-pythoninterp%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--with-python-config-dir%3D/usr/bin/python2.6-config%20%5C%20%23%20%u8FD9%u4E00%u884Cpython%u7684%u914D%u7F6E%u4E5F%u8981%u5BF9%20%20%20%20%20%20%20%20%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--enable-perlinterp%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--enable-gui%3Dgtk2%20%5C%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--enable-cscope%20%5C%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--prefix%3D/usr/local%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--enable-luainterp%20%5C%20%20%20%20%20%20%20%20%20%20%23%20%u4E0B%u9762%u4E24%u884C%u6700%u91CD%u8981%20%0A%09%09%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20--with-lua-prefix%3D/usr/bn%20%20%20%20%20%23%0A%5Bbenzhou@plslx111%20vim%5D%24%20make%0A%60%60%60%0A%u7F16%u8BD1Vim%uFF0C%u5728configure%u7684%u65F6%u5019%uFF0C%u53D1%u73B0%u627E%u4E0D%u5230lua%u7684%u5934%u6587%u4EF6%uFF0C%u641C%u7D22%u4E00%u756A%uFF0C%u539F%u56E0%u662F%u6CA1%u6709%u5B89%u88C5lua-devel%u7684%u5305%uFF0C%u4E8E%u662F%u5728%u7F51%u4E0A%u627E%u4E86%u4E00%u4E2AFedora%u7684RPM%u5305%uFF0C%u8FD0%u884Crpm%20-i%u5B89%u88C5%uFF0C%u518Dconfigure%u5C31%u6210%u4E86%u3002%0A%u6253%u5F00Vim%u547D%u4EE4%u884C%uFF0C%u8FD0%u884C%60echo%20has%28%22lua%22%29%60%uFF0C%u7ED3%u679C%u662F1%uFF0C%u5C31%u5927%u529F%u544A%u6210%u4E86%u3002%0A%0A%23%23%23Error%20523%0A%u5728%u5199Vim%u811A%u672C%u7684%u65F6%u5019%uFF0C%u4E00%u4E2A%u5F88%u7B80%u5355%u7684%u51FD%u6570%u51FA%u73B0%u4E86%60E523%3A%20Not%20allowed%20here%60%u3002%u6700%u540E%u67E5%u660E%u539F%u56E0%u662F%u5728%u88ABmap%u7684%u547D%u4EE4%u4E2D%u4E0D%u80FD%u8C03%u7528execute%u548Cnormal%u51FD%u6570%uFF0C%u636E%u8BF4%u662F%u4E3A%u4E86%u5B89%u5168%u3002%u8BE6%u60C5%u67E5%u770B%60%3Ahelp%20e523%60%u3002%u4E0B%u9762%u662F%u9519%u8BEF%u7684.vimrc%u4EE3%u7801%0A%60%60%60%0Afunction%20CscopeFind%28%29%0A%09execute%20%22cscope%20add%20cscope.out%22%0Aendfunction%0A%0Anmap%20%3Cspace%3Es%20%3A%3CC-R%3E%3DCscopeFind%28%29%3CCR%3Ecscope%20find%20s%20%3CC-R%3E%3Dexpand%28%27%3Ccword%3E%27%29%3CCR%3E%0A%60%60%60%0A%0A%23%23%23if%20%u5224%u65AD%u5B57%u7B26%u4E32%0A%u8FD9%u662F%u4E00%u4E2A%u5751%uFF0C%u548CPython%u7B49%u4E3B%u6D41%u8BED%u8A00%u4E0D%u540C%uFF0CVim%u811A%u672C%u91CC%uFF0Cif%u540E%u9762%u7684%u5B57%u7B26%u4E32%u4F1A%u88AB%u5F3A%u5236%u8F6C%u6362%u6210bool%u53D8%u91CF%uFF0C%u518D%u8FDB%u884C%u5224%u65AD%u3002%u800C%u5B57%u7B26%u4E32%u5BF9%u5E94%u7684bool%u503C%u4E3A0%u3002%u6240%u4EE5%u4E0B%u9762%u7684echo%u8BED%u53E5%u6C38%u8FDC%u4E5F%u6267%u884C%u4E0D%u5230%u3002%0A%60%60%60vim%0Aif%20%28glob%28%27/existing/file%27%29%29%0A%09echo%20%28%27yes%27%29%0Aendif%0A%60%60%60%0A%u6B63%u786E%u7684%u5199%u6CD5%u5E94%u5F53%u662F%0A%60%60%60vim%0Aif%20%28%21empty%28glob%28%27...%27%29%29%0A...%0Aendif%0A%60%60%60%0A%23%23%20%u63D2%u4EF6%0A%23%23%23ctrlP%0A%u6709%u4E86%u8FD9%u4E2A%u63D2%u4EF6%uFF0C%60cscope%20find%20f%60%u5C31%u6CA1%u5565%u5927%u7528%u4E86%u3002%u770B%u5B98%u7F51%u7684%u57FA%u672C%u7528%u6CD5%uFF1A%0A%3E-%20Press%20%60%3CF5%3E%60%20to%20purge%20the%20cache%20for%20the%20current%20directory%20to%20get%20new%20files%2C%20remove%20deleted%20files%20and%20apply%20new%20ignore%20options.%0A%3E-%20Press%20%60%3Cc-f%3E%60%20and%20%60%3Cc-b%3E%60%20to%20cycle%20between%20modes.%20%28Ben%3A%20%u5728%u641C%u7D22%u6587%u4EF6%uFF0Cbuffer%uFF0C%20funky%u4E4B%u95F4%u5FAA%u73AF%u8DF3%u8F6C%29%0A%3E-%20Press%20%60%3Cc-d%3E%60%20to%20switch%20to%20filename%20only%20search%20instead%20of%20full%20path.%20%28Ben%3A%20%u8FD9%u4E2A%u5BF9%u4E8E%u6211%u6BD4%u8F83%u6709%u7528%uFF0C%u56E0%u4E3A%u6211%u4EEC%u7684%u8DEF%u5F84%u592A%u957F%29%0A%3E-%20Press%20%60%3Cc-r%3E%60%20to%20switch%20to%20regexp%20mode.%0A%3E-%20Use%20%60%3Cc-j%3E%60%2C%20%60%3Cc-k%3E%60%20or%20the%20arrow%20keys%20to%20navigate%20the%20result%20list.%0A%3E-%20Use%20%60%3Cc-t%3E%60%20or%20%60%3Cc-v%3E%60%2C%20%60%3Cc-x%3E%60%20to%20open%20the%20selected%20entry%20in%20a%20new%20tab%20or%20in%20a%20new%20split.%0A%3E-%20Use%20%60%3Cc-n%3E%60%2C%20%60%3Cc-p%3E%60%20to%20select%20the%20next/previous%20string%20in%20the%20prompt%27s%20history.%0A%3E-%20Use%20%60%3Cc-y%3E%60%20to%20create%20a%20new%20file%20and%20its%20parent%20directories.%0A%3E-%20Use%20%60%3Cc-z%3E%60%20to%20mark/unmark%20multiple%20files%20and%20%3Cc-o%3E%20to%20open%20them.%0A%0A%u76EE%u524D%u6211%u7684%u914D%u7F6E%0A-%20%26lt%3Bleader%26gt%3B-f%3A%20%u6A21%u7CCA%u641C%u7D22%u6700%u8FD1%u6253%u5F00%u7684%u6587%u4EF6%28MRU%29%0A-%20%26lt%3Bleader%26gt%3B-p%3A%20%u6A21%u7CCA%u641C%u7D22%u5F53%u524D%u76EE%u5F55%u53CA%u5176%u5B50%u76EE%u5F55%u4E0B%u7684%u6240%u6709%u6587%u4EF6%0A-%20%26lt%3Bleader%26gt%3Bfu%3A%20%u8FDB%u5165%u5F53%u524D%u6587%u4EF6%u7684%u51FD%u6570%u5217%u8868%u641C%u7D22%0A-%20%26lt%3Bleader%26gt%3BfU%3A%20%u641C%u7D22%u5F53%u524D%u5149%u6807%u4E0B%u5355%u8BCD%u5BF9%u5E94%u7684%u51FD%u6570%0A%0A%21%5BAlt%20text%5D%28http%3A//zuyunfei.com/images/ctrlp-vim-demo.gif%20%22Ctrlp%u6F14%u793A%22%29%0A%0A%23%23%23neocomplete%0A%0A%23%23%23omni-complete%0A%u8FD9%u662F%u5728Vim%207.0%u5F15%u5165%u7684%u81EA%u52A8%u8865%u5168%u529F%u80FD%uFF0C%u4E0D%u4F9D%u8D56%u4E8E%u4EFB%u4F55%u63D2%u4EF6%u3002%u5728%u6CA1%u6709neocomplete%u7684%u65F6%u5019%uFF0C%u6BD4%u5982Windows%u4E0B%u88C5neocomplete%u548Cycm%u90FD%u5F88%u9EBB%u70E6%uFF0C%u5C31%u53EA%u80FD%u7528%u539F%u751F%u7684%u8865%u5168%u3002%u5176%u5B9E%u4E5F%u591F%u7528%u4E86%uFF0C%u53EA%u662F%u6CA1%u6709%u90A3%u4E48%u65B9%u4FBF%u3002%0A%u6240%u6709%u5E2E%u52A9%u547D%u4EE4%u5165%u53E3%uFF1A%0A%3E%3Ahelp%20ins-completion%0A%3Ahelp%20compl-omni%0A%3Ahelp%20%27omnifunc%27%0A%3Ahelp%20i_CTRL-X_CTRL-O%0A%3Ahelp%20ins-completion-menu%0A%3Ahelp%20popupmenu-keys%0A%3Ahelp%20%27completeopt%27%0A%3Ahelp%20compl-omni-filetypes%0A%3Ahelp%20omnicppcomplete.txt%20%0A%0A%u770Bspf13%u7684.vimrc%u4E2D%u6709%u8FD9%u4E48%u4E00%u53E5%uFF1A%60Automatically%20open%20and%20close%20the%20popup%20menu%20/%20preview%20window%60%0A%u672C%u6765%u4EE5%u4E3Aomni-complete%u4F1A%u50CFneocomplete%u4E00%u6837%u81EA%u52A8%u5F39%u51FA%u4E0B%u62C9%u83DC%u5355%uFF0C%u4F46%u662F%u7ECF%u8FC7%u4E00%u756AGoogle%u548Chelp%u7814%u8BFB%u3002%u8FD9%u4E2A%u7406%u89E3%u662F%u9519%u8BEF%u7684%u3002%0A%21%5BAlt%20text%5D%28./1490863953557.png%29%0A%u6240%u6709%u7684%u4E1C%u897F%u5E76%u4E0D%u4F1A%u81EA%u52A8%u6253%u5F00%uFF0C%u9700%u8981%u7528%60%3CC-X%3E%3CC-O%3E%60%u6216%u8005%60%3CC-N%3E%60%u6216%u8005%60%3CC-P%3E%60%u3002%u5176%u5B9E%60%3CC-X%3E%60%u8FDB%u5165%u4E00%u4E2A%u63D2%u5165%u6A21%u5F0F%u7684%u5B50%u6A21%u5F0F%uFF0C%u7136%u540E%u518D%u6309%u5176%u4ED6%u7684%u7EC4%u5408%u952E%uFF0C%u53EF%u4EE5%u6709%u5BF9%u5E94%u7684%u529F%u80FD%uFF0C%u6458%u8981%u5982%u4E0B%0A*%20%60%3CC-N%3E/%3CC-P%3E%60%20%20%20%20%20%20%20%u8FD9%u5C31%u4E0D%u63D0%u4E86%uFF0C%u6700%u57FA%u672C%u7684%u529F%u80FD%uFF0CN%3Dnext%uFF0CP%3Dprevious%0A*%20%60%3CCTRL-K%3E%60%20%20%20%20%20%20%u5B57%u5178%u8865%u5168%uFF0C%u67E5%u8BE2dictionary%u53C2%u6570%u4E2D%u5BF9%u5E94%u7684%u6587%u4EF6%uFF0C%u8FDB%u884C%u8865%u5168%0A*%20%60%3CCTRL-I%3E%60%20%20%20%20%20%20%u5F53%u524D%u6587%u4EF6%u548C%u5305%u542B%u6587%u4EF6%u8865%u5168%uFF0CI%3Dinclude%0A*%20%60%3CCTRL-%5D%3E%60%20%20%20%20%20%20tag%u8865%u5168%0A*%20%60%3CCTRL-F%3E%60%20%20%20%20%20%20%u6587%u4EF6%u540D%u8865%u5168%0A*%20%60%3CCTRL-D%3E%60%20%20%20%20%20%20%u5B8F%u8865%u5168%0A*%20%60%3CCTRL-V%3E%60%20%20%20%20%20%20Vim%u547D%u4EE4%u8865%u5168%uFF0CV%3DVim%0A*%20%60%3CCTRL-U%3E%60%20%20%20%20%20%20User%20defined%u8865%u5168%uFF0CU%3DUser%uFF0C%u8865%u5168%u51FD%u6570%u901A%u8FC7%60set%20completefunc%3Dxxx%60%u4F20%u5165%0A*%20%60%3CCTRL-O%3E%60%20%20%20%20%20%20omni%u8865%u5168%uFF0CO%3DOmni%uFF0C%u8865%u5168%u51FD%u6570%u901A%u8FC7%60set%20omnifunc%3Dxxx%60%u4F20%u5165%uFF0C%u8FD9%u4E2AVim%u81EA%u5E26%u7684%u811A%u672C%u90FD%u5DF2%u5199%u597D%uFF0Cspf13%u7684vimrc%u4E5F%u6709%u53C2%u8003%u8BBE%u7F6E%u4E86%0A%0A%23%23%23UltiSnips%0A%u5728%u6298%u817E%u534A%u5929snipMate%u65E0%u679C%u7684%u60C5%u51B5%u4E0B%uFF0C%u8F6C%u6295UltiSnips%u3002%u8BED%u6CD5%u590D%u6742%u5EA6%u4EE5%u53CA%u7075%u6D3B%u6027%u8981%u5F3A%u4E8EsnipMate%u3002%u6CE8%u610F%u4EE5%u4E0B%u51E0%u70B9%u5373%u53EF%0A-%20UltiSnips%u641C%u7D22%u6240%u6709runtimepath%u4E0B%u7684UltiSnips%u76EE%u5F55%u4E2D%u7684.snippet%u7ED3%u5C3E%u7684%u6587%u4EF6%0A-%20UltiSnips%u901A%u8FC7%u4E00%u4E2A%u5168%u5C40%u53D8%u91CF%u51B3%u5B9A%u662F%u5426%u652F%u6301snipMate%0A-%20UltiSnips%u7528%60%3Ctab%3E%60%u8865%u5168%uFF0C%u4E0Eomni-complete%u51B2%u7A81%uFF0C%u4E0D%u8FC7omni-complete%u8FD8%u6709%u4E00%u79CD%u7528%u6CD5%u662F%60%3CC-N%3E%60/%60%3CC-P%3E%60%u6765%u5207%u6362%u9009%u9879%uFF0C%u4E5F%u51D1%u5408%u80FD%u7528%u4E86%0A%0A

Edit


曾经谈到面相对象,就是C++,之后最多加上Java。后来,读过的书上说,面向对象其实只是一种设计方式——万事即对象,而不在乎用的是什么语言。C语言,一样也可以做面向对象设计,有时候还更自由,没有C++的各种隐藏的坑。这篇笔记就具体说说如何用C来做面向对象。
开始之前,用一篇网上收录的笔记作为入门:用C语言写面向的对象是一种什么样的体验

封装

对类结构的封装,C里面用struct,相比C++缺少的就是:

  • 构造函数和析构函数
  • private & protect
/** Class definition of BaseLed.
* The concrete LED class should inherit from this class.
*/
typedef struct BaseLed
{
uint8_t id;
/**
* Below 4 members are used to record the LED blinking state.
*/
LedState state;
uint16_t onTime;
uint16_t offTime;
uint16_t blinkCount;
/**
* Public function members.
*/
bool (*init)(struct BaseLed*, uint8_t); //!< Init hardware if needed
void (*switchit)(struct BaseLed*, LedState); //!< Turn on/off
void (*set_brightness)(struct BaseLed*, uint8_t); //!< Set LED's brightness level
}BaseLed;

上面的例子,上半部分是成员变量,下半部分是成员函数。

构造函数&析构函数

C++中,构造函数在以下情况中调用:

  • 比如你在main里面声明了一个类A..那么~A()会在main结束时调用
  • 如果在自定义的函数f()里面声明了一个A 函数f结束的时候就会调用~A()
  • 或者你delete 指向A的指针..
  • 或者显式的调用析构函数

C++各种隐藏的坑,参考网页那些被C++默默地声明和调用的函数

在C面向对象里面,就没有这种问题,因为C语言根本不会为你生成隐藏的函数,也不会帮你调用构造函数,分配内存之类的,也没有虚函数表(VTable)。所有这一切都得自己亲力亲为。不过这样也好,所见即所得嘛。

// ClassA.h
typedef struct _ClassA
{
int a;
void (*funcA)(struct _ClassA*, int);
}ClassA;
ClassA* newA(int);
void deleteA(ClassA*)
// ClassA.c
#include <ClassA.h>
void funcA(ClassA* thisObj, int a)
{
}
ClassA* newA(int a)
{
ClassA* Aobj = malloc(sizeof(ClassA));
Aobj->funcA = funcA;
Aobj->a = a;
}
void deleteA(ClassA* obj)
{
free(obj);
}
// main.c
#include <ClassA.h>
void main()
{
ClassA* aobj = newA(0);
}

在头文件中定义结构体,在.c文件中定义成员函数,在需要调用的地方include对应的头文件。注意,当main函数和ClassA定义在不同的lib中时,头文件中的newA, deleteA需要定义为extern。

访问控制——private & protect

上面的例子是最基本的封装定义。C++中最有趣的是访问控制,即隐藏具体实现,而只暴露接口。

private

怎么做到private呢?用结构体把private包起来。

// ClassA.c
#include <ClassA_Private.h>
#include <ClassA.h>
ClassA* newA(int a)
{
ClassA* pA = malloc(sizeof(ClassA));
pA->private_data = malloc(sizeof(ClassA_Private));
ClassA_Private* pPrivate = (ClassA_Private*)(pA->private_data);
pPrivate->private_a = a;
}
...
// ClassA.h
typedef struct _ClassA
{
int a;
void (*funcA)(struct _ClassA*, int);
void* private_data; // void pointer hide all details
}ClassA;
// ClassA_Private.h
struct _ClassA;
typedef _ClassA_Private
{
int private_a;
void (*private_funcA)(struct _ClassA*, int);
}ClassA_Private
// main.c
#include <ClassA.h>
void main()
{
ClassA* obj = newA(0);
// Below line will bring compile error.
// obj->private_data.private_funcA
}

将不想暴露的数据放在一个结构体中,类定义的头文件包含该头文件。对于想隐藏的客户代码,不暴露该头文件,则其不能引用该private代码。

protect

protect数据是只能暴露给子类和友元,关于友元,参考【C++基础之十】友元函数和友元类
在C里面,就没这么多花头了,“对于想隐藏的客户代码,不暴露该头文件”。

// ChildClassA.h
#include <BaseClassA.h>
#include <BaseClassA_Private.h>
typedef struct _ChildClassA
{
BaseClassA parent;
...
}
// FriendClassA.h
#include <BaseClassA.h>
#include <BaseClassA_Private.h>
typedef struct _ChildClassA
{
BaseClassA parent;
...
}
// main.c
#include <BaseClassA.h>

继承

上面已经看到继承的基本代码了,但是为了实现标准的继承我们还要做的更多。

// BaseClassA
typedef struct BaseClass
{
int a;
void (*funcA)(struct BaseClassA*, int);
}BaseClassA;
// DerivedClassB
#include <BaseClassA.h>
typedef struct DerivedClassB
{
BaseClassA parent;
int special;
void (*funcA)(struct DerivedClassB*, int);
void (*funcB)(struct DerivedClassB*, int);
}DerivedClassB;
DerivedClassB* NewB()
{
DerivedClassB* newB = malloc(sizeof(DerivedClassB));
newB->parent.funcA = funcA;
newB->funcA = funcA;
return newB;
}

子类包含父类的实例,这样就实现了继承。子类同名函数重写了父类同名函数。为下面多态做好准备。

多态

接着上面的例子

BaseClassA* pBase = (BaseClassA*)NewB();
pBase->funcA(); // 调用的是子类构造函数中赋予的函数,这就是多态了

例子

%23C%u9762%u5411%u5BF9%u8C61%0A@%28myblog%29%5Bc/c++%2C%20%u9762%u5411%u5BF9%u8C61%5D%0A%u66FE%u7ECF%u8C08%u5230%u9762%u76F8%u5BF9%u8C61%uFF0C%u5C31%u662FC++%uFF0C%u4E4B%u540E%u6700%u591A%u52A0%u4E0AJava%u3002%u540E%u6765%uFF0C%u8BFB%u8FC7%u7684%u4E66%u4E0A%u8BF4%uFF0C%u9762%u5411%u5BF9%u8C61%u5176%u5B9E%u53EA%u662F%u4E00%u79CD%u8BBE%u8BA1%u65B9%u5F0F%u2014%u2014%u4E07%u4E8B%u5373%u5BF9%u8C61%uFF0C%u800C%u4E0D%u5728%u4E4E%u7528%u7684%u662F%u4EC0%u4E48%u8BED%u8A00%u3002C%u8BED%u8A00%uFF0C%u4E00%u6837%u4E5F%u53EF%u4EE5%u505A%u9762%u5411%u5BF9%u8C61%u8BBE%u8BA1%uFF0C%u6709%u65F6%u5019%u8FD8%u66F4%u81EA%u7531%uFF0C%u6CA1%u6709C++%u7684%u5404%u79CD%u9690%u85CF%u7684%u5751%u3002%u8FD9%u7BC7%u7B14%u8BB0%u5C31%u5177%u4F53%u8BF4%u8BF4%u5982%u4F55%u7528C%u6765%u505A%u9762%u5411%u5BF9%u8C61%u3002%0A%u5F00%u59CB%u4E4B%u524D%uFF0C%u7528%u4E00%u7BC7%u7F51%u4E0A%u6536%u5F55%u7684%u7B14%u8BB0%u4F5C%u4E3A%u5165%u95E8%uFF1A%5B%u7528C%u8BED%u8A00%u5199%u9762%u5411%u7684%u5BF9%u8C61%u662F%u4E00%u79CD%u4EC0%u4E48%u6837%u7684%u4F53%u9A8C%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/29001a8f-6996-413e-b6ad-41c3cbba9c00%29%u3002%0A%0A%5BTOC%5D%0A%0A%23%23%u5C01%u88C5%0A%u5BF9%u7C7B%u7ED3%u6784%u7684%u5C01%u88C5%uFF0CC%u91CC%u9762%u7528%60struct%60%2C%u76F8%u6BD4C++%u7F3A%u5C11%u7684%u5C31%u662F%uFF1A%0A-%20%u6784%u9020%u51FD%u6570%u548C%u6790%u6784%u51FD%u6570%0A-%20private%20%26%20protect%0A%60%60%60%0A/**%20Class%20definition%20of%20BaseLed.%0A%20*%20%20The%20concrete%20LED%20class%20should%20inherit%20from%20this%20class.%0A%20*/%0Atypedef%20struct%20BaseLed%0A%7B%0A%20%20%20%20uint8_t%20id%3B%0A%20%20%20%20/**%0A%20%20%20%20%20*%20Below%204%20members%20are%20used%20to%20record%20the%20LED%20blinking%20state.%0A%20%20%20%20%20*/%0A%20%20%20%20LedState%20state%3B%20%20%20%20%20%20%20%20%20%0A%20%20%20%20uint16_t%20onTime%3B%0A%20%20%20%20uint16_t%20offTime%3B%0A%20%20%20%20uint16_t%20blinkCount%3B%0A%0A%20%20%20%20/**%0A%20%20%20%20%20*%20Public%20function%20members.%0A%20%20%20%20%20*/%0A%20%20%20%20bool%20%28*init%29%28struct%20BaseLed*%2C%20uint8_t%29%3B%20%20%20%20%20%20%20%20%20%20%20%20%20//%21%3C%20Init%20hardware%20if%20needed%0A%20%20%20%20void%20%28*switchit%29%28struct%20BaseLed*%2C%20LedState%29%3B%20%20%20%20%20%20%20%20//%21%3C%20Turn%20on/off%0A%20%20%20%20void%20%28*set_brightness%29%28struct%20BaseLed*%2C%20uint8_t%29%3B%20%20%20//%21%3C%20Set%20LED%27s%20brightness%20level%0A%7DBaseLed%3B%0A%60%60%60%0A%u4E0A%u9762%u7684%u4F8B%u5B50%uFF0C%u4E0A%u534A%u90E8%u5206%u662F%u6210%u5458%u53D8%u91CF%uFF0C%u4E0B%u534A%u90E8%u5206%u662F%u6210%u5458%u51FD%u6570%u3002%0A%23%23%23%u6784%u9020%u51FD%u6570%26%u6790%u6784%u51FD%u6570%0AC++%u4E2D%uFF0C%u6784%u9020%u51FD%u6570%u5728%u4EE5%u4E0B%u60C5%u51B5%u4E2D%u8C03%u7528%uFF1A%0A%3E*%20%u6BD4%u5982%u4F60%u5728main%u91CC%u9762%u58F0%u660E%u4E86%u4E00%u4E2A%u7C7BA..%u90A3%u4E48%7EA%28%29%u4F1A%u5728main%u7ED3%u675F%u65F6%u8C03%u7528%0A%3E*%20%u5982%u679C%u5728%u81EA%u5B9A%u4E49%u7684%u51FD%u6570f%28%29%u91CC%u9762%u58F0%u660E%u4E86%u4E00%u4E2AA%20%20%u51FD%u6570f%u7ED3%u675F%u7684%u65F6%u5019%u5C31%u4F1A%u8C03%u7528%7EA%28%29%0A%3E*%20%u6216%u8005%u4F60delete%20%u6307%u5411A%u7684%u6307%u9488..%0A%3E*%20%u6216%u8005%u663E%u5F0F%u7684%u8C03%u7528%u6790%u6784%u51FD%u6570%0A%0AC++%u5404%u79CD%u9690%u85CF%u7684%u5751%uFF0C%u53C2%u8003%u7F51%u9875%5B%u90A3%u4E9B%u88ABC++%u9ED8%u9ED8%u5730%u58F0%u660E%u548C%u8C03%u7528%u7684%u51FD%u6570%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/86f265a4-1139-468b-a941-1897a54ae440%29%0A%0A%u5728C%u9762%u5411%u5BF9%u8C61%u91CC%u9762%uFF0C%u5C31%u6CA1%u6709%u8FD9%u79CD%u95EE%u9898%uFF0C%u56E0%u4E3AC%u8BED%u8A00%u6839%u672C%u4E0D%u4F1A%u4E3A%u4F60%u751F%u6210%u9690%u85CF%u7684%u51FD%u6570%uFF0C%u4E5F%u4E0D%u4F1A%u5E2E%u4F60%u8C03%u7528%u6784%u9020%u51FD%u6570%uFF0C%u5206%u914D%u5185%u5B58%u4E4B%u7C7B%u7684%uFF0C%u4E5F%u6CA1%u6709%u865A%u51FD%u6570%u8868%28VTable%29%u3002%u6240%u6709%u8FD9%u4E00%u5207%u90FD%u5F97%u81EA%u5DF1%u4EB2%u529B%u4EB2%u4E3A%u3002%u4E0D%u8FC7%u8FD9%u6837%u4E5F%u597D%uFF0C%u6240%u89C1%u5373%u6240%u5F97%u561B%u3002%0A%60%60%60%0A//%20ClassA.h%0Atypedef%20struct%20_ClassA%0A%7B%0A%09int%20a%3B%0A%09void%20%28*funcA%29%28struct%20_ClassA*%2C%20int%29%3B%0A%7DClassA%3B%0A%0AClassA*%20newA%28int%29%3B%0Avoid%20deleteA%28ClassA*%29%0A%0A//%20ClassA.c%0A%23include%20%3CClassA.h%3E%0Avoid%20funcA%28ClassA*%20thisObj%2C%20int%20a%29%0A%7B%0A%7D%0A%0AClassA*%20newA%28int%20a%29%0A%7B%0A%09ClassA*%20Aobj%20%3D%20malloc%28sizeof%28ClassA%29%29%3B%0A%09Aobj-%3EfuncA%20%3D%20funcA%3B%0A%09Aobj-%3Ea%20%3D%20a%3B%0A%7D%0A%0Avoid%20deleteA%28ClassA*%20obj%29%0A%7B%0A%09free%28obj%29%3B%0A%7D%0A//%20main.c%0A%23include%20%3CClassA.h%3E%0Avoid%20main%28%29%0A%7B%0A%09ClassA*%20aobj%20%3D%20newA%280%29%3B%0A%7D%0A%60%60%60%0A%u5728%u5934%u6587%u4EF6%u4E2D%u5B9A%u4E49%u7ED3%u6784%u4F53%uFF0C%u5728.c%u6587%u4EF6%u4E2D%u5B9A%u4E49%u6210%u5458%u51FD%u6570%uFF0C%u5728%u9700%u8981%u8C03%u7528%u7684%u5730%u65B9include%u5BF9%u5E94%u7684%u5934%u6587%u4EF6%u3002%u6CE8%u610F%uFF0C%u5F53%60main%60%u51FD%u6570%u548CClassA%u5B9A%u4E49%u5728%u4E0D%u540C%u7684lib%u4E2D%u65F6%uFF0C%u5934%u6587%u4EF6%u4E2D%u7684newA%2C%20deleteA%u9700%u8981%u5B9A%u4E49%u4E3Aextern%u3002%0A%0A%23%23%23%u8BBF%u95EE%u63A7%u5236%u2014%u2014private%20%26%20protect%0A%u4E0A%u9762%u7684%u4F8B%u5B50%u662F%u6700%u57FA%u672C%u7684%u5C01%u88C5%u5B9A%u4E49%u3002C++%u4E2D%u6700%u6709%u8DA3%u7684%u662F%u8BBF%u95EE%u63A7%u5236%uFF0C%u5373%u9690%u85CF%u5177%u4F53%u5B9E%u73B0%uFF0C%u800C%u53EA%u66B4%u9732%u63A5%u53E3%u3002%0A%23%23%23%23private%0A%u600E%u4E48%u505A%u5230private%u5462%uFF1F%u7528%u7ED3%u6784%u4F53%u628Aprivate%u5305%u8D77%u6765%u3002%0A%60%60%60cpp%0A//%20ClassA.c%0A%23include%20%3CClassA_Private.h%3E%0A%23include%20%3CClassA.h%3E%0AClassA*%20newA%28int%20a%29%0A%7B%0A%09ClassA*%20pA%20%3D%20malloc%28sizeof%28ClassA%29%29%3B%0A%09pA-%3Eprivate_data%20%3D%20malloc%28sizeof%28ClassA_Private%29%29%3B%0A%09ClassA_Private*%20pPrivate%20%3D%20%28ClassA_Private*%29%28pA-%3Eprivate_data%29%3B%0A%09pPrivate-%3Eprivate_a%20%3D%20a%3B%0A%7D%0A...%0A%60%60%60%0A%60%60%60%0A//%20ClassA.h%0Atypedef%20struct%20_ClassA%0A%7B%0A%09int%20a%3B%0A%09void%20%28*funcA%29%28struct%20_ClassA*%2C%20int%29%3B%0A%09void*%20private_data%3B%20%20//%20void%20pointer%20hide%20all%20details%0A%7DClassA%3B%0A%60%60%60%0A%60%60%60%0A//%20ClassA_Private.h%0Astruct%20_ClassA%3B%0Atypedef%20_ClassA_Private%0A%7B%0A%09int%20private_a%3B%0A%09void%20%28*private_funcA%29%28struct%20_ClassA*%2C%20int%29%3B%0A%7DClassA_Private%0A%60%60%60%0A%0A%60%60%60%0A//%20main.c%0A%23include%20%3CClassA.h%3E%0Avoid%20main%28%29%0A%7B%0A%09ClassA*%20obj%20%3D%20newA%280%29%3B%0A%09//%20Below%20line%20will%20bring%20compile%20error.%0A%09//%20obj-%3Eprivate_data.private_funcA%0A%7D%0A%60%60%60%0A%u5C06%u4E0D%u60F3%u66B4%u9732%u7684%u6570%u636E%u653E%u5728%u4E00%u4E2A%u7ED3%u6784%u4F53%u4E2D%uFF0C%u7C7B%u5B9A%u4E49%u7684%u5934%u6587%u4EF6%u5305%u542B%u8BE5%u5934%u6587%u4EF6%u3002%u5BF9%u4E8E%u60F3%u9690%u85CF%u7684%u5BA2%u6237%u4EE3%u7801%uFF0C%u4E0D%u66B4%u9732%u8BE5%u5934%u6587%u4EF6%uFF0C%u5219%u5176%u4E0D%u80FD%u5F15%u7528%u8BE5private%u4EE3%u7801%u3002%0A%23%23%23protect%0Aprotect%u6570%u636E%u662F%u53EA%u80FD%u66B4%u9732%u7ED9%u5B50%u7C7B%u548C%u53CB%u5143%uFF0C%u5173%u4E8E%u53CB%u5143%uFF0C%u53C2%u8003%5B%u3010C++%u57FA%u7840%u4E4B%u5341%u3011%u53CB%u5143%u51FD%u6570%u548C%u53CB%u5143%u7C7B%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/b14c761f-a0d8-4c31-b54c-fb0f4a369aae%29%0A%u5728C%u91CC%u9762%uFF0C%u5C31%u6CA1%u8FD9%u4E48%u591A%u82B1%u5934%u4E86%uFF0C%u201C%u5BF9%u4E8E%u60F3%u9690%u85CF%u7684%u5BA2%u6237%u4EE3%u7801%uFF0C%u4E0D%u66B4%u9732%u8BE5%u5934%u6587%u4EF6%u201D%u3002%0A%60%60%60%0A//%20ChildClassA.h%0A%23include%20%3CBaseClassA.h%3E%0A%23include%20%3CBaseClassA_Private.h%3E%0Atypedef%20struct%20_ChildClassA%0A%7B%0A%09BaseClassA%20parent%3B%0A%09...%0A%7D%0A%0A//%20FriendClassA.h%0A%23include%20%3CBaseClassA.h%3E%0A%23include%20%3CBaseClassA_Private.h%3E%0Atypedef%20struct%20_ChildClassA%0A%7B%0A%09BaseClassA%20parent%3B%0A%09...%0A%7D%0A%0A//%20main.c%0A%23include%20%3CBaseClassA.h%3E%0A%60%60%60%0A%23%23%u7EE7%u627F%0A%u4E0A%u9762%u5DF2%u7ECF%u770B%u5230%u7EE7%u627F%u7684%u57FA%u672C%u4EE3%u7801%u4E86%uFF0C%u4F46%u662F%u4E3A%u4E86%u5B9E%u73B0%u6807%u51C6%u7684%u7EE7%u627F%u6211%u4EEC%u8FD8%u8981%u505A%u7684%u66F4%u591A%u3002%0A%60%60%60%0A//%20BaseClassA%0Atypedef%20struct%20BaseClass%0A%7B%0A%09int%20a%3B%0A%09void%20%28*funcA%29%28struct%20BaseClassA*%2C%20int%29%3B%0A%7DBaseClassA%3B%0A%0A//%20DerivedClassB%0A%23include%20%3CBaseClassA.h%3E%0Atypedef%20struct%20DerivedClassB%0A%7B%0A%09BaseClassA%20parent%3B%0A%09int%20special%3B%0A%09void%20%28*funcA%29%28struct%20DerivedClassB*%2C%20int%29%3B%0A%09void%20%28*funcB%29%28struct%20DerivedClassB*%2C%20int%29%3B%0A%7DDerivedClassB%3B%0A%0ADerivedClassB*%20NewB%28%29%0A%7B%0A%09DerivedClassB*%20newB%20%3D%20malloc%28sizeof%28DerivedClassB%29%29%3B%0A%09newB-%3Eparent.funcA%20%3D%20funcA%3B%0A%09newB-%3EfuncA%20%3D%20funcA%3B%0A%09return%20newB%3B%0A%7D%0A%60%60%60%0A%u5B50%u7C7B%u5305%u542B%u7236%u7C7B%u7684%u5B9E%u4F8B%uFF0C%u8FD9%u6837%u5C31%u5B9E%u73B0%u4E86%u7EE7%u627F%u3002%u5B50%u7C7B%u540C%u540D%u51FD%u6570%u91CD%u5199%u4E86%u7236%u7C7B%u540C%u540D%u51FD%u6570%u3002%u4E3A%u4E0B%u9762%u591A%u6001%u505A%u597D%u51C6%u5907%u3002%0A%23%23%u591A%u6001%0A%u63A5%u7740%u4E0A%u9762%u7684%u4F8B%u5B50%0A%60%60%60%0ABaseClassA*%20pBase%20%3D%20%28BaseClassA*%29NewB%28%29%3B%0ApBase-%3EfuncA%28%29%3B%20//%20%u8C03%u7528%u7684%u662F%u5B50%u7C7B%u6784%u9020%u51FD%u6570%u4E2D%u8D4B%u4E88%u7684%u51FD%u6570%uFF0C%u8FD9%u5C31%u662F%u591A%u6001%u4E86%0A%60%60%60%0A%23%23%u4F8B%u5B50%0A

Edit


Python太强大了,使用其Win32库可以操作所有的Windows应用程序。例如我们在做Dashboard生成器的时候,使用win32com来操作Excel和PPT来获得数据,并更新PPT文件。在初期,我们采用python的xlrd和pptx来操作Excel和PPT,但是发现功能局限性很大,在后来的开发中,我发现xlrd和pptx不仅功能不行,效率也极其低下,远远慢于win32com。唯一的好处就是,其可以跨平台,而不依赖于Windows操作系统。但这一点对我毫无吸引力。

网上使用win32com的文档不是很多,找到下面这篇,讲操作PPT的,入门还是不错的

其他的可以参考微软的VBA文档,每一个COM object都有其对应的属性列表和方法列表。

一些经验

  1. 大多数COM中的索引值都是从1开始
  2. Excel分为Workbook->Worksheet->ListObjects / ChartObjects

其实可以单独写一篇如何操作PPT和EXCEL,苦于没有时间
EXCEL里面有一些核心概念,都是通过PDB尝试才慢慢得来。例如Range,AutoFIlter,ListObject。先列在这儿,待有时间再慢慢补充。

%23Python%20win32com%0A@%28%u5B66%u4E60%u7B14%u8BB0%29%5Bpython%2C%20win32com%5D%0APython%u592A%u5F3A%u5927%u4E86%uFF0C%u4F7F%u7528%u5176Win32%u5E93%u53EF%u4EE5%u64CD%u4F5C%u6240%u6709%u7684Windows%u5E94%u7528%u7A0B%u5E8F%u3002%u4F8B%u5982%u6211%u4EEC%u5728%u505ADashboard%u751F%u6210%u5668%u7684%u65F6%u5019%uFF0C%u4F7F%u7528win32com%u6765%u64CD%u4F5CExcel%u548CPPT%u6765%u83B7%u5F97%u6570%u636E%uFF0C%u5E76%u66F4%u65B0PPT%u6587%u4EF6%u3002%u5728%u521D%u671F%uFF0C%u6211%u4EEC%u91C7%u7528python%u7684xlrd%u548Cpptx%u6765%u64CD%u4F5CExcel%u548CPPT%uFF0C%u4F46%u662F%u53D1%u73B0%u529F%u80FD%u5C40%u9650%u6027%u5F88%u5927%uFF0C%u5728%u540E%u6765%u7684%u5F00%u53D1%u4E2D%uFF0C%u6211%u53D1%u73B0xlrd%u548Cpptx%u4E0D%u4EC5%u529F%u80FD%u4E0D%u884C%uFF0C%u6548%u7387%u4E5F%u6781%u5176%u4F4E%u4E0B%uFF0C%u8FDC%u8FDC%u6162%u4E8Ewin32com%u3002%u552F%u4E00%u7684%u597D%u5904%u5C31%u662F%uFF0C%u5176%u53EF%u4EE5%u8DE8%u5E73%u53F0%uFF0C%u800C%u4E0D%u4F9D%u8D56%u4E8EWindows%u64CD%u4F5C%u7CFB%u7EDF%u3002%u4F46%u8FD9%u4E00%u70B9%u5BF9%u6211%u6BEB%u65E0%u5438%u5F15%u529B%u3002%0A%0A%u7F51%u4E0A%u4F7F%u7528win32com%u7684%u6587%u6863%u4E0D%u662F%u5F88%u591A%uFF0C%u627E%u5230%u4E0B%u9762%u8FD9%u7BC7%uFF0C%u8BB2%u64CD%u4F5CPPT%u7684%uFF0C%u5165%u95E8%u8FD8%u662F%u4E0D%u9519%u7684%0A-%20%5B%5BPython%5D%20win32com%20PowerPoint%20%AB%20ibluemonkey%27s%20Note%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/d5ac6ed2-19a4-435d-9b98-69db9ae0107c%29%0A%0A%u5176%u4ED6%u7684%u53EF%u4EE5%u53C2%u8003%u5FAE%u8F6F%u7684VBA%u6587%u6863%uFF0C%u6BCF%u4E00%u4E2ACOM%20object%u90FD%u6709%u5176%u5BF9%u5E94%u7684%u5C5E%u6027%u5217%u8868%u548C%u65B9%u6CD5%u5217%u8868%u3002%0A-%20%5B%u5BF9%u8C61%u6A21%u578B%uFF08PowerPoint%20VBA%20%u53C2%u8003%uFF09%5D%28https%3A//msdn.microsoft.com/zh-cn/library/office/ff743835.aspx%29%0A%0A%23%23%u4E00%u4E9B%u7ECF%u9A8C%0A1.%20%u5927%u591A%u6570COM%u4E2D%u7684%u7D22%u5F15%u503C%u90FD%u662F%u4ECE1%u5F00%u59CB%0A2.%20Excel%u5206%u4E3AWorkbook-%3EWorksheet-%3EListObjects%20/%20ChartObjects%0A%0A%u5176%u5B9E%u53EF%u4EE5%u5355%u72EC%u5199%u4E00%u7BC7%u5982%u4F55%u64CD%u4F5CPPT%u548CEXCEL%uFF0C%u82E6%u4E8E%u6CA1%u6709%u65F6%u95F4%0AEXCEL%u91CC%u9762%u6709%u4E00%u4E9B%u6838%u5FC3%u6982%u5FF5%uFF0C%u90FD%u662F%u901A%u8FC7PDB%u5C1D%u8BD5%u624D%u6162%u6162%u5F97%u6765%u3002%u4F8B%u5982Range%uFF0CAutoFIlter%uFF0CListObject%u3002%u5148%u5217%u5728%u8FD9%u513F%uFF0C%u5F85%u6709%u65F6%u95F4%u518D%u6162%u6162%u8865%u5145%u3002

Edit

问题

1. SimpleHTTPServer无法通过管道输出信息

在做第4步的时候,遇到了很大的挫折。第1步采用subprocess模块,打开命令python MyHTTPServer.py。对subprocess的介绍可参考:

遇到的问题是:

  • popen.communicate/read会block主进程,且block时,无法用ctrl+c退出
  • readline始终返回空字符

解决

最后解决的方案在这两个网页中:

简而言之,block是因为,没有字符输出到stdout,因为存在缓存,对python采用-u可以解决

2. Python Requests库在访问localhost时出503 Error

参看这个网页,来自Stack Overflow
Python requests 503 erros when trying to access localhost:8000
问题是因为公司代理禁止自己ping自己。

整理

SimpleHTTPServer基于BaseHTTPServer,并提供了文件列表下载服务。它是python为BaseHTTPServer提供的例程。开发者可以基于它开发,或者参考它,并基于BaseHTTPServer开发。

%23%u4F7F%u7528HTML%u4F5C%u4E3APython%u7A0B%u5E8F%u7684UI%0A@%28%u5DE5%u4F5C%u7B14%u8BB0%29%5Bpython%2C%20http%5D%0A%60%60%60sequence%0AUpdater-%3ESimpleHTTPServer%3A1.Start%0AUpdater-%3EHTML%3A%202.Open%20in%20Browser%0AHTML-%3ESimpleHTTPServer%3A%203.POST%0ASimpleHTTPServer-%3EUpdater%3A4.PIPE%0AUpdater-%3ESimpleHTTPServer%3A5.Terminate%0A%60%60%60%0A%0A%23%23%u95EE%u9898%0A%23%23%231.%20SimpleHTTPServer%u65E0%u6CD5%u901A%u8FC7%u7BA1%u9053%u8F93%u51FA%u4FE1%u606F%0A%u5728%u505A%u7B2C4%u6B65%u7684%u65F6%u5019%uFF0C%u9047%u5230%u4E86%u5F88%u5927%u7684%u632B%u6298%u3002%u7B2C1%u6B65%u91C7%u7528subprocess%u6A21%u5757%uFF0C%u6253%u5F00%u547D%u4EE4%60python%20MyHTTPServer.py%60%u3002%u5BF9subprocess%u7684%u4ECB%u7ECD%u53EF%u53C2%u8003%uFF1A%0A-%20%5B%20python%u5B50%u8FDB%u7A0B%u6A21%u5757subprocess%u8BE6%u89E3%u4E0E%u5E94%u7528%u5B9E%u4F8B%20%u4E4B%u4E00%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/3fcc11e2-7d72-479f-9228-df72909bd465%29%0A-%20%5B%u5B98%u65B9%u6587%u6863%5D%28https%3A//docs.python.org/2/library/subprocess.html%23subprocess.CalledProcessError%29%0A%0A%u9047%u5230%u7684%u95EE%u9898%u662F%uFF1A%0A-%20popen.communicate/read%u4F1Ablock%u4E3B%u8FDB%u7A0B%uFF0C%u4E14block%u65F6%uFF0C%u65E0%u6CD5%u7528ctrl+c%u9000%u51FA%0A-%20readline%u59CB%u7EC8%u8FD4%u56DE%u7A7A%u5B57%u7B26%0A%0A%23%23%23%23%u89E3%u51B3%0A%u6700%u540E%u89E3%u51B3%u7684%u65B9%u6848%u5728%u8FD9%u4E24%u4E2A%u7F51%u9875%u4E2D%uFF1A%0A-%20%5BStartserver%20does%20not%20send%20data%20back%20to%20POpen.communicate%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/81960cae-4da2-4526-9ec2-3888b3fee1fd%29%0A-%20%5BBypassing%20buffering%20of%20subprocess%20output%20with%20popen%20in%20C%20or%20Python%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/ef454085-44d1-44c6-8862-42a889a855ab%29%0A%0A%u7B80%u800C%u8A00%u4E4B%uFF0Cblock%u662F%u56E0%u4E3A%uFF0C%u6CA1%u6709%u5B57%u7B26%u8F93%u51FA%u5230stdout%uFF0C%u56E0%u4E3A%u5B58%u5728%u7F13%u5B58%uFF0C%u5BF9python%u91C7%u7528%60-u%60%u53EF%u4EE5%u89E3%u51B3%0A%0A%23%23%232.%20Python%20Requests%u5E93%u5728%u8BBF%u95EElocalhost%u65F6%u51FA503%20Error%0A%u53C2%u770B%u8FD9%u4E2A%u7F51%u9875%uFF0C%u6765%u81EAStack%20Overflow%0A%5BPython%20requests%20503%20erros%20when%20trying%20to%20access%20localhost%3A8000%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/272a1b96-68ed-4fc6-8bfa-4160c5f09907%29%0A%u95EE%u9898%u662F%u56E0%u4E3A%u516C%u53F8%u4EE3%u7406%u7981%u6B62%u81EA%u5DF1ping%u81EA%u5DF1%u3002%0A%0A%23%23%u6574%u7406%0ASimpleHTTPServer%u57FA%u4E8EBaseHTTPServer%uFF0C%u5E76%u63D0%u4F9B%u4E86%u6587%u4EF6%u5217%u8868%u4E0B%u8F7D%u670D%u52A1%u3002%u5B83%u662Fpython%u4E3ABaseHTTPServer%u63D0%u4F9B%u7684%u4F8B%u7A0B%u3002%u5F00%u53D1%u8005%u53EF%u4EE5%u57FA%u4E8E%u5B83%u5F00%u53D1%uFF0C%u6216%u8005%u53C2%u8003%u5B83%uFF0C%u5E76%u57FA%u4E8EBaseHTTPServer%u5F00%u53D1%u3002%0A%0A

Edit

从Android单元测试中,接触到Java的mock框架。参看这篇笔记《Android单元测试》。最近在做Dashboard Generator,要用python解析excel,ppt和网页,测试效率极低。所以考虑到可以用mock来代替一些耗时的操作和资源。于是接触到python的mock框架。
python mock在3.0中已经集成为内置类,但是2.7仍然需要用pip来安装。这也不难。然后在网上搜集了几篇还不错的文章,如下:

简介

因为是python语言的特性,所以Mock上手非常容易。窃以为比Java(Android) Mock要容易的多。

Mock vs. Stub/Fake

参看Using Mocks in Python,也可以参看Martin Fowler的一篇文章Mocks Aren’t Stubs
这里提到了Mock和Stub/Fake的区别。这是我以前一直没有注意到的。

为什么要用Mock?

A good unit test has to be repeatable, allowing you to isolate and identify a fault. But the test resource might give out stochastic results, or it might have widely varying response times. And as a result, you end up glossing over a potential showstopper.

测试必须是可重复的,解耦的。但代码用到的运行时资源往往是随机的,或者昂贵的(比如网页,总是在变化的,比如,download文件,非常耗时)。我们不能让我们的测试首先不能依赖于测试资源,其次需要有比较高的效率。

These are some of the reasons why you might want to use a mock in place of a test resource. A mock can present the same set of method interfaces as the resource to the test subject. But a mock is easier to setup, easier to manage. It can deliver deterministic results, and it can be customized to suit a particular test. And it can be easily updated to reflect changes in the actual resource.

Stubs & Fake

Stub

A stub presents a set of method interfaces to the test subject, the same set the subject would see in an actual test resource. When the test subject calls a stub method, the stub may respond with a predetermined set of results. It may raise an error or exception, also predetermined. A stub may track its interactions with the test subject, but it performs no tasks outside the narrow scope of its programming.

Fake

A fake also presents a set of method interfaces and tracks its interactions with the test subject. But unlike a stub, a fake actually processes input data from the test subject and produces results based on that data. In short, a fake is a functional, but non-production version of the actual test resource. It lacks the checks and balances found in resource, it uses simpler algorithms, and it seldom, if ever, stores or transports data.

Stub和Fake都是针对接口的模拟,在需要对状态进行测试的情况时,我们可以用Stub或者Fake。例如UnitTest++,就是用的Stub。
但是如果我们要测试具体的代码行为,我们往往要用到Mock。比如,一个函数调用了几次,用的什么参数,等等。

我的理解,其实他们三者之间并没有很明显的界限。用Mock的时候,针对一些需要模拟的接口,仍然可以有办法将之stub out。只是Mock并不擅长,方法不够直觉。同理Stub也可以用来mock掉一些对象。
Stub/Fake更像是应用于面向接口编程,而Mock更擅长于面向对象编程。

何时使用Mock

Of course, mocks are not without issues. Designing an accurate mock is difficult, especially if you have no reliable information on the test resource. You can try and find an open-source match, or you can make a guesstimate on the resource’s method interface. Whichever you choose, you can update the mock easily later on, should you get more detailed information on the preferred resource. Too many mocks can complicate a test, making it harder for you to track down a failure.
Best practice

  • is to limit a test case to one or two mocks
  • or use separate test cases for each mock/subject pairing.

如何使用

constructor

class Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs)

主要参数如下:

  • name: 只有标记作用,在print或者repr的时候可以看到,调试的时候有用
  • return_value: 最简单的对接口的stub化
  • side_effect: 其参数可以为列表或函数,若其返回值为DEFAULT,则采用return_value的值,若其返回值不是DEFAULT,则其会覆盖return_value的值
  • spec: 可以是string列表,也可以为class或instance。Accessing any attribute not in this list will raise an AttributeError.

side_effect为列表

>>> mock = Mock()
>>> mock.side_effect = [3, 2, 1]
>>> mock(), mock(), mock()
(3, 2, 1)

side_effect为函数,其参数与真实传入的参数相同

>>> side_effect = lambda value: value + 1
>>> mock = Mock(side_effect=side_effect)
>>> mock(3)
4
>>> mock(-8)
-7

对函数调用的检测

mock包含以下属性:

  • called
  • call_count
  • call_args
  • call_args_list
    含义显而易见,用法参考官方文档

method_calls & mock_calls

>>> mock = Mock()
>>> mock.method()
<Mock name='mock.method()' id='...'>
>>> mock.property.method.attribute()
<Mock name='mock.property.method.attribute()' id='...'>
>>> mock.method_calls
[call.method(), call.property.method.attribute()]

>>> mock = MagicMock()
>>> result = mock(1, 2, 3)
>>> mock.first(a=3)
<MagicMock name='mock.first()' id='...'>
>>> mock.second()
<MagicMock name='mock.second()' id='...'>
>>> int(mock)
1
>>> result(1)
<MagicMock name='mock()()' id='...'>
>>> expected = [call(1, 2, 3), call.first(a=3), call.second(),
... call.__int__(), call()(1)]
>>> mock.mock_calls == expected
True

assert

Mock提供了以下几种assert:

  • assert_called_once
  • assert_called_with
  • assert_called_once_with
  • assert_has_calls
  • assert_any_calls
    前面三个很直觉,后面两个稍作解释。

assert_any_call

The assert assert_any_call() checks if the test subject called a mocked method at any point of the test routine. This is regardless of how many other calls were made between the mocked method and the assert.

assert_has_calls

This one looks at a sequence of method calls, checks if they are in the right order and with the right arguments.

from mock import Mock, call

# The mock specification
class Foo(object):
_fooValue = 123

def callFoo(self):
pass

def doFoo(self, argValue):
pass

# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>

mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")

fooCalls = [call.callFoo(), call.dooFoo("narf"), call.doFoo("zort")]

mockFoo.assert_has_calls(fooCalls)
# AssertionError: Calls not found.
# Expected: [call.callFoo(), call.dooFoo('narf'), call.doFoo('zort')]
# Actual: [call.callFoo(), call.doFoo('narf'), call.doFoo('zort')]

fooCalls = [call.callFoo(), call.dooFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls, any_order = True)
# AssertionError: (call.dooFoo('narf'),) not all found in call list

高阶特性

MagicMock vs. Mock

With Mock you can mock magic methods but you have to define them. MagicMock has “default implementations of most of the magic methods“.
If you don’t need to test any magic methods, Mock is adequate and doesn’t bring a lot of extraneous things into your tests. If you need to test a lot of magic methods MagicMock will save you some time.

哪些magic methods?看下面

  • lt: NotImplemented
  • gt: NotImplemented
  • le: NotImplemented
  • ge: NotImplemented
  • int : 1
  • contains : False
  • len : 1
  • iter : iter([])
  • exit : False
  • complex : 1j
  • float : 1.0
  • bool : True
  • nonzero : True
  • oct : ‘1’
  • hex : ‘0x1’
  • long : long(1)
  • index : 1
  • hash : default hash for the mock
  • str : default str for the mock
  • unicode : default unicode for the mock
  • sizeof: default sizeof for the mock
>>> mock = MagicMock()
>>> int(mock)
1
>>> len(mock)
0
>>> hex(mock)
'0x1'
>>> list(mock)
[]
>>> object() in mock
False

所谓magic methods就是一些内置的python运算符,而MagicMock支持这些运算符,Mock不支持

mock import

Mocking Python imports这里有提到。其实很简单,看代码

# A.py
import B
B.foo()

# test.py
A.B = mock.Mock()
A.B.foo.return_value = 123

mock class constructor

直接贴上实际的测试代码

mockSMBConnObj = mock.Mock()
mockSMBConn = mock.Mock(return_value=mockSMBConnObj) # mock constructor

mock对象的自动创建

当访问一个mock对象中不存在的属性时,mock会自动建立一个子mock对象,并且把正在访问的属性指向它,这个功能对于实现多级属性的mock很方便。

client = mock.Mock()
client.v2_client.get.return_value = '200'

上面例子中client.v2_client.get就是自动生成的mock对象
类似自动生成,我们还可以采用attach_mock的方法。不同的是,attach_mock会让被attach的双方具有父子关系,则对子mock的调用会被计入父的mock_calls。参考Attaching Mocks as Attributes

patch

通过patch,我们可以控制Mock对象的生存周期。意思就是在一个函数范围内,或者一个类的范围内,或者with语句的范围内mock掉一个对象。
有下面

decorator

>>> @patch('__main__.SomeClass')
... def function(normal_argument, mock_class):
... print mock_class is SomeClass
...
>>> function(None)
True

context manager

>>> class Class(object):
... def method(self):
... pass
...
>>> with patch('__main__.Class') as MockClass:
... instance = MockClass.return_value
... instance.method.return_value = 'foo'
... assert Class() is instance
... assert Class().method() == 'foo'

patcher

>>> Original = Class
>>> patcher = patch('__main__.Class', spec=True)
>>> MockClass = patcher.start()
>>> instance = MockClass()
>>> assert isinstance(instance, Original)
>>> patcher.stop()

patch.object和patch类似,只是写法不同,看下面对比:

@patch.object(SomeClass, 'class_method')
@patch('SomeClass.class_method')

patch还有很多种其他用法,patch.multiple, patch.dict等等。参看More Patch

其他未决的问题

其实还有很多mock高级的用法,例如,当我想mock掉win32com的时候,搜到的这个网页Mocking out python OS specific imports。其中有一段代码:

 modules = {
"_winreg": mock.MagicMock(),
"pythoncom": mock.MagicMock(),
"pywintypes": mock.MagicMock(),
"win32api": mock.MagicMock(),
"win32com": self.win32com,
"win32com.client": self.win32com.client,
"win32file": mock.MagicMock(),
"win32service": mock.MagicMock(),
"win32serviceutil": mock.MagicMock(),
"winerror": mock.MagicMock(),
"wmi": self.wmimock
}

self.module_patcher = mock.patch.dict("sys.modules", modules)
self.module_patcher.start()

还有如何mock掉win32com.client的对象?例如,待测代码如下

Application = win32com.client.Dispatch("PowerPoint.Application")
source_ppt = Application.Presentations.Open(path)
source_ppt.Slides.InsertFromFile(os.path.abspath(chart), index, 1, 1)

因为对win32com.client实现一无所知,不知道如何mock,推测mock代码如下,还未验证

mockApp = mock.Mock()
with mock.patch('MyModule.win32com.client.Dispatch', return_value=mockApp) as mockWin32com:
mockPpt = mock.Mock()
mockApp.Presnetations.Open.return_value = mockPpt
mockPpt.Slides.InsertFromFile.assert_called_once_with(...)

因为python的语言特性,python的Mock框架还是比Java的Mock框架要灵活很多。比如:对类构造函数的Mock,非常容易,而Java则需要经过特殊处理。还有对接口的fake化,用side_effect很容易实现,但是Java Mock则要用到when().thenAnswer(){}。麻烦又不直觉。

when(...).thenAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return value;
}
});
%23python%20mock%u521D%u6B65%0A@%28%u5B66%u4E60%u7B14%u8BB0%29%5Bpython%2C%20mock%2C%20unittest%5D%0A%0A%5BTOC%5D%0A%0A%u4ECEAndroid%u5355%u5143%u6D4B%u8BD5%u4E2D%uFF0C%u63A5%u89E6%u5230Java%u7684mock%u6846%u67B6%u3002%u53C2%u770B%u8FD9%u7BC7%u7B14%u8BB0%u300A%5BAndroid%u5355%u5143%u6D4B%u8BD5%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/4769d75d-17cc-4dcc-96b8-b746bcae53c1%29%u300B%u3002%u6700%u8FD1%u5728%u505ADashboard%20Generator%uFF0C%u8981%u7528python%u89E3%u6790excel%uFF0Cppt%u548C%u7F51%u9875%uFF0C%u6D4B%u8BD5%u6548%u7387%u6781%u4F4E%u3002%u6240%u4EE5%u8003%u8651%u5230%u53EF%u4EE5%u7528mock%u6765%u4EE3%u66FF%u4E00%u4E9B%u8017%u65F6%u7684%u64CD%u4F5C%u548C%u8D44%u6E90%u3002%u4E8E%u662F%u63A5%u89E6%u5230python%u7684mock%u6846%u67B6%u3002%0Apython%20mock%u57283.0%u4E2D%u5DF2%u7ECF%u96C6%u6210%u4E3A%u5185%u7F6E%u7C7B%uFF0C%u4F46%u662F2.7%u4ECD%u7136%u9700%u8981%u7528pip%u6765%u5B89%u88C5%u3002%u8FD9%u4E5F%u4E0D%u96BE%u3002%u7136%u540E%u5728%u7F51%u4E0A%u641C%u96C6%u4E86%u51E0%u7BC7%u8FD8%u4E0D%u9519%u7684%u6587%u7AE0%uFF0C%u5982%u4E0B%uFF1A%0A-%20%5BPython%20Mock%u7684%u5165%u95E8%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/1cb1675b-d132-408e-a88a-0eeb3d81fcc2%29%0A-%20%5BMocking%20Python%20imports%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/d063563d-dc7d-4373-96a9-a0759de8e970%29%0A-%20%5BUsing%20Mocks%20in%20Python%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/b12c60d1-416d-44da-8d6d-9ad1f39803dd%29%0A-%20%5BMock%u5B98%u65B9%u6587%u6863%5D%28http%3A//www.voidspace.org.uk/python/mock/mock.html%29%0A%0A%23%23%u7B80%u4ECB%0A%u56E0%u4E3A%u662Fpython%u8BED%u8A00%u7684%u7279%u6027%uFF0C%u6240%u4EE5Mock%u4E0A%u624B%u975E%u5E38%u5BB9%u6613%u3002%u7A83%u4EE5%u4E3A%u6BD4Java%28Android%29%20Mock%u8981%u5BB9%u6613%u7684%u591A%u3002%0A%23%23%23Mock%20vs.%20Stub/Fake%0A%u53C2%u770B%5BUsing%20Mocks%20in%20Python%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/b12c60d1-416d-44da-8d6d-9ad1f39803dd%29%uFF0C%u4E5F%u53EF%u4EE5%u53C2%u770BMartin%20Fowler%u7684%u4E00%u7BC7%u6587%u7AE0%5BMocks%20Aren%27t%20Stubs%5D%28https%3A//martinfowler.com/articles/mocksArentStubs.html%29%u3002%0A%u8FD9%u91CC%u63D0%u5230%u4E86Mock%u548CStub/Fake%u7684%u533A%u522B%u3002%u8FD9%u662F%u6211%u4EE5%u524D%u4E00%u76F4%u6CA1%u6709%u6CE8%u610F%u5230%u7684%u3002%0A%0A%23%23%23%23%u4E3A%u4EC0%u4E48%u8981%u7528Mock%uFF1F%0A%3EA%20good%20unit%20test%20has%20to%20be%20**repeatable**%2C%20allowing%20you%20to%20**isolate**%20and%20identify%20a%20fault.%20But%20the%20test%20resource%20might%20give%20out%20stochastic%20results%2C%20or%20it%20might%20have%20widely%20varying%20response%20times.%20And%20as%20a%20result%2C%20you%20end%20up%20glossing%20over%20a%20potential%20showstopper.%0A%0A%u6D4B%u8BD5%u5FC5%u987B%u662F%u53EF%u91CD%u590D%u7684%uFF0C%u89E3%u8026%u7684%u3002%u4F46%u4EE3%u7801%u7528%u5230%u7684%u8FD0%u884C%u65F6%u8D44%u6E90%u5F80%u5F80%u662F%u968F%u673A%u7684%uFF0C%u6216%u8005%u6602%u8D35%u7684%uFF08%u6BD4%u5982%u7F51%u9875%uFF0C%u603B%u662F%u5728%u53D8%u5316%u7684%uFF0C%u6BD4%u5982%uFF0Cdownload%u6587%u4EF6%uFF0C%u975E%u5E38%u8017%u65F6%uFF09%u3002%u6211%u4EEC%u4E0D%u80FD%u8BA9%u6211%u4EEC%u7684%u6D4B%u8BD5%u9996%u5148%u4E0D%u80FD%u4F9D%u8D56%u4E8E%u6D4B%u8BD5%u8D44%u6E90%uFF0C%u5176%u6B21%u9700%u8981%u6709%u6BD4%u8F83%u9AD8%u7684%u6548%u7387%u3002%0A%0A%3EThese%20are%20some%20of%20the%20reasons%20why%20you%20might%20want%20to%20use%20a%20mock%20in%20place%20of%20a%20**test%20resource**.%20A%20mock%20can%20present%20the%20same%20set%20of%20method%20interfaces%20as%20the%20resource%20to%20the%20test%20subject.%20But%20a%20mock%20is%20easier%20to%20setup%2C%20easier%20to%20manage.%20It%20can%20deliver%20deterministic%20results%2C%20and%20it%20can%20be%20customized%20to%20suit%20a%20particular%20test.%20And%20it%20can%20be%20easily%20updated%20to%20reflect%20changes%20in%20the%20actual%20resource.%0A%0A%23%23%23%23Stubs%20%26%20Fake%0AStub%0A%3EA%20stub%20presents%20a%20set%20of%20method%20interfaces%20to%20the%20test%20subject%2C%20the%20same%20set%20the%20subject%20would%20see%20in%20an%20actual%20test%20resource.%20When%20the%20test%20subject%20calls%20a%20stub%20method%2C%20the%20stub%20may%20respond%20with%20a%20predetermined%20set%20of%20results.%20It%20may%20raise%20an%20error%20or%20exception%2C%20also%20predetermined.%20A%20stub%20may%20track%20its%20interactions%20with%20the%20test%20subject%2C%20but%20it%20performs%20no%20tasks%20outside%20the%20narrow%20scope%20of%20its%20programming.%0A%0AFake%0A%3EA%20fake%20also%20presents%20a%20set%20of%20method%20interfaces%20and%20tracks%20its%20interactions%20with%20the%20test%20subject.%20But%20unlike%20a%20stub%2C%20a%20fake%20actually%20processes%20input%20data%20from%20the%20test%20subject%20and%20produces%20results%20based%20on%20that%20data.%20In%20short%2C%20a%20fake%20is%20a%20functional%2C%20but%20non-production%20version%20of%20the%20actual%20test%20resource.%20It%20lacks%20the%20checks%20and%20balances%20found%20in%20resource%2C%20it%20uses%20simpler%20algorithms%2C%20and%20it%20seldom%2C%20if%20ever%2C%20stores%20or%20transports%20data.%0A%0AStub%u548CFake%u90FD%u662F%u9488%u5BF9%u63A5%u53E3%u7684%u6A21%u62DF%uFF0C%u5728%u9700%u8981%u5BF9%u72B6%u6001%u8FDB%u884C%u6D4B%u8BD5%u7684%u60C5%u51B5%u65F6%uFF0C%u6211%u4EEC%u53EF%u4EE5%u7528Stub%u6216%u8005Fake%u3002%u4F8B%u5982UnitTest++%uFF0C%u5C31%u662F%u7528%u7684Stub%u3002%0A%u4F46%u662F%u5982%u679C%u6211%u4EEC%u8981%u6D4B%u8BD5%u5177%u4F53%u7684%u4EE3%u7801%u884C%u4E3A%uFF0C%u6211%u4EEC%u5F80%u5F80%u8981%u7528%u5230Mock%u3002%u6BD4%u5982%uFF0C%u4E00%u4E2A%u51FD%u6570%u8C03%u7528%u4E86%u51E0%u6B21%uFF0C%u7528%u7684%u4EC0%u4E48%u53C2%u6570%uFF0C%u7B49%u7B49%u3002%0A%0A%u6211%u7684%u7406%u89E3%uFF0C%u5176%u5B9E%u4ED6%u4EEC%u4E09%u8005%u4E4B%u95F4%u5E76%u6CA1%u6709%u5F88%u660E%u663E%u7684%u754C%u9650%u3002%u7528Mock%u7684%u65F6%u5019%uFF0C%u9488%u5BF9%u4E00%u4E9B%u9700%u8981%u6A21%u62DF%u7684%u63A5%u53E3%uFF0C%u4ECD%u7136%u53EF%u4EE5%u6709%u529E%u6CD5%u5C06%u4E4Bstub%20out%u3002%u53EA%u662FMock%u5E76%u4E0D%u64C5%u957F%uFF0C%u65B9%u6CD5%u4E0D%u591F%u76F4%u89C9%u3002%u540C%u7406Stub%u4E5F%u53EF%u4EE5%u7528%u6765mock%u6389%u4E00%u4E9B%u5BF9%u8C61%u3002%0AStub/Fake%u66F4%u50CF%u662F%u5E94%u7528%u4E8E%u9762%u5411%u63A5%u53E3%u7F16%u7A0B%uFF0C%u800CMock%u66F4%u64C5%u957F%u4E8E%u9762%u5411%u5BF9%u8C61%u7F16%u7A0B%u3002%0A%0A%23%23%23%23%u4F55%u65F6%u4F7F%u7528Mock%0A%3EOf%20course%2C%20mocks%20are%20not%20without%20issues.%20Designing%20an%20accurate%20mock%20is%20difficult%2C%20especially%20if%20you%20have%20no%20reliable%20information%20on%20the%20test%20resource.%20You%20can%20try%20and%20find%20an%20open-source%20match%2C%20or%20you%20can%20make%20a%20guesstimate%20on%20the%20resource%27s%20method%20interface.%20Whichever%20you%20choose%2C%20you%20can%20update%20the%20mock%20easily%20later%20on%2C%20should%20you%20get%20more%20detailed%20information%20on%20the%20preferred%20resource.%20Too%20many%20mocks%20can%20complicate%20a%20test%2C%20making%20it%20harder%20for%20you%20to%20track%20down%20a%20failure.%20%0A%3E**Best%20practice**%20%0A%3E%20-%20is%20to%20limit%20a%20test%20case%20to%20**one%20or%20two%20mocks**%0A%3E%20-%20or%20use%20**separate%20test%20cases**%20for%20each%20mock/subject%20pairing.%0A%0A%0A%23%23%23%u5982%u4F55%u4F7F%u7528%0A%21%5BAlt%20text%7C400x0%5D%28./1486178612793.png%29%0A%0A%23%23%23%23constructor%0A%60%60%60%0Aclass%20Mock%28spec%3DNone%2C%20side_effect%3DNone%2C%20return_value%3DDEFAULT%2C%20wraps%3DNone%2C%20name%3DNone%2C%20spec_set%3DNone%2C%20**kwargs%29%0A%60%60%60%0A%u4E3B%u8981%u53C2%u6570%u5982%u4E0B%uFF1A%0A-%20name%3A%20%u53EA%u6709%u6807%u8BB0%u4F5C%u7528%uFF0C%u5728print%u6216%u8005repr%u7684%u65F6%u5019%u53EF%u4EE5%u770B%u5230%uFF0C%u8C03%u8BD5%u7684%u65F6%u5019%u6709%u7528%0A-%20return_value%3A%20%u6700%u7B80%u5355%u7684%u5BF9%u63A5%u53E3%u7684stub%u5316%0A-%20side_effect%3A%20%u5176%u53C2%u6570%u53EF%u4EE5%u4E3A%u5217%u8868%u6216%u51FD%u6570%uFF0C%u82E5%u5176%u8FD4%u56DE%u503C%u4E3ADEFAULT%uFF0C%u5219%u91C7%u7528return_value%u7684%u503C%uFF0C%u82E5%u5176%u8FD4%u56DE%u503C%u4E0D%u662FDEFAULT%uFF0C%u5219%u5176%u4F1A%u8986%u76D6return_value%u7684%u503C%0A-%20spec%3A%20%20%u53EF%u4EE5%u662Fstring%u5217%u8868%uFF0C%u4E5F%u53EF%u4EE5%u4E3Aclass%u6216instance%u3002Accessing%20any%20attribute%20not%20in%20this%20list%20will%20raise%20an%20AttributeError.%0A%0Aside_effect%u4E3A%u5217%u8868%0A%60%60%60%0A%3E%3E%3E%20mock%20%3D%20Mock%28%29%0A%3E%3E%3E%20mock.side_effect%20%3D%20%5B3%2C%202%2C%201%5D%0A%3E%3E%3E%20mock%28%29%2C%20mock%28%29%2C%20mock%28%29%0A%283%2C%202%2C%201%29%0A%60%60%60%0Aside_effect%u4E3A%u51FD%u6570%uFF0C%u5176%u53C2%u6570%u4E0E%u771F%u5B9E%u4F20%u5165%u7684%u53C2%u6570%u76F8%u540C%0A%60%60%60%0A%3E%3E%3E%20side_effect%20%3D%20lambda%20value%3A%20value%20+%201%0A%3E%3E%3E%20mock%20%3D%20Mock%28side_effect%3Dside_effect%29%0A%3E%3E%3E%20mock%283%29%0A4%0A%3E%3E%3E%20mock%28-8%29%0A-7%0A%60%60%60%0A%0A%23%23%23%23%u5BF9%u51FD%u6570%u8C03%u7528%u7684%u68C0%u6D4B%0Amock%u5305%u542B%u4EE5%u4E0B%u5C5E%u6027%uFF1A%0A-%20called%0A-%20call_count%0A-%20call_args%0A-%20call_args_list%0A%u542B%u4E49%u663E%u800C%u6613%u89C1%uFF0C%u7528%u6CD5%u53C2%u8003%5B%u5B98%u65B9%u6587%u6863%5D%28http%3A//www.voidspace.org.uk/python/mock/mock.html%29%0A%0Amethod_calls%20%26%20mock_calls%0A%60%60%60%0A%3E%3E%3E%20mock%20%3D%20Mock%28%29%0A%3E%3E%3E%20mock.method%28%29%0A%3CMock%20name%3D%27mock.method%28%29%27%20id%3D%27...%27%3E%0A%3E%3E%3E%20mock.property.method.attribute%28%29%0A%3CMock%20name%3D%27mock.property.method.attribute%28%29%27%20id%3D%27...%27%3E%0A%3E%3E%3E%20mock.method_calls%0A%5Bcall.method%28%29%2C%20call.property.method.attribute%28%29%5D%0A%0A%3E%3E%3E%20mock%20%3D%20MagicMock%28%29%0A%3E%3E%3E%20result%20%3D%20mock%281%2C%202%2C%203%29%0A%3E%3E%3E%20mock.first%28a%3D3%29%0A%3CMagicMock%20name%3D%27mock.first%28%29%27%20id%3D%27...%27%3E%0A%3E%3E%3E%20mock.second%28%29%0A%3CMagicMock%20name%3D%27mock.second%28%29%27%20id%3D%27...%27%3E%0A%3E%3E%3E%20int%28mock%29%0A1%0A%3E%3E%3E%20result%281%29%0A%3CMagicMock%20name%3D%27mock%28%29%28%29%27%20id%3D%27...%27%3E%0A%3E%3E%3E%20expected%20%3D%20%5Bcall%281%2C%202%2C%203%29%2C%20call.first%28a%3D3%29%2C%20call.second%28%29%2C%0A...%20call.__int__%28%29%2C%20call%28%29%281%29%5D%0A%3E%3E%3E%20mock.mock_calls%20%3D%3D%20expected%0ATrue%0A%60%60%60%0A%0A%23%23%23%23assert%0AMock%u63D0%u4F9B%u4E86%u4EE5%u4E0B%u51E0%u79CDassert%uFF1A%0A-%20assert_called_once%0A-%20assert_called_with%0A-%20assert_called_once_with%0A-%20assert_has_calls%0A-%20assert_any_calls%0A%u524D%u9762%u4E09%u4E2A%u5F88%u76F4%u89C9%uFF0C%u540E%u9762%u4E24%u4E2A%u7A0D%u4F5C%u89E3%u91CA%u3002%0A%0Aassert_any_call%0A%3EThe%20assert%20assert_any_call%28%29%20checks%20if%20the%20test%20subject%20called%20a%20mocked%20method%20at%20any%20point%20of%20the%20test%20routine.%20This%20is%20regardless%20of%20how%20many%20other%20calls%20were%20made%20between%20the%20mocked%20method%20and%20the%20assert.%20%0A%0Aassert_has_calls%0A%3EThis%20one%20looks%20at%20a%20sequence%20of%20method%20calls%2C%20checks%20if%20they%20are%20in%20the%20right%20order%20and%20with%20the%20right%20arguments.%0A%0A%60%60%60%0Afrom%20mock%20import%20Mock%2C%20call%0A%20%0A%23%20The%20mock%20specification%0Aclass%20Foo%28object%29%3A%0A%20%20%20%20_fooValue%20%3D%20123%0A%20%20%20%20%20%0A%20%20%20%20def%20callFoo%28self%29%3A%0A%20%20%20%20%20%20%20%20pass%0A%20%20%20%20%20%0A%20%20%20%20def%20doFoo%28self%2C%20argValue%29%3A%0A%20%20%20%20%20%20%20%20pass%0A%20%0A%23%20create%20the%20mock%20object%0AmockFoo%20%3D%20Mock%28spec%20%3D%20Foo%29%0Aprint%20mockFoo%0A%23%20returns%20%3CMock%20spec%3D%27Foo%27%20id%3D%27507120%27%3E%0A%20%0AmockFoo.callFoo%28%29%0AmockFoo.doFoo%28%22narf%22%29%0AmockFoo.doFoo%28%22zort%22%29%0A%20%0AfooCalls%20%3D%20%5Bcall.callFoo%28%29%2C%20call.dooFoo%28%22narf%22%29%2C%20call.doFoo%28%22zort%22%29%5D%0A%20%0AmockFoo.assert_has_calls%28fooCalls%29%0A%23%20AssertionError%3A%20Calls%20not%20found.%0A%23%20Expected%3A%20%5Bcall.callFoo%28%29%2C%20call.dooFoo%28%27narf%27%29%2C%20call.doFoo%28%27zort%27%29%5D%0A%23%20Actual%3A%20%5Bcall.callFoo%28%29%2C%20call.doFoo%28%27narf%27%29%2C%20call.doFoo%28%27zort%27%29%5D%0A%20%0AfooCalls%20%3D%20%5Bcall.callFoo%28%29%2C%20call.dooFoo%28%22narf%22%29%2C%20call.doFoo%28%22zort%22%29%5D%0AmockFoo.assert_has_calls%28fooCalls%2C%20any_order%20%3D%20True%29%0A%23%20AssertionError%3A%20%28call.dooFoo%28%27narf%27%29%2C%29%20not%20all%20found%20in%20call%20list%0A%60%60%60%0A%0A%23%23%u9AD8%u9636%u7279%u6027%0A%23%23%23MagicMock%20vs.%20Mock%0A%3EWith%20Mock%20you%20can%20mock%20magic%20methods%20but%20you%20have%20to%20define%20them.%20MagicMock%20has%20%22%5Bdefault%20implementations%20of%20most%20of%20the%20**magic%20methods**%5D%28http%3A//www.voidspace.org.uk/python/mock/magicmock.html%23mock.MagicMock%29%22.%0A%3EIf%20you%20don%27t%20need%20to%20test%20any%20magic%20methods%2C%20Mock%20is%20adequate%20and%20doesn%27t%20bring%20a%20lot%20of%20extraneous%20things%20into%20your%20tests.%20If%20you%20need%20to%20test%20a%20lot%20of%20magic%20methods%20MagicMock%20will%20save%20you%20some%20time.%0A%0A%u54EA%u4E9Bmagic%20methods%uFF1F%u770B%u4E0B%u9762%0A*%20__lt__%3A%20NotImplemented%0A*%20__gt__%3A%20NotImplemented%0A*%20__le__%3A%20NotImplemented%0A*%20__ge__%3A%20NotImplemented%0A*%20__int__%20%3A%201%0A*%20__contains__%20%3A%20False%0A*%20__len__%20%3A%201%0A*%20__iter__%20%3A%20iter%28%5B%5D%29%0A*%20__exit__%20%3A%20False%0A*%20__complex__%20%3A%201j%0A*%20__float__%20%3A%201.0%0A*%20__bool__%20%3A%20True%0A*%20__nonzero__%20%3A%20True%0A*%20__oct__%20%3A%20%u20181%u2019%0A*%20__hex__%20%3A%20%u20180x1%u2019%0A*%20__long__%20%3A%20long%281%29%0A*%20__index__%20%3A%201%0A*%20__hash__%20%3A%20default%20hash%20for%20the%20mock%0A*%20__str__%20%3A%20default%20str%20for%20the%20mock%0A*%20__unicode__%20%3A%20default%20unicode%20for%20the%20mock%0A*%20__sizeof__%3A%20default%20sizeof%20for%20the%20mock%0A%60%60%60%0A%3E%3E%3E%20mock%20%3D%20MagicMock%28%29%0A%3E%3E%3E%20int%28mock%29%0A1%0A%3E%3E%3E%20len%28mock%29%0A0%0A%3E%3E%3E%20hex%28mock%29%0A%270x1%27%0A%3E%3E%3E%20list%28mock%29%0A%5B%5D%0A%3E%3E%3E%20object%28%29%20in%20mock%0AFalse%0A%60%60%60%0A%u6240%u8C13magic%20methods%u5C31%u662F%u4E00%u4E9B%u5185%u7F6E%u7684python%u8FD0%u7B97%u7B26%uFF0C%u800CMagicMock%u652F%u6301%u8FD9%u4E9B%u8FD0%u7B97%u7B26%uFF0CMock%u4E0D%u652F%u6301%0A%0A%23%23%23mock%20import%0A%5BMocking%20Python%20imports%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/d063563d-dc7d-4373-96a9-a0759de8e970%29%u8FD9%u91CC%u6709%u63D0%u5230%u3002%u5176%u5B9E%u5F88%u7B80%u5355%uFF0C%u770B%u4EE3%u7801%0A%60%60%60%0A%23%20A.py%0Aimport%20B%0AB.foo%28%29%0A%0A%23%20test.py%0AA.B%20%3D%20mock.Mock%28%29%0AA.B.foo.return_value%20%3D%20123%0A%60%60%60%0A%0A%23%23%23mock%20class%20constructor%0A%u76F4%u63A5%u8D34%u4E0A%u5B9E%u9645%u7684%u6D4B%u8BD5%u4EE3%u7801%0A%60%60%60python%0AmockSMBConnObj%20%3D%20mock.Mock%28%29%0AmockSMBConn%20%3D%20mock.Mock%28return_value%3DmockSMBConnObj%29%20%23%20mock%20constructor%0A%60%60%60%0A%0A%23%23%23mock%u5BF9%u8C61%u7684%u81EA%u52A8%u521B%u5EFA%0A%u5F53%u8BBF%u95EE%u4E00%u4E2Amock%u5BF9%u8C61%u4E2D%u4E0D%u5B58%u5728%u7684%u5C5E%u6027%u65F6%uFF0Cmock%u4F1A%u81EA%u52A8%u5EFA%u7ACB%u4E00%u4E2A%u5B50mock%u5BF9%u8C61%uFF0C%u5E76%u4E14%u628A%u6B63%u5728%u8BBF%u95EE%u7684%u5C5E%u6027%u6307%u5411%u5B83%uFF0C%u8FD9%u4E2A%u529F%u80FD%u5BF9%u4E8E%u5B9E%u73B0%u591A%u7EA7%u5C5E%u6027%u7684mock%u5F88%u65B9%u4FBF%u3002%0A%60%60%60%0Aclient%20%3D%20mock.Mock%28%29%0Aclient.v2_client.get.return_value%20%3D%20%27200%27%0A%60%60%60%0A%u4E0A%u9762%u4F8B%u5B50%u4E2D%60client.v2_client.get%60%u5C31%u662F%u81EA%u52A8%u751F%u6210%u7684mock%u5BF9%u8C61%0A%u7C7B%u4F3C%u81EA%u52A8%u751F%u6210%uFF0C%u6211%u4EEC%u8FD8%u53EF%u4EE5%u91C7%u7528%60attach_mock%60%u7684%u65B9%u6CD5%u3002%u4E0D%u540C%u7684%u662F%uFF0Cattach_mock%u4F1A%u8BA9%u88ABattach%u7684%u53CC%u65B9%u5177%u6709%u7236%u5B50%u5173%u7CFB%uFF0C%u5219%u5BF9%u5B50mock%u7684%u8C03%u7528%u4F1A%u88AB%u8BA1%u5165%u7236%u7684mock_calls%u3002%u53C2%u8003%5BAttaching%20Mocks%20as%20Attributes%5D%28http%3A//www.voidspace.org.uk/python/mock/mock.html%23attaching-mocks-as-attributes%29%0A%0A%23%23%23patch%0A%u901A%u8FC7patch%uFF0C%u6211%u4EEC%u53EF%u4EE5%u63A7%u5236Mock%u5BF9%u8C61%u7684%u751F%u5B58%u5468%u671F%u3002%u610F%u601D%u5C31%u662F%u5728%u4E00%u4E2A%u51FD%u6570%u8303%u56F4%u5185%uFF0C%u6216%u8005%u4E00%u4E2A%u7C7B%u7684%u8303%u56F4%u5185%uFF0C%u6216%u8005with%u8BED%u53E5%u7684%u8303%u56F4%u5185mock%u6389%u4E00%u4E2A%u5BF9%u8C61%u3002%0A%u6709%u4E0B%u9762%0A%0Adecorator%0A%60%60%60%0A%3E%3E%3E%20@patch%28%27__main__.SomeClass%27%29%0A...%20def%20function%28normal_argument%2C%20mock_class%29%3A%0A...%20%20%20%20%20print%20mock_class%20is%20SomeClass%0A...%0A%3E%3E%3E%20function%28None%29%0ATrue%0A%60%60%60%0A%0Acontext%20manager%0A%60%60%60%0A%3E%3E%3E%20class%20Class%28object%29%3A%0A...%20%20%20%20%20def%20method%28self%29%3A%0A...%20%20%20%20%20%20%20%20%20pass%0A...%0A%3E%3E%3E%20with%20patch%28%27__main__.Class%27%29%20as%20MockClass%3A%0A...%20%20%20%20%20instance%20%3D%20MockClass.return_value%0A...%20%20%20%20%20instance.method.return_value%20%3D%20%27foo%27%0A...%20%20%20%20%20assert%20Class%28%29%20is%20instance%0A...%20%20%20%20%20assert%20Class%28%29.method%28%29%20%3D%3D%20%27foo%27%0A%60%60%60%0A%0Apatcher%0A%60%60%60%0A%3E%3E%3E%20Original%20%3D%20Class%0A%3E%3E%3E%20patcher%20%3D%20patch%28%27__main__.Class%27%2C%20spec%3DTrue%29%0A%3E%3E%3E%20MockClass%20%3D%20patcher.start%28%29%0A%3E%3E%3E%20instance%20%3D%20MockClass%28%29%0A%3E%3E%3E%20assert%20isinstance%28instance%2C%20Original%29%0A%3E%3E%3E%20patcher.stop%28%29%0A%60%60%60%0A%0Apatch.object%u548Cpatch%u7C7B%u4F3C%uFF0C%u53EA%u662F%u5199%u6CD5%u4E0D%u540C%uFF0C%u770B%u4E0B%u9762%u5BF9%u6BD4%uFF1A%0A%60%60%60%0A@patch.object%28SomeClass%2C%20%27class_method%27%29%0A@patch%28%27SomeClass.class_method%27%29%0A%60%60%60%0A%0Apatch%u8FD8%u6709%u5F88%u591A%u79CD%u5176%u4ED6%u7528%u6CD5%uFF0Cpatch.multiple%2C%20patch.dict%u7B49%u7B49%u3002%u53C2%u770B%5BMore%20Patch%5D%28http%3A//www.voidspace.org.uk/python/mock/patch.html%23patch-dict%29%0A%0A%23%23%23%u5176%u4ED6%u672A%u51B3%u7684%u95EE%u9898%0A%u5176%u5B9E%u8FD8%u6709%u5F88%u591Amock%u9AD8%u7EA7%u7684%u7528%u6CD5%uFF0C%u4F8B%u5982%uFF0C%u5F53%u6211%u60F3mock%u6389win32com%u7684%u65F6%u5019%uFF0C%u641C%u5230%u7684%u8FD9%u4E2A%u7F51%u9875%5BMocking%20out%20python%20OS%20specific%20imports%5D%28http%3A//ilostmynotes.blogspot.com/2014/10/mocking-out-python-os-specific-imports.html%29%u3002%u5176%u4E2D%u6709%u4E00%u6BB5%u4EE3%u7801%uFF1A%0A%60%60%60%0A%20modules%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22_winreg%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22pythoncom%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22pywintypes%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22win32api%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22win32com%22%3A%20self.win32com%2C%0A%20%20%20%20%20%20%20%20%22win32com.client%22%3A%20self.win32com.client%2C%0A%20%20%20%20%20%20%20%20%22win32file%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22win32service%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22win32serviceutil%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22winerror%22%3A%20mock.MagicMock%28%29%2C%0A%20%20%20%20%20%20%20%20%22wmi%22%3A%20self.wmimock%0A%20%20%20%20%20%20%20%20%7D%0A%0Aself.module_patcher%20%3D%20mock.patch.dict%28%22sys.modules%22%2C%20modules%29%0Aself.module_patcher.start%28%29%0A%60%60%60%0A%u8FD8%u6709%u5982%u4F55mock%u6389win32com.client%u7684%u5BF9%u8C61%uFF1F%u4F8B%u5982%uFF0C%u5F85%u6D4B%u4EE3%u7801%u5982%u4E0B%0A%60%60%60%0AApplication%20%3D%20win32com.client.Dispatch%28%22PowerPoint.Application%22%29%0Asource_ppt%20%3D%20Application.Presentations.Open%28path%29%0Asource_ppt.Slides.InsertFromFile%28os.path.abspath%28chart%29%2C%20index%2C%201%2C%201%29%0A%60%60%60%0A%u56E0%u4E3A%u5BF9%60win32com.client%60%u5B9E%u73B0%u4E00%u65E0%u6240%u77E5%uFF0C%u4E0D%u77E5%u9053%u5982%u4F55mock%uFF0C%u63A8%u6D4Bmock%u4EE3%u7801%u5982%u4E0B%uFF0C%u8FD8%u672A%u9A8C%u8BC1%0A%60%60%60%0AmockApp%20%3D%20mock.Mock%28%29%0Awith%20mock.patch%28%27MyModule.win32com.client.Dispatch%27%2C%20return_value%3DmockApp%29%20as%20mockWin32com%3A%0A%09mockPpt%20%3D%20mock.Mock%28%29%0A%09mockApp.Presnetations.Open.return_value%20%3D%20mockPpt%0A%09mockPpt.Slides.InsertFromFile.assert_called_once_with%28...%29%0A%60%60%60%0A%0A%23%u603B%u7ED3%0A%u56E0%u4E3Apython%u7684%u8BED%u8A00%u7279%u6027%uFF0Cpython%u7684Mock%u6846%u67B6%u8FD8%u662F%u6BD4Java%u7684Mock%u6846%u67B6%u8981%u7075%u6D3B%u5F88%u591A%u3002%u6BD4%u5982%uFF1A%u5BF9%u7C7B%u6784%u9020%u51FD%u6570%u7684Mock%uFF0C%u975E%u5E38%u5BB9%u6613%uFF0C%u800CJava%u5219%u9700%u8981%u7ECF%u8FC7%u7279%u6B8A%u5904%u7406%u3002%u8FD8%u6709%u5BF9%u63A5%u53E3%u7684fake%u5316%uFF0C%u7528side_effect%u5F88%u5BB9%u6613%u5B9E%u73B0%uFF0C%u4F46%u662FJava%20Mock%u5219%u8981%u7528%u5230%60when%28%29.thenAnswer%28%29%7B%7D%60%u3002%u9EBB%u70E6%u53C8%u4E0D%u76F4%u89C9%u3002%0A%60%60%60%0Awhen%28...%29.thenAnswer%28new%20Answer%28%29%20%7B%0A%09@Override%0A%09public%20Object%20answer%28InvocationOnMock%20invocation%29%20throws%20Throwable%20%7B%0A%09%09return%20value%3B%0A%09%7D%0A%7D%29%3B%0A%60%60%60%0A

Edit

第1-6章

敏捷实践的原则

  1. 人比工具重要,应先构建团队,再让团队基于需要配置环境
  2. 直到迫切需要并且意义重大时,才来编制文档。针对系统原理和结构方面的文档,应仅论述系统的高层结构和概括的设计原理
  3. 客户合同指导协作,而不是试图去规定项目范围的细节和固定成本下的进度。
  4. 为下两周做详细的计划,为下三个月做粗略的计划,再以后就做极为粗糙的计划。

极限编程

  1. 客户作为团队成员
      * 用户素材(user stories): UML Use Case图的Feature。参看UML Distilled笔记

在XP中,我们和客户反复讨论,以获取对于需求细节的理解,但是不去捕获那些细节。我们更愿意客户在索引卡片上写下一些我们认可的词语,这些词语可以提醒我们记起这次交谈。基本上在和客户进行书写的同一刻,开发人员在该卡片上写下对应于卡片上需求的估算。估算时基于和客户进行交谈期间所得到的对于细节的理解进行的。

  1. 短交付周期,每2周迭代一次,并交付客户使用,每12周一次发布
  2. 每次交付都有客户针对feature的验收测试
  3. 结对编程
  4. 集体所有权,指不固定expert,凭兴趣决定想做的方向。
  5. 持续集成,类同第2点
  6. 可持续的开发速度。不允许加班,版本发布前一个礼拜例外

软件项目不是全速的短跑,它是马拉松长跑。

  1. 开放的工作空间
  2. 计划游戏
  3. 简单的设计
    XP团队总是尽可能寻找能实现当前feature的最简单的设计
  4. 重构是持续进行的,每隔一个小时或半个小时就要去做的事情。
  5. 隐喻 (没看懂)

总结,这里极限编程其实强调的更多的是软件开发团队的运作方式,需要各方面达成一致,才能严格按照他的每一条去做。但是,即便在我们现在的环境下,不管是极限编程还是敏捷方法都不为人所知,没办法完全开展。但是里面的一些观点很有启发意义,仍然可以应用到我们日常的项目当中。比如第一点,要求开发人员实时同客户交流,并选定feature或及时修改开发方案。第二点,不断的交付。其实都可以马上运用上。

第7-12章

虽然书没看完,但是感觉这一部分是全书的核心,即敏捷开发的原则。

什么是敏捷设计?
敏捷设计是一个过程,一个持续的应用原则、模式以及实践来改进软件的结构和可读性的过程。

换而言之,就是不要随随便便打补丁,让程序能运行满足需求修改,而是应用各种方法使程序更具弹性。另一方面,又不为了修改而修改,不为了子虚乌有的弹性,花费额外的精力来达到想象中的弹性设计。

8-12章为我们介绍了面向对象设计的5原则:

  • SRP: 单一职责原则
  • OCP: 开放封闭原则
  • LSP: Linskov替换原则
  • DIP: 依赖倒置原则
  • ISP: 接口隔离原则

逐一摘录如下:

SRP

在SRP中,我们把职责定义为“变化的原因”。如果你能想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。
如果应用程序的变化方式总是导致这两个职责同时变化,那么就不必分离他们。

第一次的设计,我们常见的
NA
分离过职责以后
NA
这样的设计,如果两个接口变化频率非常不一致时,可以减少重新部署的范围。

OCP

  1. 对于扩展开放
  2. 对于修改关闭

怎么能做到呢?看下面的图:

抽象类和它们的客户的关系要比和实现它们的类的关系更密切。
意思是,Client与Client Interface的关系要比其与Server的关系更密切。

说到这里,这个原则其实已经很清晰了,但作者希望告诉我们更多。在《是的,我说谎了》那一节里,作者告诉我们,事实并不总像想象中那么美好。往往会有各种稀奇古怪的需求,导致原先的设计不能对该需求导致的变化封闭。作者给了我们忠告:

设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最优可能发生变化的种类,然后构造抽象来隔离那些变化。
这是很不容易做到的,要根据经验猜测哪些应用程序在生长历程中有可能的变化。

如何隔离变化:

  1. 在发现第一次变化时,进行抽象改造。
  2. 通过测试+快速迭代来刺激变化,尽快将变化的可能暴露出来。

本章还介绍了一种很实用的封闭变化的方法,使用“数据驱动”方法。其实就是表格驱动。将变化的部分总结固化到表格中。

开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要

LSP

LSP - 子类型(的方法)必须能够替换掉它们的基类型(的方法)。

Linskov首次提出这个原则。
本章举的例子是正方形vs.矩形。以常理推论正方形IS-A矩形,所以正方形的类应当可以继承自矩形的类。但以替换原则看,在某些情况下正方形和矩形的行为并不一致。

void g (Rectangle& r)
{
r.SetWidth(5);
r.SetHeight(4);
assert(r.Area() == 20);
}

如果r传入的是正方形对象,则必然会出断言,所以这段代码不符合LSP。

OOD中IS-A关系是就行为方式而言。

可见,虽然代码是现实生活的抽象,但也不完全是。如何规避,或者说发现这种微妙的不同。作者给出一个方法就是基于契约的设计。通过设置前后置条件,来确定是否IS-A关系。

派生类中的例程

  • 只能使用相等或更弱的前置条件来替换原始的前置条件,
  • 只能使用相等或更强的后置条件来替换原始的后置条件。
  • 可以在单元测试中指定前后置条件,来看是否满足IS-A的关系,如果不满足就要重新设计。
  • 所谓条件强,即约束多,条件弱,即约束少。

如何让代码做到LSP,方法就是摒弃曾经的抽象方法,通过在实践中,总结两个类行为一致的部分,并提取出公有的抽象父类。下图是例子

有可能引起违反LSP的两种情况:

  1. 派生类中方法定义为空函数,这种情况虽然没有违反LSP,但仍然会引起引用父类指针时的微妙区别。
  2. 从派生类抛出异常,明显违犯LSP,如果要遵循LSP,要么需要修改父类及使用预期,要么不抛异常。

总结:子类型的正确定义是“可替换性的”,这里的可替换性可以通过显式或者隐式的契约来定义。

DIP

这一条很有启示意义。以前从来没这么想过,但经作者一说,其实解答之前很多的疑惑。

无论如何高层模块都不应该依赖于低层模块。我们更希望能够重用的是高层的策略设置模块。
何为高层策略?
它是应用背后的抽象,是那些不随具体细节的改变而改变的真理

Lamp并不依赖于Button,而是Button依赖于Lamp提供出的接口ButtonServer。而这个interface也不局限于Button,其实只要有开关策略的具体类都可以实现这个接口。但是所有这些低层类统统依赖于这个高层提供的接口。而低层模块,如Button的修改并不会影响到Lamp。
有一天Lamp需要修改这个接口的时候,所有的类都会受到影响。这就是高层影响低层。但是Lamp是高层策略,是隐喻,并不会经常改变。

再看这个例子。
原始的算法如下

ISP

这个规则要解决的问题叫接口污染。
何为接口污染?看下面这个例子

接口隔离原则:不应该强迫客户依赖于它们不用的方法。

实现ISP的两个途径

委托

这个不太好理解,而且这个方法按作者的说法也不是很好。

  • 当Timed Door需要一个定时例程的时候,它先创建一个Door Timer Adapter对象,并以Timer Client的形式注册给Timer
  • 当Timer计时到达时,Door Timer Adapter的Timeout会被调用
  • 进而因为委托,会调用Timed Door的DoorTimeOut

这样做,就不需要Door来实现Timer接口,防止了接口污染。缺点是,每次需要定时程序的时候,都要创建一个Door Timer Adapter对象,浪费资源。

多重继承

看上面的委托的例子,其实就很容易想到多重继承了。只要对TimedDoor采用多重继承就好了,既不影响Door的其他子类,又能使TimedDoor具有Timer和Door的双重功能。
采用多重继承后,上面例子的解决方案变成:

另外一个例子

这里有两点要注意:

应该这样写:

也不要这样写:

引申下来

void g(DepositUI&, TransferUI&);
void g(UI&);

哪种写法好?其实一目了然。肯定是第一种,虽然看起来有点啰嗦。作者告诉我们了:

无论是否有悖常理,多参数形式通常都应该优于单参数形式使用。

ISP的两点建议

  1. 对客户分组。就像上面ATM的例子,对Transaction分类隔离。不同的客户要求的服务可能有重叠,如果重叠少就隔离,重叠多就抽取公共抽象类。
  2. 改变接口尽量通过新加接口来做,避免修改现有接口。因为你的子类可能正在用这个接口。

第13-19章

本书的第三~六部分,结合4个比较大型的例子,讲解了一系列设计模式。本部分涉及的模式有:

  • COMMAND & ACTIVE OBJECT
  • TEMPLATE METHOD & STRATEGY
  • FACADE & MEDIATOR
  • SINGLETON & MONOSTATE
  • NULL OBJECT
    其实每个模式,在看书的时候,结合作者给出的例子,很容易理解,也知道他在说什么,但是如果想要应用到实际的开发中,还是有一定难度的。作者在后文中,也给出一个例子,教读者如何通过抽象总结寻找适合自己的设计模式。但是不管怎么说,对每一个设计模式的特点和目的总要有一个清醒的认识,才能灵活的加以应用。

COMMAND & ACTIVE OBJECT

这两个模式都是基于对操作的封装。ACTIVE OBJECT模式基于COMMAND模式。下图就是COMMAND模式:

什么时候用COMMAND模式?

COMMAND模式可以分离操作发起者和操作本身。比如下面需要sensor驱动事件的模型。

若不采用COMMAND模式,sensor需要知道调用什么函数做什么操作。若采用COMMAND模式后,高层的掌握事件逻辑的模块,对sensor和事件进行绑定,之后sensor就可以对事件进行无差别的调用(command->do())。从而达到事件执行者和事件本身的解耦

ACTIVE OBJECT呢?

ACTIVE OBJECT基于COMMAND模式,有如下的简单结构:

public class ActiveObject{
Command itsCommands[];
public void run(){
for each command{
do();
}
}
public void addCommand(Command cmd) {
itsCommands.append(cmd);
}
}

该模式分离了任务的提交与任务的运行。按作者的说法,并参考网上其他的笔记,这个古老的设计模式往往会带来意想不到的好效果。

  1. 它可以模拟多线程的运行。实际上线程例程也可以是一个active object
  2. 我们可以在Command的do接口中决定下一步的操作,可以达到控制整个active object运行还是停止的效果。

TEMPLATE METHOD & STRATEGY

TEMPLATE METHOD

在我看来,TEMPLATE METHOD并不能称为一种设计模式,只是把一些相同的流程,抽象成一个抽象基类,然后所有的派生类重用这个流程。但这往往沦为鸡肋,因为派生类总是在某个不确定的时间表现出不一样的行为,然后整个抽象的结构就被补丁打的面目全非。作者说,对TEMPLATE METHOD一定要慎之又慎,往往会出现模式滥用的情况。
TEMPLATE METHOD有一个很典型的例子,就是Bubble Sort。不管是对数字做冒泡,还是对字符做冒泡,还是对自定义对象做冒泡,其核心算法总是一样的。其不同在于

  1. 两个对象的比较操作
  2. 两个对象的交换操作

如此就可以很好的使用TEMPLATE METHOD了。把这两个操作作为接口抽象出来,冒泡排序的核心算法就是TEMPLATE METHOD了。
我觉得只有在这种超经典的环境下,才可以使用TEMPLATE METHOD。否则还是考虑其他模式吧。

STRATEGY

FACADE & MEDIATOR

FACADE

当想要为一组具有复杂且全面的接口的对象提供一个简单且特定的接口时,可以使用队FACADE模式 。

MEDIATOR

SINGLETON & MONOSTATE

这两个模式都是单例模式,一个关注结构(SINGLETON),一个关注行为(MONOSTATE)。

何时需要单例?

作者在本章开篇的时候说,

那些强制对象单一性的机制似乎有些多余。毕竟 ,在初始化应用程序时,完全可以只创建每个
对象的一个实例,然后使用该实例。事实上,这通常也是最好的方法。在没有急迫并且有意义的需要 时,应该避免使用这些机制

那到底什么时候才是使用SINGLETON的正确时机呢?作者接着说了

我们也希望代码能够传达我们的意图。如果强制对象单一性的机制是轻量级的,那么传达意图带来的收益就会胜过实施这些机制的代价。

所以使用单例要符合两个元素:

  1. 机制轻量级,也就是逻辑要简单
  2. 需要传达只允许一个实例的意图

作者在本章结尾处指出:

如果希望透过派生去约束一个现存类,并且不介意它的所有调用者都必须要调用instance()方法来获取访问权,那么SINGLETON是最合适的。如果希望类的单一性本质对使用者透明,或者希望使用单一对象的多态派生对象,那么MONOSTATE是最适合的。

应用场景,例如:

  • 工厂对 象(factories),用来创建系统中的其他对象。
  • 管理器(managers)对象,负责管理某些其他对象并以合适的方式去控制它们。

因为这些类实例一旦产生超过一个,就会因为对象之间的同步问题,产生逻辑问题。

SINGLETON

public class Singleton {
private static Singleton theInsLance = null;
private Singleton() {}
public static Singleton Instance()
{
if (theIristance == null)
theInstance = new Singleton();
return theInstance;
}
}

私有构造函数,通过static接口来做实例化,控制类实例只有一个。
下面的例子是Phoenix代码中最常见的单例模式。

class Child : public Parent
{
Child(){}
}
class Factory{
static Parent* Instance ()
{
static Child child;
return &child;
}
}

利用局部的static变量实现单例。不管用上面的哪种方式,其实例化过程都不是经典的面向对象方法,而需要调用者遵循约定,调用特殊的接口以创建类实例。其创建的实例确实都指向同一个真正的对象。

MONOSTATE

此模式与SINGLETON不同,MONOSTATE强调的是所有创建的对象具有相同的行为。

public class MonoState {
private static int itsX;
public void setX(int x) {
itsX = x;
}
public int getX(){
return itsX;
}
}

这里有一个约定:所有的类成员均为static,所有的方法均为非static
所有方法为非static的用意是,其接口均可继承到派生类中。所有成员变量是static,一方面保证所有类对象具有相同属性,另一方面也保证了MONOSTATE类的派生类都具有MONOSTATE特性。而实际上,所有派生类都共享同一个MONOSTATE的一部分。

NULL OBJECT模式

这是一个很实用,但又总是很容易被忽略的模式。我们在写code的时候,下面的情况很常见:

Employee e = DB.getEmployee("Bob");
if (e != null && e.isTimeToPay(today))
e.pay();

先获得一个对象,在失败时返回null,然后根据返回的结果做下一步操作。使用NULL OBJECT以后的样子,可能是这样的:

Employee e = DB.getEmployee("Bob");
if (e.isTimeToPay(today))
e.pay();
public class NullEmployee {
public boolean isTimeToPay(Date data) {
return false;
}
}

进阶NULL OBJECT

import java.util.Date;
public interface Employee
{
public boolean isTimeToPay(Date payDate);
public void pay();
public static final Employee NULL = new Employee()
{
public boolean isTimeToPay(Date payDate)
{
return false;
}
public void pay()
{
}
};
}

使无效雇员类成为一个匿名内嵌类是一种确保该类只有单一实例的方法。实际上并不存在NullEmplyee类本身。其他任何人都无法创建NULL类实例。并且static final变量也保证了NULL的单例性。如果NULL不能做到单例的话,会引发歧义,导致不可预知的错误。

第20-22章

本部分只讲了一个模式(FACTORY),但放入了一个很有用的章节——关于包的设计原则。包是类的集合,当软件达到一定规模时,就需要考虑包的设计了。我觉得这值得反复阅读。我打算颠倒书上的顺序,先罗列FACTORY模式,再来看包设计规则。

FACTORY

这个模式,是我阅读这本书迄今为止(还有第四部分的三章未看),最有用的模式。他回答了我到底该在哪里传入多态绑定信息。

class Child1 : Parent{}
class Child2 : Parent{}
switch (info){
case A:
Parent* obj = new Child1();
break;
case B:
Parent* obj = new Child2();
break;
}

上面这一段不管是早绑定,迟绑定,总是要出现的。放在哪里?放在FACTORY里。
为什么要放到FACTORY里?换句话说:

为什么要使用FACTORY?

作者说:

FACTORY模式允许我们只依赖于抽象接口就能创建出具体对象的实例。所 以 ,在正在进行的开发期间,如果具体类是髙度易变的,那么该模式是非常有用的。

严格按照DIP来讲,必须要对系统中所有的易变类使用工厂。针对这句话,作者又说:

我不是一开始就使用丁厂。只是在非常需要它们的情况下,我才把它们放入到系统中。例如,

  • 如果有必要使用PROXY模式,那么就可能有必要使用工厂去创建持久化对象。
  • 或者,在单元测试期间,如果遇 到必须要欺骗一个对象的创建者的情况时,那么我很可能会使用工厂。

但是我不是一开始就假设工厂是必要的。

一开始,不理解这句话,现在深深体会,工厂模式真的好,很容易被滥用。我现在就有滥用的倾向。

public interface IFactory{
public IObject makeObject();
}
public class Factory implements IFactory{
@Override
public IObject makeObject(){
return new Object();
}
}
public class Invoker{
public void func(){
IFactory factory = new Factory();
IObject = factory.makeObject();
}
}

Invoker类完全依赖于抽象的接口——工厂接口和Object接口,而不依赖于具体的类。在开发阶段,或者类结构不稳定阶段,我们可以任意修改makeObject接口的实现来生产我们需要的对象。

工厂模式在单元测试中也是很有用的。我们可以通过替换具体的工厂类来实现真实的类和mock类之间的切换。当然我们也可以用mockito来帮我们做这些事情。如果类庞大的mockito解决不了,一个工厂类可能会给我们提供意想不到的方便。

作者的例子:
在 某 些 情 况 下 , Payroll Test把 Database的引用传递给Payrol l是相当自然的,在另一些情况下,有可能PayrollTest必须设置一个全局变量保存对Database的引用。还有一些情况下Payroll可能完全期望自己来创建Database实例。在最后一种情况中,可以使用FACTORY模式,通过传给Payroll另外一个工厂对象,来欺骗Payroll创建出Database的测试版本。

包设计原则

粒度3原则——如何决定哪些类应当放入一个包

REP ——Reuse-Release Equivalence Principle 重用发布等效原则

一个包中的软件要么都是可重用的,要么都是不可重用的。我们不希望一个用户发现包中所包含的类中,一些是他所需要的,另一些对他却完全不适合。
我理解的意思就是,考虑问题要以包为最小粒度。类似类设计的SRP,单一职责原则。

CRP——Common Reuse Principle共同重用原则

CRP规定相互之间没有紧密联系的类不应该在同一个包中

CCP——Common Close Principle共同封闭原则

这条原则规定了一个包小应该包介多个引起变化的原因。

稳定性原则

如何避免”晨后综合症”

  • 每周构建
  • ADP——Acyclic Dependencies Principle无环依赖

有依赖环,则会影响到环上节点相关的所有节点,进而导致整个软件包的崩溃。所以切记,依赖关系分析很重要,绝不能有依赖环。

解除依赖环的方法

  1. 依赖倒置(DIP)

  1. 定义出共同依赖的包

20.5&20.6是本章的核心,在这两节中,作者阐述了如何定量地分析包的稳定性,并指导我们究竟改如何分布稳定类和非稳定类。这其中有一句话,让我印象颇为深刻:

并不是所有的类都适合作为稳定类。

这一章内容适合反复研读,我打算留做下一次再来做笔记。

23-27章

COMPOSITE

这个模式是对COMMAND模式的扩展。为的是让多个对象的行为表现的像一个对象。例如:

OBSERVER

这一章,作者给出了如何从最基本的coding方式,推演出如何套用合适的模式。其基本思想就是

不要过度设计,而是在不断的重构中,向某一种模式不断靠近,当其结构已经演化成某一种模式时,将所有的名称修改为该模式的术语,从而达到使用模式的目的

这实际是本章的精髓。
不过本章在阐述上述蜕化演进的过程的时候,以OBSERVER模式为例,也将这个模式的原理和使用方法讲的很清楚了。

两种模式——推&拉

拉模式适合简单的信息交互,Observer知道去Subject拉什么信息。
腿模式适合复杂信息交互,由Subject告诉Observer什么信息发生了变化。

ABSTRACT SERVER, ADAPTER&BRIDGE

ABSTRACT SERVER

这个模式很简单,很容易理解,看下面两幅图:

  • 对Switch的继承,总是带上了Light信息,有可能导致修改
  • 高层Switch依赖于Light

右边的图将Switch接口抽象出来,不管控制什么设备,只要定义了该接口就可以。
在这里,始终萦绕我的一个问题又出现了,就是何时实例化Light类?按照图25.2的逻辑,应该是Switch包含一个Light对象,在调用Switch的turnOn时,委托给Light的turnOn。

  1. 那么到25.3中,就应该是Switch持有一个Switchable的对象(可能是Light或者Fan等等)。那就可能是由某个工厂来产生这个对象给Switch。
  2. 还有一种可能就是,由客户逻辑来实现Switch和Switchable对象的绑定。例如Switch.setSwitchable(Light)。在Switch中无差别的使用Switchable接口。

两个都是我的理解,不一定正确。以后若有机会与大师交流,可以当面提出这个问题。

谁拥有这个接口

在这一章作者还提出了一个很值得重视的问题(其实在前面的章节已经出现过),就是接口到底该和谁打包?看作者的阐述:

客户和接门之间的逻辑绑定关系要强于接口和它的派生类之间的逻辑绑定关系。它们之间的关系强到在没有Switchable的情况下就无法使用Switch;但是,在没有口Light的情况下却完全可以使用Switch。逻辑关系的强度和实体 关系的强度是不一致的。继承是一个比关联强得多的实体关系。

换句话说,我们应当按照逻辑关系的强弱来决定包的边界,即接口的客户应当接口的定义。继承关系是天然的,我们应当参考的是类之间的逻辑关系。

ADAPTER

先看什么是ADAPTER模式
一般形式的ADAPTER:

BRIDGE

Bridge模式在这本书上的内容没看懂,去参考设计模式圣经——《设计模式》。不愧为经典书,讲解的很清楚透彻。
书中给的例子是Window System,看下图:

  1. Window系统自身的演化
  2. 各个平台对Window系统的实现
    如果他们都依赖于同一个继承关系,那就会出现类继承失控的现象。Bridge模式的出现就是为了解决这个问题。

这就是一个经典的Bridge模式。抽象的Window类和各平台的实现部分在各自的类层次结构中分别演化。Window与WindowImp之间的关系称为桥接。代码示例如下:

class Window
{
public:
virtual void DrawLine(const Point&, const Point&) = 0;
protected:
WindowImp* GetWindowImp(); //**********
private:
WindowImp* _imp;
View* _contents;
}
class WindowImp
{
public:
virtual void DrawLineImp(const Point&, const Point&) = 0;
}
class IconWindow : public Window
{
public:
virtual void DrawLine(const Point& a, const Point& b)
{
WindowImp* imp = GetWindowImp();
imp->DrawLineImp(a, b);
}
}

这里很有意思的是Window类的派生类,通过Window的protected接口来访问到对应的Imp接口。而GetWindowImp可能利用一个抽象工厂,来生成需要的对象。GetWindowImp可以在这个工厂中检测当前的平台来实例化对应的WindowImp类。

Bridge模式一些值得注意的地方

  1. 仅有一个Implementor的时候,没有必要创建一个抽象的Implementor类
  2. 实例化Imp类的方法有:
    • 如果根抽象类知道所有的Implementor实现类,则可在其构造函数中根据需要来实例化一个Implementor类
    • 首先选择一个默认的实现,然后根据需要改变这个实现
    • 采用工厂模式来生产对应的Imp类对象
  3. 在C++中,可以使用多重继承结合两个抽象层次。但是这种办法依赖于静态继承。因此不可能用多重继承的方法来实现真正的Bridge模式。以Window系统为例,如果一个窗口类继承Window和WindowImp抽象类,但是他并没有获得XWindow的实现。

敏捷软件开发中的Bridge模式

再回到《敏捷软件开发》这本书,看下图:

  • ModemConnectionController定义了两个接口:原有的Modem和新的DedicatedModem。
  • ModemConnectionController中所有的Imp接口均为Protected,只能被其子类使用。
  • ModemConnectionController在适当的时机,实例化对应Modem的硬件实现,并将所有的Imp接口委托给这个实例。

用代码来阐述可能更直观:

public interface Modem {
public void Dial();
}
public interface DedicatedModem {
public void Send();
}
public abstract class ModemConnectionController implements Modem, DedicatedModem{
private ModemImplementation _imp;
protected ModemImplementation GetImp(int token){
switch (token) {
case 1:
return new Object();
}
}
protected void DialImpl(){
return GetImp(mToken).Dial(); // delegate
}
protected void SendImpl(){
return GetImp(mToken).Send(); // delegate
}
public void Dial() {}
public void Send() {}
}
public class DedModemController extends ModemConnectionController {
public void Dial(){ /* own version of Dial */ }
public void Send(){ return DialImpl(); }
}
public class DedUser {
void main(){
DedicatedModem dedModem = (DedicatedModem)new DedModemController;
dedModem.Dial();
dedModem.Send();
}
}
public class OldUser {
void main(){
Modem modem = (Modem)new HayesModem;
modem.Dial();
modem.Send();
}
}

因为*Impl函数的存在,DedModem可以演变成独立的类演化序列。

PROXY

下图是一个典型的PROXY模式:

每个要被代理的对象都被分成3个部分:

  1. 一个接口,声明了客户要调用的所有方法
  2. 一个 类在不涉及数据库逻辑的情况下实现了接口中的方法
  3. 一个知晓数据库的代理

这个例子应该己经消除了所有关于使用代理是简单和优雅的错误认识。使用代理是有代价的。规范模式中所隐含的简单委托模型很少能够被优美地实现。相反,我们经常会取消对于繁琐的获取和设置方法的委托。

关于缓存

你可能会认为ProductProxy的实现是非常低效的。在每个访问方法中,它都会去使用数据库。如果它把ProductData条目进行缓存来避免访问数据库不是会更好一些吗?
虽然这个更改非常简单,但是促使我们这样做的惟一原因就是我们的恐惧。此时 ,还没有数据显示出这个程序具有性能问题。此 外,数据库引擎本身也会做一些缓存处理,所以建立自己的缓存会给我们带来什么好处并不明显。在做这些麻烦的工作前,我们应该等待,直到我们看到性能问题的迹象。
如果你担心性能可能是个问题,我建议你做一些试验去证明它确实是一个问题。当且仅当得到证实时,你才应该考虑如何去提速。

STAIRWAY TO HEAVEN

STAIRWAY TO HEAVEN使用了类形式(class form )的ADAPTER模式的一个变体.

  • 核心部分就是上半部分的Product,PersistentObject和PersistentProduct,下面Assembly相关的部分是对Product部分的扩展
  • PersistentProduct通过Product得到产品逻辑,通过PersistentObject获得障碍(数据库,网络等等)操作逻辑。
    对比看PROXY的静态模型

管理第三方API

在我们刚开始使用第三方API的时候,往往是这样的:

作者在本章最后还提到了几个操作第三方API的模式:

  • Extension Object
  • VISITOR
  • Decorator
  • Facade

作者最后的结论很有指导意义:

远在真正需要PROXY模式或者STAIRWAY TO HEAVEN模式前,就去预测对于它们的需要是非常有诱惑力的。但这几乎从来都不是一个好主意,特别是对于PROXY模 式。我建议在开始时先使用FACADE模式,然后在必要时进行重构。如果这样做的话,就会为自己节省时间并省去麻烦。

我在做微信IoT打印安卓端开发的时候,也是谨遵作者的教诲。FACADE模式前面有专门的章节介绍。这里再放一个本章的关于FACADE的截图。

28-30章

VISITOR

VISITOR模式是一个很好的模式,他可以给现有的框架打补丁。作者给的例子是关于Modem的

  1. 一次次修改变成一次性操作。在Modem的接口中添加VISITOR接口,即上图中的accept。
  2. 当客户代码要为Unix配置的时候,调用对应实体Modem类的accept接口,该接口会调用Visitor->visit,并传入自身上下文
  3. 在visit里面就可以调用各个Modem暴露出来的public方法了,注意不是Modem接口哦,是具体类的public方法
  4. 如果我们需要其他的访问代码,我们可以加一个类,并定义ModemVisitor接口就可以了。这个类可以做任意想做的事情,不局限于ModemConfigurator

这里还学到一个java的小知识:
我们知道有private, protected, public,如果不写默认是什么?

  • C++里默认是private
  • Java里不写的话,表示包级访问权限,意即只有同一个包里的代码可以调用。如果软件只有一个包,就等同于public。因为Java中没有friend关键字,这一功能可以起到一部分friend的作用。其实也就是Java的作者认为,包内的类都是友元。

ACYCLIC VISITOR模式

acyclic —— 无环的,这里指没有依赖环。

为何有ACYCLIC变体

作者在本节一开始的时候就介绍了为什么要在VISITOR的基础上引入ACYCLIC变体。不过我想了好久,也没太理解。暂且罗列如下:

请注意,被访问 (Modem)层次结构的基类依赖于访问者层次结构(ModemVisitor)的基类。同样请注意,访问者层次结构的基类中对于被访问层次结构中的每个派生类都有一个对应函数。因此,就有一个依赖环把所有被访问的派生类(所有的调制解调器)绑定在一 起。这样,就很难实现对访问者结构的增量编译,并且也很难向被访问层次结构中增加新的派生类。
如果程序中要更改的层次结构不需要经常地增加新的派生类,那么VISITOR模式工作的很好。如果我们很可能只需要Hayes、Zoom以及Ernie,或者很少会去增加新的Modem派生类,那么VISITOR模式将会非常合适。
另一方面,如果被访问层次结构非常不稳定,经常需要创建许多新的派生类,那么每当向被访问 层次结构中增加一个新的派生类时,就必须要更改并且重新编译VISITOR基类(也就是ModemVisitor)以及它的所有派生类。在C++中,情况甚至更糟。每当增加任何一个新的派生类时,整个被访问层次结构就必须要被重新编译、重新部署。

谈一下我的理解。这可能和Java的编译过程有关系。先把VISITOR中的类图拷过来:

  • ModemVisitor要添加一个接口
  • 因为依赖关系Modem要重新编译
  • 定义了Modem接口的类都要重新编译

关于C++的描述:

在C++中,情况甚至更糟。每当增加任何一个新的派生类时,整个被访问层次结构就必须要被重新编译、重新部署。

在C++中,interface一般会是一个头文件,被所有实体类包含,一个头文件改动,则该类图中所有的类都会需要重新编译。

*这里只强调编译,链接总是都要重新做的。

ACYCLIC VISITOR

理解了为何要有ACYCLIC变体以后,再看什么是ACYCLIC VISITOR:

  1. 针对每个Modem类都有一个Visitor接口,注意是接口
  2. UnixModemConfigurator定义了所有Modem的Visitor接口,并且也定义了那个空的接口ModemVisitor。这样Modem就可以通过ModemVisitor接口访问到UnixModemConfigurator了。
  3. 因为ModemVisitor是一个空接口(退化的),所以不管添加多少Modem实体类,ModemVisitor都不用修改,那Modem接口不用跟着重新编译。只有新增加的Modem实体类和UnixModemConfigurator会被编译。

ACYCLIC VISITOR很巧妙地解决了依赖环的问题。他的缺点是,在实体Modem类中,需要对传入的ModemVisitor接口进行强制类型转化,变成对应的Visitor接口。这会对执行效率引入不确定性。

更糟糕的是,转型花费的时间依赖于被访问层次结构的宽度和深度,所以很难进行测定。由于转型需要花费大量的执行时间,并且这些时间是小可预测的,所以ACYCLIC VISITOR模式不适用于严格的实时系统。
对于那些被访问的层次结构不稳定,并且增暈编译比较重要的系统来说,该模式是一个不错的选择 。

何时使用VISITOR模式

报表生成器

其他

一般来说,如果一个应用程序中存在有需要以多种不同方式进行解释的数据结构,就可以使用VISITOR模式。

其实就是实现数据与视图的分离,类似MVC的概念。

DECORATOR

最早接触decorator是在python的@语法,参看这篇笔记理解Python中的装饰器。那时候还不懂什么设计模式。
最近在做Android程序的JUnit代码里也有装饰器。可见其应用之广。
现在就可以看一下正规的Decorator怎么做?

Decorator的主要作用就是消除重复代码。

如果有多个Decorator,要消除委托代码的重复,可以用下面的类图:

EXTENSION OBJECT

  • Part用HashMap管理PartExtension
  • PartExtension是一个退化的接口(即无方法的接口),所以使用的时候会要做强制类型转换
  • PartPiece和Assembly在构造的时候添加对应的extension object,则在需要的时候可以get出来
  • PartPiece和Assembly在extension构造的时候,把自己传给该extension,则实现了Visit功能。

为什么要有EXTENSION OBJECT

Visitor可以实现不去修改类层次结构的情况下,向其中添加新功能。但是所有的访问功能都在一个类当中,如我们例子是在UnixModemConfigurator中,而且对每个Modem类只有一个visit函数。
当我们需要隔离对各个类的访问进行隔离,或者需要对一个类有不同的访问方式,VISITOR模式就做不到了。
于是有升级版的VISITOR,也就是EXTENSION OBJECT。每一个类可以有任意多的访问方式,且每个类之间的访问和不同访问方式之间都是隔离的。例如本例中,有两个被访问的类(PartPiece & Assembly),有两种访问方式(XML & CSV)。所以总共有4个extension object。

*作者时时在提醒我们

  • 所有代码是从测试用例演化而来,所有代码都刚好让测试通过,不多也不少。(这个节奏很难把握,还在学习中)
  • 不要为了模式而模式,而是先有代码,要消除重复,重构时才慢慢演化成适当的模式。而模式并不一定是标准的,有可能是经过修改而适合使用的

看看最一开始的代码可能是这样的

public PartExtension getExtension(String extensionType)
{
if (extensionType.equals(""XML"))
return new XMLPiecePartExtension(this);
else if (extensionType.equals("CSV"))
return new XMLAssemblyExetnsion(this);
return new BadPartExtertsion();
}

STATE

STATE模式这就是有限状态机。其应用相当广泛——UI,数据接口(例如control panel的命令)等等。下面是十字转门的状态迁移图。

看看真正的STATE模式是怎么实现的:

  • TurstyleState的派生类,代表状态本身
  • Turnstyle代表了整个系统,其包含了所有状态对象,也包含了所有状态迁移时产生的动作
  • TurstyleState的派生类负责调用Turnstyle的状态迁移接口,和迁移动作。

STATE模式彻底地分离了状态机的逻辑和动作。动作是在Context类中实现的,而逻辑则是分布在STATE类的派生类中。这就使得二者可以非常容易地独立变化、互不影响。

STATE vs. STRATEGY

在STATE模式中,派生类持有回指向上下文类的引用。派生类的主要功能是使用这个引 用选择并调用上下文类中的方法。在STRATEGY模式中,不存在这样的限制以及意图。STRATEGY的派生类不必持有指向上下文类的引用,并且也不需要去调用上下文类的方法。所以,所有的STATE模式实例同样也是STRATEGY模式实例,但是并非所有的STRATEGY模式实例都是STATE模式实例

SMC——状态机编译器

这是一个代码生成器。在前面介绍STATE模式的时候,会发现,其实最核心的部分就是状态迁移表。这样一章表格其实包含了整个有限状态机系统所有的逻辑。而SMC就是根据这样一张类似的表格来生成STATE模式中的各个类。

%0A%23%u654F%u6377%u8F6F%u4EF6%u5F00%u53D1%uFF0D%u539F%u5219%u3001%u6A21%u5F0F%u4E0E%u5B9E%u8DF5%0A@%28myblog%29%5B%u8F6F%u4EF6%u5F00%u53D1%2C%20%u8BBE%u8BA1%u6A21%u5F0F%5D%0A%0A%5BTOC%5D%0A%0A%23%23%u7B2C1-6%u7AE0%0A%23%23%23%u654F%u6377%u5B9E%u8DF5%u7684%u539F%u5219%0A1.%20%u4EBA%u6BD4%u5DE5%u5177%u91CD%u8981%uFF0C%u5E94%u5148%u6784%u5EFA%u56E2%u961F%uFF0C%u518D%u8BA9%u56E2%u961F%u57FA%u4E8E%u9700%u8981%u914D%u7F6E%u73AF%u5883%0A2.%20%u76F4%u5230%u8FEB%u5207%u9700%u8981%u5E76%u4E14%u610F%u4E49%u91CD%u5927%u65F6%uFF0C%u624D%u6765%u7F16%u5236%u6587%u6863%u3002%u9488%u5BF9%u7CFB%u7EDF%u539F%u7406%u548C%u7ED3%u6784%u65B9%u9762%u7684%u6587%u6863%uFF0C%u5E94%u4EC5%u8BBA%u8FF0%u7CFB%u7EDF%u7684%u9AD8%u5C42%u7ED3%u6784%u548C%u6982%u62EC%u7684%u8BBE%u8BA1%u539F%u7406%0A3.%20%u5BA2%u6237%u5408%u540C%u6307%u5BFC%u534F%u4F5C%uFF0C%u800C%u4E0D%u662F%u8BD5%u56FE%u53BB%u89C4%u5B9A%u9879%u76EE%u8303%u56F4%u7684%u7EC6%u8282%u548C%u56FA%u5B9A%u6210%u672C%u4E0B%u7684%u8FDB%u5EA6%u3002%0A4.%20%u4E3A%u4E0B%u4E24%u5468%u505A%u8BE6%u7EC6%u7684%u8BA1%u5212%uFF0C%u4E3A%u4E0B%u4E09%u4E2A%u6708%u505A%u7C97%u7565%u7684%u8BA1%u5212%uFF0C%u518D%u4EE5%u540E%u5C31%u505A%u6781%u4E3A%u7C97%u7CD9%u7684%u8BA1%u5212%u3002%0A%0A%23%23%23%u6781%u9650%u7F16%u7A0B%0A1.%20%u5BA2%u6237%u4F5C%u4E3A%u56E2%u961F%u6210%u5458%0A%26nbsp%3B%09%09*%20%u7528%u6237%u7D20%u6750%28user%20stories%29%3A%20UML%20Use%20Case%u56FE%u7684Feature%u3002%u53C2%u770B%5BUML%20Distilled%u7B14%u8BB0%5D%28https%3A//www.evernote.com/shard/s24/nl/2724128/40ed6ed0-a555-4b13-9226-6fafe34a9254%3Ftitle%3DUML%2520Distilled%2520%28UML%25E7%25B2%25BE%25E7%25B2%25B9%29%29%u3002%0A%3E%u5728XP%u4E2D%uFF0C%u6211%u4EEC%u548C%u5BA2%u6237%u53CD%u590D%u8BA8%u8BBA%uFF0C%u4EE5%u83B7%u53D6%u5BF9%u4E8E%u9700%u6C42%u7EC6%u8282%u7684%u7406%u89E3%uFF0C**%u4F46%u662F%u4E0D%u53BB%u6355%u83B7%u90A3%u4E9B%u7EC6%u8282**%u3002%u6211%u4EEC%u66F4%u613F%u610F**%u5BA2%u6237%u5728%u7D22%u5F15%u5361%u7247%u4E0A%u5199%u4E0B%u4E00%u4E9B%u6211%u4EEC%u8BA4%u53EF%u7684%u8BCD%u8BED**%uFF0C%u8FD9%u4E9B%u8BCD%u8BED%u53EF%u4EE5%u63D0%u9192%u6211%u4EEC%u8BB0%u8D77%u8FD9%u6B21%u4EA4%u8C08%u3002%u57FA%u672C%u4E0A%u5728%u548C%u5BA2%u6237%u8FDB%u884C%u4E66%u5199%u7684%u540C%u4E00%u523B%uFF0C%u5F00%u53D1%u4EBA%u5458%u5728%u8BE5%u5361%u7247%u4E0A%u5199%u4E0B%u5BF9%u5E94%u4E8E%u5361%u7247%u4E0A%u9700%u6C42%u7684**%u4F30%u7B97**%u3002%u4F30%u7B97%u65F6%u57FA%u4E8E%u548C%u5BA2%u6237%u8FDB%u884C%u4EA4%u8C08%u671F%u95F4%u6240%u5F97%u5230%u7684%u5BF9%u4E8E%u7EC6%u8282%u7684%u7406%u89E3%u8FDB%u884C%u7684%u3002%0A%0A%0A2.%20%u77ED%u4EA4%u4ED8%u5468%u671F%uFF0C%u6BCF2%u5468%u8FED%u4EE3%u4E00%u6B21%uFF0C%u5E76%u4EA4%u4ED8%u5BA2%u6237%u4F7F%u7528%uFF0C%u6BCF12%u5468%u4E00%u6B21%u53D1%u5E03%0A3.%20%u6BCF%u6B21%u4EA4%u4ED8%u90FD%u6709%u5BA2%u6237%u9488%u5BF9feature%u7684%u9A8C%u6536%u6D4B%u8BD5%0A4.%20%u7ED3%u5BF9%u7F16%u7A0B%0A5.%20%u96C6%u4F53%u6240%u6709%u6743%uFF0C%u6307%u4E0D%u56FA%u5B9Aexpert%uFF0C%u51ED%u5174%u8DA3%u51B3%u5B9A%u60F3%u505A%u7684%u65B9%u5411%u3002%0A6.%20%u6301%u7EED%u96C6%u6210%uFF0C%u7C7B%u540C%u7B2C2%u70B9%0A7.%20%u53EF%u6301%u7EED%u7684%u5F00%u53D1%u901F%u5EA6%u3002%u4E0D%u5141%u8BB8%u52A0%u73ED%uFF0C%u7248%u672C%u53D1%u5E03%u524D%u4E00%u4E2A%u793C%u62DC%u4F8B%u5916%0A%3E%u8F6F%u4EF6%u9879%u76EE%u4E0D%u662F%u5168%u901F%u7684%u77ED%u8DD1%uFF0C%u5B83%u662F%u9A6C%u62C9%u677E%u957F%u8DD1%u3002%0A8.%20%u5F00%u653E%u7684%u5DE5%u4F5C%u7A7A%u95F4%0A9.%20%u8BA1%u5212%u6E38%u620F%0A10.%20%u7B80%u5355%u7684%u8BBE%u8BA1%0A%3EXP%u56E2%u961F%u603B%u662F%u5C3D%u53EF%u80FD%u5BFB%u627E%u80FD%u5B9E%u73B0%u5F53%u524Dfeature%u7684%u6700%u7B80%u5355%u7684%u8BBE%u8BA1%0A11.%20%u91CD%u6784%u662F%u6301%u7EED%u8FDB%u884C%u7684%uFF0C%u6BCF%u9694%u4E00%u4E2A%u5C0F%u65F6%u6216%u534A%u4E2A%u5C0F%u65F6%u5C31%u8981%u53BB%u505A%u7684%u4E8B%u60C5%u3002%0A12.%20%u9690%u55BB%20%uFF08%u6CA1%u770B%u61C2%uFF09%0A%0A%u603B%u7ED3%uFF0C%u8FD9%u91CC%u6781%u9650%u7F16%u7A0B%u5176%u5B9E%u5F3A%u8C03%u7684%u66F4%u591A%u7684%u662F%u8F6F%u4EF6%u5F00%u53D1%u56E2%u961F%u7684%u8FD0%u4F5C%u65B9%u5F0F%uFF0C%u9700%u8981%u5404%u65B9%u9762%u8FBE%u6210%u4E00%u81F4%uFF0C%u624D%u80FD%u4E25%u683C%u6309%u7167%u4ED6%u7684%u6BCF%u4E00%u6761%u53BB%u505A%u3002%u4F46%u662F%uFF0C%u5373%u4FBF%u5728%u6211%u4EEC%u73B0%u5728%u7684%u73AF%u5883%u4E0B%uFF0C%u4E0D%u7BA1%u662F%u6781%u9650%u7F16%u7A0B%u8FD8%u662F%u654F%u6377%u65B9%u6CD5%u90FD%u4E0D%u4E3A%u4EBA%u6240%u77E5%uFF0C%u6CA1%u529E%u6CD5%u5B8C%u5168%u5F00%u5C55%u3002%u4F46%u662F%u91CC%u9762%u7684%u4E00%u4E9B%u89C2%u70B9%u5F88%u6709%u542F%u53D1%u610F%u4E49%uFF0C%u4ECD%u7136%u53EF%u4EE5%u5E94%u7528%u5230%u6211%u4EEC%u65E5%u5E38%u7684%u9879%u76EE%u5F53%u4E2D%u3002%u6BD4%u5982%u7B2C%u4E00%u70B9%uFF0C%u8981%u6C42%u5F00%u53D1%u4EBA%u5458%u5B9E%u65F6%u540C%u5BA2%u6237%u4EA4%u6D41%uFF0C%u5E76%u9009%u5B9Afeature%u6216%u53CA%u65F6%u4FEE%u6539%u5F00%u53D1%u65B9%u6848%u3002%u7B2C%u4E8C%u70B9%uFF0C%u4E0D%u65AD%u7684%u4EA4%u4ED8%u3002%u5176%u5B9E%u90FD%u53EF%u4EE5%u9A6C%u4E0A%u8FD0%u7528%u4E0A%u3002%0A%0A%23%23%u7B2C7-12%u7AE0%0A%u867D%u7136%u4E66%u6CA1%u770B%u5B8C%uFF0C%u4F46%u662F%u611F%u89C9%u8FD9%u4E00%u90E8%u5206%u662F%u5168%u4E66%u7684%u6838%u5FC3%uFF0C%u5373%u654F%u6377%u5F00%u53D1%u7684%u539F%u5219%u3002%0A%3E%u4EC0%u4E48%u662F%u654F%u6377%u8BBE%u8BA1%uFF1F%0A%3E%u654F%u6377%u8BBE%u8BA1%u662F%u4E00%u4E2A%u8FC7%u7A0B%uFF0C%u4E00%u4E2A%u6301%u7EED%u7684%u5E94%u7528%u539F%u5219%u3001%u6A21%u5F0F%u4EE5%u53CA%u5B9E%u8DF5%u6765%u6539%u8FDB%u8F6F%u4EF6%u7684%u7ED3%u6784%u548C%u53EF%u8BFB%u6027%u7684%u8FC7%u7A0B%u3002%0A%0A%u6362%u800C%u8A00%u4E4B%uFF0C%u5C31%u662F%u4E0D%u8981%u968F%u968F%u4FBF%u4FBF%u6253%u8865%u4E01%uFF0C%u8BA9%u7A0B%u5E8F%u80FD%u8FD0%u884C%u6EE1%u8DB3%u9700%u6C42%u4FEE%u6539%uFF0C%u800C%u662F%u5E94%u7528%u5404%u79CD%u65B9%u6CD5%u4F7F%u7A0B%u5E8F%u66F4%u5177%u5F39%u6027%u3002%u53E6%u4E00%u65B9%u9762%uFF0C%u53C8%u4E0D%u4E3A%u4E86%u4FEE%u6539%u800C%u4FEE%u6539%uFF0C%u4E0D%u4E3A%u4E86%u5B50%u865A%u4E4C%u6709%u7684%u5F39%u6027%uFF0C%u82B1%u8D39%u989D%u5916%u7684%u7CBE%u529B%u6765%u8FBE%u5230%u60F3%u8C61%u4E2D%u7684%u5F39%u6027%u8BBE%u8BA1%u3002%0A%0A8-12%u7AE0%u4E3A%u6211%u4EEC%u4ECB%u7ECD%u4E86%u9762%u5411%u5BF9%u8C61%u8BBE%u8BA1%u76845%u539F%u5219%uFF1A%0A-%20SRP%3A%20%u5355%u4E00%u804C%u8D23%u539F%u5219%0A-%20OCP%3A%20%u5F00%u653E%u5C01%u95ED%u539F%u5219%0A-%20LSP%3A%20Linskov%u66FF%u6362%u539F%u5219%0A-%20DIP%3A%20%u4F9D%u8D56%u5012%u7F6E%u539F%u5219%0A-%20ISP%3A%20%u63A5%u53E3%u9694%u79BB%u539F%u5219%0A%0A%u9010%u4E00%u6458%u5F55%u5982%u4E0B%uFF1A%0A%0A%23%23%23%20SRP%0A%3E%u5728SRP%u4E2D%uFF0C%u6211%u4EEC%u628A%u804C%u8D23%u5B9A%u4E49%u4E3A%u201C%u53D8%u5316%u7684%u539F%u56E0%u201D%u3002%u5982%u679C%u4F60%u80FD%u60F3%u5230%u591A%u4E8E%u4E00%u4E2A%u7684%u52A8%u673A%u53BB%u6539%u53D8%u4E00%u4E2A%u7C7B%uFF0C%u90A3%u4E48%u8FD9%u4E2A%u7C7B%u5C31%u5177%u6709%u591A%u4E8E%u4E00%u4E2A%u7684%u804C%u8D23%u3002%0A%3E%u5982%u679C%u5E94%u7528%u7A0B%u5E8F%u7684%u53D8%u5316%u65B9%u5F0F%u603B%u662F%u5BFC%u81F4%u8FD9%u4E24%u4E2A%u804C%u8D23%u540C%u65F6%u53D8%u5316%uFF0C%u90A3%u4E48%u5C31%u4E0D%u5FC5%u5206%u79BB%u4ED6%u4EEC%u3002%0A%0A%u7B2C%u4E00%u6B21%u7684%u8BBE%u8BA1%uFF0C%u6211%u4EEC%u5E38%u89C1%u7684%0ANA%0A%u5206%u79BB%u8FC7%u804C%u8D23%u4EE5%u540E%0ANA%0A%u8FD9%u6837%u7684%u8BBE%u8BA1%uFF0C%u5982%u679C%u4E24%u4E2A%u63A5%u53E3%u53D8%u5316%u9891%u7387%u975E%u5E38%u4E0D%u4E00%u81F4%u65F6%uFF0C%u53EF%u4EE5%u51CF%u5C11%u91CD%u65B0%u90E8%u7F72%u7684%u8303%u56F4%u3002%0A%0A%23%23%23OCP%0A1.%20%u5BF9%u4E8E%u6269%u5C55%u5F00%u653E%0A2.%20%u5BF9%u4E8E%u4FEE%u6539%u5173%u95ED%0A%0A%u600E%u4E48%u80FD%u505A%u5230%u5462%uFF1F%u770B%u4E0B%u9762%u7684%u56FE%uFF1A%0A%21%5BAlt%20text%7C400x0%5D%28./1471165809639.png%29%0AClient%u4E0EClient%20Interface%u4E4B%u95F4%u662F%u5173%u8054%u7684%u5173%u7CFB%uFF0C%u8FD9%u91CC%u5E94%u8BE5%u662F%u4F9D%u8D56%u5173%u7CFB%uFF0C%u5373Client%u4F1A%u8C03%u7528Client%20Interface%uFF0CServer%u7EE7%u627F%u81EAClient%20Interface%u3002%u5177%u4F53UML%u56FE%u4F8B%u53EF%u4EE5%u53C2%u8003%u7B14%u8BB0%5BUML%u56FE%20%20%u7B26%u53F7%u7684%u542B%u4E49%5D%28https%3A//www.evernote.com/shard/s24/nl/2724128/3f2a96ed-4b1f-444c-83ce-1a403fdd26eb%29%u3002%0A%0A%3E%u62BD%u8C61%u7C7B%u548C%u5B83%u4EEC%u7684%u5BA2%u6237%u7684%u5173%u7CFB%u8981%u6BD4%u548C%u5B9E%u73B0%u5B83%u4EEC%u7684%u7C7B%u7684%u5173%u7CFB%u66F4%u5BC6%u5207%u3002%0A%3E%u610F%u601D%u662F%uFF0CClient%u4E0EClient%20Interface%u7684%u5173%u7CFB%u8981%u6BD4%u5176%u4E0EServer%u7684%u5173%u7CFB%u66F4%u5BC6%u5207%u3002%0A%0A%u8BF4%u5230%u8FD9%u91CC%uFF0C%u8FD9%u4E2A%u539F%u5219%u5176%u5B9E%u5DF2%u7ECF%u5F88%u6E05%u6670%u4E86%uFF0C%u4F46%u4F5C%u8005%u5E0C%u671B%u544A%u8BC9%u6211%u4EEC%u66F4%u591A%u3002%u5728%u300A%u662F%u7684%uFF0C%u6211%u8BF4%u8C0E%u4E86%u300B%u90A3%u4E00%u8282%u91CC%uFF0C%u4F5C%u8005%u544A%u8BC9%u6211%u4EEC%uFF0C%u4E8B%u5B9E%u5E76%u4E0D%u603B%u50CF%u60F3%u8C61%u4E2D%u90A3%u4E48%u7F8E%u597D%u3002%u5F80%u5F80%u4F1A%u6709%u5404%u79CD%u7A00%u5947%u53E4%u602A%u7684%u9700%u6C42%uFF0C%u5BFC%u81F4%u539F%u5148%u7684%u8BBE%u8BA1%u4E0D%u80FD%u5BF9%u8BE5%u9700%u6C42%u5BFC%u81F4%u7684%u53D8%u5316%u5C01%u95ED%u3002%u4F5C%u8005%u7ED9%u4E86%u6211%u4EEC%u5FE0%u544A%uFF1A%0A%3E%u8BBE%u8BA1%u4EBA%u5458%u5FC5%u987B%u5BF9%u4E8E%u4ED6%u8BBE%u8BA1%u7684%u6A21%u5757%u5E94%u8BE5%u5BF9%u54EA%u79CD%u53D8%u5316%u5C01%u95ED%u505A%u51FA%u9009%u62E9%u3002%u4ED6%u5FC5%u987B%u5148%u731C%u6D4B%u51FA%u6700%u4F18%u53EF%u80FD%u53D1%u751F%u53D8%u5316%u7684%u79CD%u7C7B%uFF0C%u7136%u540E%u6784%u9020%u62BD%u8C61%u6765%u9694%u79BB%u90A3%u4E9B%u53D8%u5316%u3002%0A%3E%u8FD9%u662F%u5F88%u4E0D%u5BB9%u6613%u505A%u5230%u7684%uFF0C%u8981%u6839%u636E%u7ECF%u9A8C%u731C%u6D4B%u54EA%u4E9B%u5E94%u7528%u7A0B%u5E8F%u5728%u751F%u957F%u5386%u7A0B%u4E2D%u6709%u53EF%u80FD%u7684%u53D8%u5316%u3002%0A%0A%u5982%u4F55%u9694%u79BB%u53D8%u5316%uFF1A%0A1.%20%u5728%u53D1%u73B0%u7B2C%u4E00%u6B21%u53D8%u5316%u65F6%uFF0C%u8FDB%u884C%u62BD%u8C61%u6539%u9020%u3002%0A2.%20%u901A%u8FC7%u6D4B%u8BD5+%u5FEB%u901F%u8FED%u4EE3%u6765%u523A%u6FC0%u53D8%u5316%uFF0C%u5C3D%u5FEB%u5C06%u53D8%u5316%u7684%u53EF%u80FD%u66B4%u9732%u51FA%u6765%u3002%0A%0A%u672C%u7AE0%u8FD8%u4ECB%u7ECD%u4E86%u4E00%u79CD%u5F88%u5B9E%u7528%u7684%u5C01%u95ED%u53D8%u5316%u7684%u65B9%u6CD5%uFF0C%u4F7F%u7528%u201C%u6570%u636E%u9A71%u52A8%u201D%u65B9%u6CD5%u3002%u5176%u5B9E%u5C31%u662F%u8868%u683C%u9A71%u52A8%u3002%u5C06%u53D8%u5316%u7684%u90E8%u5206%u603B%u7ED3%u56FA%u5316%u5230%u8868%u683C%u4E2D%u3002%0A%0A%3E%u5F00%u53D1%u4EBA%u5458%u5E94%u8BE5%u4EC5%u4EC5%u5BF9%u7A0B%u5E8F%u4E2D%u5448%u73B0%u51FA%u9891%u7E41%u53D8%u5316%u7684%u90A3%u4E9B%u90E8%u5206%u505A%u51FA%u62BD%u8C61%u3002%u62D2%u7EDD%u4E0D%u6210%u719F%u7684%u62BD%u8C61%u548C%u62BD%u8C61%u672C%u8EAB%u4E00%u6837%u91CD%u8981%0A%0A%23%23%23LSP%0A%3E%20LSP%20-%20%u5B50%u7C7B%u578B%uFF08%u7684%u65B9%u6CD5%uFF09%u5FC5%u987B%u80FD%u591F%u66FF%u6362%u6389%u5B83%u4EEC%u7684%u57FA%u7C7B%u578B%uFF08%u7684%u65B9%u6CD5%uFF09%u3002%0A%0ALinskov%u9996%u6B21%u63D0%u51FA%u8FD9%u4E2A%u539F%u5219%u3002%0A%u672C%u7AE0%u4E3E%u7684%u4F8B%u5B50%u662F%u6B63%u65B9%u5F62vs.%u77E9%u5F62%u3002%u4EE5%u5E38%u7406%u63A8%u8BBA%u6B63%u65B9%u5F62IS-A%u77E9%u5F62%uFF0C%u6240%u4EE5%u6B63%u65B9%u5F62%u7684%u7C7B%u5E94%u5F53%u53EF%u4EE5%u7EE7%u627F%u81EA%u77E9%u5F62%u7684%u7C7B%u3002%u4F46%u4EE5%u66FF%u6362%u539F%u5219%u770B%uFF0C%u5728%u67D0%u4E9B%u60C5%u51B5%u4E0B%u6B63%u65B9%u5F62%u548C%u77E9%u5F62%u7684%u884C%u4E3A%u5E76%u4E0D%u4E00%u81F4%u3002%0A%60%60%60%0Avoid%20g%20%28Rectangle%26%20r%29%0A%7B%0A%09r.SetWidth%285%29%3B%0A%09r.SetHeight%284%29%3B%0A%09assert%28r.Area%28%29%20%3D%3D%2020%29%3B%0A%7D%0A%60%60%60%0A%u5982%u679Cr%u4F20%u5165%u7684%u662F%u6B63%u65B9%u5F62%u5BF9%u8C61%uFF0C%u5219%u5FC5%u7136%u4F1A%u51FA%u65AD%u8A00%uFF0C%u6240%u4EE5%u8FD9%u6BB5%u4EE3%u7801%u4E0D%u7B26%u5408LSP%u3002%0A%3EOOD%u4E2D**IS-A**%u5173%u7CFB%u662F%u5C31%u884C%u4E3A%u65B9%u5F0F%u800C%u8A00%u3002%0A%0A%u53EF%u89C1%uFF0C%u867D%u7136%u4EE3%u7801%u662F%u73B0%u5B9E%u751F%u6D3B%u7684%u62BD%u8C61%uFF0C%u4F46%u4E5F%u4E0D%u5B8C%u5168%u662F%u3002%u5982%u4F55%u89C4%u907F%uFF0C%u6216%u8005%u8BF4%u53D1%u73B0%u8FD9%u79CD%u5FAE%u5999%u7684%u4E0D%u540C%u3002%u4F5C%u8005%u7ED9%u51FA%u4E00%u4E2A%u65B9%u6CD5%u5C31%u662F%u57FA%u4E8E%u5951%u7EA6%u7684%u8BBE%u8BA1%u3002%u901A%u8FC7%u8BBE%u7F6E%u524D%u540E%u7F6E%u6761%u4EF6%uFF0C%u6765%u786E%u5B9A%u662F%u5426IS-A%u5173%u7CFB%u3002%0A%3E%u6D3E%u751F%u7C7B%u4E2D%u7684%u4F8B%u7A0B%0A%3E-%20%u53EA%u80FD%u4F7F%u7528%u76F8%u7B49%u6216%u66F4%u5F31%u7684%u524D%u7F6E%u6761%u4EF6%u6765%u66FF%u6362%u539F%u59CB%u7684%u524D%u7F6E%u6761%u4EF6%uFF0C%0A%3E-%20%u53EA%u80FD%u4F7F%u7528%u76F8%u7B49%u6216%u66F4%u5F3A%u7684%u540E%u7F6E%u6761%u4EF6%u6765%u66FF%u6362%u539F%u59CB%u7684%u540E%u7F6E%u6761%u4EF6%u3002%0A%3E-%20%u53EF%u4EE5%u5728%u5355%u5143%u6D4B%u8BD5%u4E2D%u6307%u5B9A%u524D%u540E%u7F6E%u6761%u4EF6%uFF0C%u6765%u770B%u662F%u5426%u6EE1%u8DB3IS-A%u7684%u5173%u7CFB%uFF0C%u5982%u679C%u4E0D%u6EE1%u8DB3%u5C31%u8981%u91CD%u65B0%u8BBE%u8BA1%u3002%0A%0A*%20%u6240%u8C13%u6761%u4EF6%u5F3A%uFF0C%u5373%u7EA6%u675F%u591A%uFF0C%u6761%u4EF6%u5F31%uFF0C%u5373%u7EA6%u675F%u5C11%u3002%0A%0A%u5982%u4F55%u8BA9%u4EE3%u7801%u505A%u5230LSP%uFF0C%u65B9%u6CD5%u5C31%u662F%u6452%u5F03%u66FE%u7ECF%u7684%u62BD%u8C61%u65B9%u6CD5%uFF0C%u901A%u8FC7%u5728%u5B9E%u8DF5%u4E2D%uFF0C%u603B%u7ED3%u4E24%u4E2A%u7C7B%u884C%u4E3A%u4E00%u81F4%u7684%u90E8%u5206%uFF0C%u5E76%u63D0%u53D6%u51FA%u516C%u6709%u7684%u62BD%u8C61%u7236%u7C7B%u3002%u4E0B%u56FE%u662F%u4F8B%u5B50%0A%21%5BAlt%20text%7C400x0%5D%28./1471391264213.png%29%0A%u8FD9%u5E45%u56FEPersistentSet%u76F4%u63A5%u4ECESet%u7EE7%u627F%uFF0C%u5E76%u76F4%u63A5%u59D4%u6258%28delegate%29%u51FA%u53BB%uFF0C%u5176%u59D4%u6258%u7684%u4EE3%u7801%u53EA%u63A5%u53D7%u4E00%u79CD%u53C2%u6570PersistentObject%u3002%u90A3%u8FD9%u4E2A%u65B9%u6CD5%u5C31%u4E0D%u80FD%u66FF%u4EE3Set%u7684%u65B9%u6CD5%uFF0C%u4F1A%u6709%u4E0D%u53EF%u9884%u77E5%u7684%u4E8B%u60C5%u53D1%u751F%u3002%0A%0A%21%5BAlt%20text%7C500x0%5D%28./1471391282049.png%29%0A%u8FD9%u5F20%u56FE%u5C06PersistentSet%u653E%u5230%u4E0ESet%u540C%u7B49%u7684%u4F4D%u7F6E%uFF0C%u4ED6%u4EEC%u5171%u540C%u7EE7%u627F%u4E8E%u4E00%u4E2A%u516C%u5171%u62BD%u8C61%u7236%u7C7B%uFF0CSet%u7684%u5B50%u7C7B%u4E0D%u77E5%u9053PersistentSet%u7C7B%u7684%u5B58%u5728%uFF0C%u6240%u4EE5%u5C31%u4E0D%u4F1A%u6709%u4E0A%u56FE%u7684%u95EE%u9898%u53D1%u751F%u3002%0A%0A%u6709%u53EF%u80FD%u5F15%u8D77%u8FDD%u53CDLSP%u7684%u4E24%u79CD%u60C5%u51B5%uFF1A%0A1.%20%u6D3E%u751F%u7C7B%u4E2D%u65B9%u6CD5%u5B9A%u4E49%u4E3A%u7A7A%u51FD%u6570%uFF0C%u8FD9%u79CD%u60C5%u51B5%u867D%u7136%u6CA1%u6709%u8FDD%u53CDLSP%uFF0C%u4F46%u4ECD%u7136%u4F1A%u5F15%u8D77%u5F15%u7528%u7236%u7C7B%u6307%u9488%u65F6%u7684%u5FAE%u5999%u533A%u522B%u3002%0A2.%20%u4ECE%u6D3E%u751F%u7C7B%u629B%u51FA%u5F02%u5E38%uFF0C%u660E%u663E%u8FDD%u72AFLSP%uFF0C%u5982%u679C%u8981%u9075%u5FAALSP%uFF0C%u8981%u4E48%u9700%u8981%u4FEE%u6539%u7236%u7C7B%u53CA%u4F7F%u7528%u9884%u671F%uFF0C%u8981%u4E48%u4E0D%u629B%u5F02%u5E38%u3002%0A%0A%3E%u603B%u7ED3%uFF1A%u5B50%u7C7B%u578B%u7684%u6B63%u786E%u5B9A%u4E49%u662F%u201C%u53EF%u66FF%u6362%u6027%u7684%u201D%uFF0C%u8FD9%u91CC%u7684%u53EF%u66FF%u6362%u6027%u53EF%u4EE5%u901A%u8FC7%u663E%u5F0F%u6216%u8005%u9690%u5F0F%u7684%u5951%u7EA6%u6765%u5B9A%u4E49%u3002%0A%0A%23%23%23DIP%0A%u8FD9%u4E00%u6761%u5F88%u6709%u542F%u793A%u610F%u4E49%u3002%u4EE5%u524D%u4ECE%u6765%u6CA1%u8FD9%u4E48%u60F3%u8FC7%uFF0C%u4F46%u7ECF%u4F5C%u8005%u4E00%u8BF4%uFF0C%u5176%u5B9E%u89E3%u7B54%u4E4B%u524D%u5F88%u591A%u7684%u7591%u60D1%u3002%0A%0A%3E%u65E0%u8BBA%u5982%u4F55%u9AD8%u5C42%u6A21%u5757%u90FD%u4E0D%u5E94%u8BE5%u4F9D%u8D56%u4E8E%u4F4E%u5C42%u6A21%u5757%u3002%u6211%u4EEC%u66F4%u5E0C%u671B%u80FD%u591F%u91CD%u7528%u7684%u662F%u9AD8%u5C42%u7684%u7B56%u7565%u8BBE%u7F6E%u6A21%u5757%u3002%0A%3E%u4F55%u4E3A%u9AD8%u5C42%u7B56%u7565%uFF1F%0A%3E%u5B83%u662F%u5E94%u7528%u80CC%u540E%u7684%u62BD%u8C61%uFF0C%u662F%u90A3%u4E9B%u4E0D%u968F%u5177%u4F53%u7EC6%u8282%u7684%u6539%u53D8%u800C%u6539%u53D8%u7684%u771F%u7406%0A%21%5BAlt%20text%7C350x0%5D%28./1471477427952.png%29%0ALamp%u662F%u706F%uFF0C%u662F%u5E94%u7528%uFF0C%u662F%u9AD8%u5C42%u6A21%u5757%u3002%u5B83%u4F9D%u8D56%u4E8E%u62BD%u8C61%u6A21%u5757interface%20ButtonServer%uFF0C%u8FD9%u4E2A%u5C31%u662F%u7B56%u7565%uFF0C%u6709%u7684%u5730%u65B9%u79F0%u4E4B%u4E3A%u9690%u55BB%28metaphore%29%0A%0ALamp%u5E76%u4E0D%u4F9D%u8D56%u4E8EButton%uFF0C%u800C%u662FButton%u4F9D%u8D56%u4E8ELamp%u63D0%u4F9B%u51FA%u7684%u63A5%u53E3ButtonServer%u3002%u800C%u8FD9%u4E2Ainterface%u4E5F%u4E0D%u5C40%u9650%u4E8EButton%uFF0C%u5176%u5B9E%u53EA%u8981%u6709%u5F00%u5173%u7B56%u7565%u7684%u5177%u4F53%u7C7B%u90FD%u53EF%u4EE5%u5B9E%u73B0%u8FD9%u4E2A%u63A5%u53E3%u3002%u4F46%u662F%u6240%u6709%u8FD9%u4E9B%u4F4E%u5C42%u7C7B%u7EDF%u7EDF%u4F9D%u8D56%u4E8E%u8FD9%u4E2A%u9AD8%u5C42%u63D0%u4F9B%u7684%u63A5%u53E3%u3002%u800C%u4F4E%u5C42%u6A21%u5757%uFF0C%u5982Button%u7684%u4FEE%u6539%u5E76%u4E0D%u4F1A%u5F71%u54CD%u5230Lamp%u3002%0A%u6709%u4E00%u5929Lamp%u9700%u8981%u4FEE%u6539%u8FD9%u4E2A%u63A5%u53E3%u7684%u65F6%u5019%uFF0C%u6240%u6709%u7684%u7C7B%u90FD%u4F1A%u53D7%u5230%u5F71%u54CD%u3002%u8FD9%u5C31%u662F%u9AD8%u5C42%u5F71%u54CD%u4F4E%u5C42%u3002%u4F46%u662FLamp%u662F%u9AD8%u5C42%u7B56%u7565%uFF0C%u662F%u9690%u55BB%uFF0C%u5E76%u4E0D%u4F1A%u7ECF%u5E38%u6539%u53D8%u3002%0A%0A%u518D%u770B%u8FD9%u4E2A%u4F8B%u5B50%u3002%0A%u539F%u59CB%u7684%u7B97%u6CD5%u5982%u4E0B%0A%21%5BAlt%20text%7C500x0%5D%28./1471477939567.png%29%0A%u8FD9%u91CC%u5939%u6742%u4E86%u5F88%u591A%u4F4E%u5C42%u7684%u7EC6%u8282%uFF0C%u5BFC%u81F4%u9AD8%u5C42%u4F9D%u8D56%u4E8E%u5E95%u5C42%u6A21%u5757%u3002%u8FD9%u6BB5%u4EE3%u7801%u6839%u672C%u4E0D%u80FD%u91CD%u7528%u4E8E%u4E0D%u540C%u7684%u63A7%u5236%u786C%u4EF6%u3002%0A%21%5BAlt%20text%7C400x0%5D%28./1471477820628.png%29%0A%u8FD9%u4E2A%u56FE%u662F%u7528OO%u7684%u65B9%u6CD5%uFF0C%u62BD%u8C61%u51FAThermometer%u548CHeater%u63A5%u53E3%u3002%u8FD9%u6837%u53EA%u8981%u4F4E%u5C42%u6A21%u5757%u80FD%u6EE1%u8DB3%u4E00%u4E2A%u8BFB%u4E00%u4E2A%u53D1%u547D%u4EE4%u5C31%u53EF%u4EE5%u4E86%u3002%u5177%u6709%u5F88%u5927%u7684%u7075%u6D3B%u6027%uFF0C%u4F4E%u5C42%u4F9D%u8D56%u4E8E%u9AD8%u5C42%uFF0C%u4F4E%u5C42%u7684%u6539%u53D8%u4E5F%u4E0D%u4F1A%u5F71%u54CD%u5230%u9AD8%u5C42%u7684%u5B9E%u73B0%u3002%0A%0A%23%23%23ISP%0A%u8FD9%u4E2A%u89C4%u5219%u8981%u89E3%u51B3%u7684%u95EE%u9898%u53EB%u63A5%u53E3%u6C61%u67D3%u3002%0A%u4F55%u4E3A%u63A5%u53E3%u6C61%u67D3%uFF1F%u770B%u4E0B%u9762%u8FD9%u4E2A%u4F8B%u5B50%0A%21%5BAlt%20text%7C400x0%5D%28./1471530170661.png%29%0A%u6709%u4E9B%u95E8%u9700%u8981%u5B9A%u65F6%u529F%u80FD%uFF0C%u5B89%u88C5DIP%uFF0CDoor%u53EF%u4EE5%u5B9E%u73B0TimerClient%u7684%u63A5%u53E3%uFF0C%u4F46%u662F%u5176%u4ED6%u7684%u95E8%u53EF%u80FD%u4E0D%u9700%u8981%u5B9A%u65F6%u7684%u529F%u80FD%uFF0C%u4F46%u662F%u56E0%u4E3A%u8FD9%u6B21%u7EE7%u627F%uFF0C%u5BFC%u81F4%u5176%u4ED6Door%u7684%u6D3E%u751F%u7C7B%u4E5F%u6709%u4E86%u8FD9%u4E9B%u5BF9%u5B83%u4EEC%u6BEB%u65E0%u610F%u4E49%u7684%u63A5%u53E3%uFF0C%u8FD9%u5C31%u662F%u63A5%u53E3%u6C61%u67D3%uFF0C%u6709%u65F6%u5019%u88AB%u53EB%u4F5C%u63A5%u53E3%u53D8%u201C%u80D6%u201D%u3002%0A%0A%3E%u63A5%u53E3%u9694%u79BB%u539F%u5219%uFF1A%u4E0D%u5E94%u8BE5%u5F3A%u8FEB%u5BA2%u6237%u4F9D%u8D56%u4E8E%u5B83%u4EEC%u4E0D%u7528%u7684%u65B9%u6CD5%u3002%0A%0A%u5B9E%u73B0ISP%u7684%u4E24%u4E2A%u9014%u5F84%0A%23%23%23%23%20%u59D4%u6258%0A%u8FD9%u4E2A%u4E0D%u592A%u597D%u7406%u89E3%uFF0C%u800C%u4E14%u8FD9%u4E2A%u65B9%u6CD5%u6309%u4F5C%u8005%u7684%u8BF4%u6CD5%u4E5F%u4E0D%u662F%u5F88%u597D%u3002%0A%21%5BAlt%20text%7C500x0%5D%28./1471530881483.png%29%0A-%20%u5F53Timed%20Door%u9700%u8981%u4E00%u4E2A%u5B9A%u65F6%u4F8B%u7A0B%u7684%u65F6%u5019%uFF0C%u5B83%u5148%u521B%u5EFA%u4E00%u4E2ADoor%20Timer%20Adapter%u5BF9%u8C61%uFF0C%u5E76%u4EE5Timer%20Client%u7684%u5F62%u5F0F%u6CE8%u518C%u7ED9Timer%0A-%20%u5F53Timer%u8BA1%u65F6%u5230%u8FBE%u65F6%uFF0CDoor%20Timer%20Adapter%u7684Timeout%u4F1A%u88AB%u8C03%u7528%0A-%20%u8FDB%u800C%u56E0%u4E3A%u59D4%u6258%uFF0C%u4F1A%u8C03%u7528Timed%20Door%u7684DoorTimeOut%0A%0A%u8FD9%u6837%u505A%uFF0C%u5C31%u4E0D%u9700%u8981Door%u6765%u5B9E%u73B0Timer%u63A5%u53E3%uFF0C%u9632%u6B62%u4E86%u63A5%u53E3%u6C61%u67D3%u3002%u7F3A%u70B9%u662F%uFF0C%u6BCF%u6B21%u9700%u8981%u5B9A%u65F6%u7A0B%u5E8F%u7684%u65F6%u5019%uFF0C%u90FD%u8981%u521B%u5EFA%u4E00%u4E2ADoor%20Timer%20Adapter%u5BF9%u8C61%uFF0C%u6D6A%u8D39%u8D44%u6E90%u3002%0A%0A%23%23%23%23%u591A%u91CD%u7EE7%u627F%0A%u770B%u4E0A%u9762%u7684%u59D4%u6258%u7684%u4F8B%u5B50%uFF0C%u5176%u5B9E%u5C31%u5F88%u5BB9%u6613%u60F3%u5230%u591A%u91CD%u7EE7%u627F%u4E86%u3002%u53EA%u8981%u5BF9TimedDoor%u91C7%u7528%u591A%u91CD%u7EE7%u627F%u5C31%u597D%u4E86%uFF0C%u65E2%u4E0D%u5F71%u54CDDoor%u7684%u5176%u4ED6%u5B50%u7C7B%uFF0C%u53C8%u80FD%u4F7FTimedDoor%u5177%u6709Timer%u548CDoor%u7684%u53CC%u91CD%u529F%u80FD%u3002%0A%u91C7%u7528%u591A%u91CD%u7EE7%u627F%u540E%uFF0C%u4E0A%u9762%u4F8B%u5B50%u7684%u89E3%u51B3%u65B9%u6848%u53D8%u6210%uFF1A%0A%21%5BAlt%20text%7C500x0%5D%28./1471531269827.png%29%0A%0A%u53E6%u5916%u4E00%u4E2A%u4F8B%u5B50%0A%21%5BAlt%20text%5D%28./1471562775035.png%29%0A%0A%u8FD9%u91CC%u6709%u4E24%u70B9%u8981%u6CE8%u610F%uFF1A%0A%21%5BAlt%20text%5D%28./1471562817773.png%29%0A%u867D%u7136%u8BED%u6CD5%u4E0A%u56E0%u4E3A%u591A%u91CD%u7EE7%u627F%uFF0C%u5141%u8BB8%u8FD9%u6837%u5199%u3002%u4F46%u662F%u8FD9%u6837%u4E5F%u662F%u4E00%u79CD%u63A5%u53E3%u6C61%u67D3%uFF0CDepositTransaction%u6839%u672C%u4E0D%u9700%u8981UI%u4E2D%u5176%u4ED6transaction%u7684UI%u3002%0A%0A%u5E94%u8BE5%u8FD9%u6837%u5199%uFF1A%0A%21%5BAlt%20text%5D%28./1471562897916.png%29%0A%0A%u4E5F%u4E0D%u8981%u8FD9%u6837%u5199%uFF1A%0A%21%5BAlt%20text%5D%28./1471562957325.png%29%0A%u628A%u6240%u6709%u5168%u5C40%u53D8%u91CF%u5305%u5230%u4E00%u4E2A%u7C7B%u91CC%u9762%uFF0C%u7B49%u4E8E%u524D%u9762%u7684%u4E8B%u60C5%u767D%u505A%u4E86%u3002%u8FD9%u91CC%u56E0%u4E3A%u6240%u6709%u7684%u7C7B%u90FD%u653E%u5230%u4E00%u8D77%uFF0C%u5C31%u6709%u673A%u4F1A%u4EA7%u751F%u4E92%u76F8%u4F9D%u8D56%u3002%u5982%u679C%u8981%u6DFB%u52A0%u4E00%u4E2A%u65B0%u7C7B%uFF0C%u90A3%u5C31%u4F1A%u6709%u53EF%u80FD%u8981%u4FEE%u6539%u6240%u6709%u7C7B%u3002%u8FD9%u6837%u5C31%u9694%u79BB%u5931%u8D25%u4E86%u3002%0A%0A%u5F15%u7533%u4E0B%u6765%0A%60%60%60%0Avoid%20g%28DepositUI%26%2C%20TransferUI%26%29%3B%0Avoid%20g%28UI%26%29%3B%0A%60%60%60%0A%u54EA%u79CD%u5199%u6CD5%u597D%uFF1F%u5176%u5B9E%u4E00%u76EE%u4E86%u7136%u3002%u80AF%u5B9A%u662F%u7B2C%u4E00%u79CD%uFF0C%u867D%u7136%u770B%u8D77%u6765%u6709%u70B9%u5570%u55E6%u3002%u4F5C%u8005%u544A%u8BC9%u6211%u4EEC%u4E86%uFF1A%0A%3E%u65E0%u8BBA%u662F%u5426%u6709%u6096%u5E38%u7406%uFF0C%u591A%u53C2%u6570%u5F62%u5F0F%u901A%u5E38%u90FD%u5E94%u8BE5%u4F18%u4E8E%u5355%u53C2%u6570%u5F62%u5F0F%u4F7F%u7528%u3002%0A%0A%23%23%23%23ISP%u7684%u4E24%u70B9%u5EFA%u8BAE%0A1.%20%u5BF9%u5BA2%u6237%u5206%u7EC4%u3002%u5C31%u50CF%u4E0A%u9762ATM%u7684%u4F8B%u5B50%uFF0C%u5BF9Transaction%u5206%u7C7B%u9694%u79BB%u3002%u4E0D%u540C%u7684%u5BA2%u6237%u8981%u6C42%u7684%u670D%u52A1%u53EF%u80FD%u6709%u91CD%u53E0%uFF0C%u5982%u679C%u91CD%u53E0%u5C11%u5C31%u9694%u79BB%uFF0C%u91CD%u53E0%u591A%u5C31%u62BD%u53D6%u516C%u5171%u62BD%u8C61%u7C7B%u3002%0A2.%20%u6539%u53D8%u63A5%u53E3%u5C3D%u91CF%u901A%u8FC7%u65B0%u52A0%u63A5%u53E3%u6765%u505A%uFF0C%u907F%u514D%u4FEE%u6539%u73B0%u6709%u63A5%u53E3%u3002%u56E0%u4E3A%u4F60%u7684%u5B50%u7C7B%u53EF%u80FD%u6B63%u5728%u7528%u8FD9%u4E2A%u63A5%u53E3%u3002%0A%0A%23%23%u7B2C13-19%u7AE0%0A%u672C%u4E66%u7684%u7B2C%u4E09%7E%u516D%u90E8%u5206%uFF0C%u7ED3%u54084%u4E2A%u6BD4%u8F83%u5927%u578B%u7684%u4F8B%u5B50%uFF0C%u8BB2%u89E3%u4E86%u4E00%u7CFB%u5217%u8BBE%u8BA1%u6A21%u5F0F%u3002%u672C%u90E8%u5206%u6D89%u53CA%u7684%u6A21%u5F0F%u6709%uFF1A%0A-%20COMMAND%20%26%20ACTIVE%20OBJECT%0A-%20TEMPLATE%20METHOD%20%26%20STRATEGY%0A-%20FACADE%20%26%20MEDIATOR%0A-%20SINGLETON%20%26%20MONOSTATE%0A-%20NULL%20OBJECT%0A%u5176%u5B9E%u6BCF%u4E2A%u6A21%u5F0F%uFF0C%u5728%u770B%u4E66%u7684%u65F6%u5019%uFF0C%u7ED3%u5408%u4F5C%u8005%u7ED9%u51FA%u7684%u4F8B%u5B50%uFF0C%u5F88%u5BB9%u6613%u7406%u89E3%uFF0C%u4E5F%u77E5%u9053%u4ED6%u5728%u8BF4%u4EC0%u4E48%uFF0C%u4F46%u662F%u5982%u679C%u60F3%u8981%u5E94%u7528%u5230%u5B9E%u9645%u7684%u5F00%u53D1%u4E2D%uFF0C%u8FD8%u662F%u6709%u4E00%u5B9A%u96BE%u5EA6%u7684%u3002%u4F5C%u8005%u5728%u540E%u6587%u4E2D%uFF0C%u4E5F%u7ED9%u51FA%u4E00%u4E2A%u4F8B%u5B50%uFF0C%u6559%u8BFB%u8005%u5982%u4F55%u901A%u8FC7%u62BD%u8C61%u603B%u7ED3%u5BFB%u627E%u9002%u5408%u81EA%u5DF1%u7684%u8BBE%u8BA1%u6A21%u5F0F%u3002%u4F46%u662F%u4E0D%u7BA1%u600E%u4E48%u8BF4%uFF0C%u5BF9%u6BCF%u4E00%u4E2A%u8BBE%u8BA1%u6A21%u5F0F%u7684%u7279%u70B9%u548C%u76EE%u7684%u603B%u8981%u6709%u4E00%u4E2A%u6E05%u9192%u7684%u8BA4%u8BC6%uFF0C%u624D%u80FD%u7075%u6D3B%u7684%u52A0%u4EE5%u5E94%u7528%u3002%0A%0A%23%23%23%3Cspan%20id%3D%22jump%22%3ECOMMAND%20%26%20ACTIVE%20OBJECT%3C/span%3E%0A%u8FD9%u4E24%u4E2A%u6A21%u5F0F%u90FD%u662F%u57FA%u4E8E%u5BF9%u64CD%u4F5C%u7684%u5C01%u88C5%u3002ACTIVE%20OBJECT%u6A21%u5F0F%u57FA%u4E8ECOMMAND%u6A21%u5F0F%u3002%u4E0B%u56FE%u5C31%u662FCOMMAND%u6A21%u5F0F%uFF1A%0A%21%5BAlt%20text%7C240x0%5D%28./1477352892193.png%29%0A%23%23%23%23%u4EC0%u4E48%u65F6%u5019%u7528COMMAND%u6A21%u5F0F%uFF1F%0ACOMMAND%u6A21%u5F0F%u53EF%u4EE5%u5206%u79BB%u64CD%u4F5C%u53D1%u8D77%u8005%u548C%u64CD%u4F5C%u672C%u8EAB%u3002%u6BD4%u5982%u4E0B%u9762%u9700%u8981sensor%u9A71%u52A8%u4E8B%u4EF6%u7684%u6A21%u578B%u3002%0A%21%5BAlt%20text%5D%28./1477353059870.png%29%0A%0A%u82E5%u4E0D%u91C7%u7528COMMAND%u6A21%u5F0F%uFF0Csensor%u9700%u8981%u77E5%u9053%u8C03%u7528%u4EC0%u4E48%u51FD%u6570%u505A%u4EC0%u4E48%u64CD%u4F5C%u3002%u82E5%u91C7%u7528COMMAND%u6A21%u5F0F%u540E%uFF0C%u9AD8%u5C42%u7684%u638C%u63E1%u4E8B%u4EF6%u903B%u8F91%u7684%u6A21%u5757%uFF0C%u5BF9sensor%u548C%u4E8B%u4EF6%u8FDB%u884C%u7ED1%u5B9A%uFF0C%u4E4B%u540Esensor%u5C31%u53EF%u4EE5%u5BF9%u4E8B%u4EF6%u8FDB%u884C%u65E0%u5DEE%u522B%u7684%u8C03%u7528%uFF08command-%3Edo%28%29%uFF09%u3002%u4ECE%u800C%u8FBE%u5230**%u4E8B%u4EF6%u6267%u884C%u8005%u548C%u4E8B%u4EF6%u672C%u8EAB%u7684%u89E3%u8026**%u3002%0A%0A%23%23%23%23ACTIVE%20OBJECT%u5462%uFF1F%0AACTIVE%20OBJECT%u57FA%u4E8ECOMMAND%u6A21%u5F0F%uFF0C%u6709%u5982%u4E0B%u7684%u7B80%u5355%u7ED3%u6784%uFF1A%0A%60%60%60%0Apublic%20class%20ActiveObject%7B%0A%09Command%20itsCommands%5B%5D%3B%0A%09public%20void%20run%28%29%7B%0A%09%09for%20each%20command%7B%0A%09%09%09do%28%29%3B%0A%09%09%7D%0A%09%7D%0A%09public%20void%20addCommand%28Command%20cmd%29%20%7B%0A%09%09itsCommands.append%28cmd%29%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%u8BE5%u6A21%u5F0F%u5206%u79BB%u4E86%u4EFB%u52A1%u7684%u63D0%u4EA4%u4E0E%u4EFB%u52A1%u7684%u8FD0%u884C%u3002%u6309%u4F5C%u8005%u7684%u8BF4%u6CD5%uFF0C%u5E76%u53C2%u8003%u7F51%u4E0A%u5176%u4ED6%u7684%u7B14%u8BB0%uFF0C%u8FD9%u4E2A%u53E4%u8001%u7684%u8BBE%u8BA1%u6A21%u5F0F%u5F80%u5F80%u4F1A%u5E26%u6765%u610F%u60F3%u4E0D%u5230%u7684%u597D%u6548%u679C%u3002%0A1.%20%u5B83%u53EF%u4EE5%u6A21%u62DF%u591A%u7EBF%u7A0B%u7684%u8FD0%u884C%u3002%u5B9E%u9645%u4E0A%u7EBF%u7A0B%u4F8B%u7A0B%u4E5F%u53EF%u4EE5%u662F%u4E00%u4E2Aactive%20object%0A2.%20%u6211%u4EEC%u53EF%u4EE5%u5728Command%u7684do%u63A5%u53E3%u4E2D%u51B3%u5B9A%u4E0B%u4E00%u6B65%u7684%u64CD%u4F5C%uFF0C%u53EF%u4EE5%u8FBE%u5230%u63A7%u5236%u6574%u4E2Aactive%20object%u8FD0%u884C%u8FD8%u662F%u505C%u6B62%u7684%u6548%u679C%u3002%0A%0A%23%23%23TEMPLATE%20METHOD%20%26%20STRATEGY%0A%23%23%23%23TEMPLATE%20METHOD%0A%u5728%u6211%u770B%u6765%uFF0CTEMPLATE%20METHOD%u5E76%u4E0D%u80FD%u79F0%u4E3A%u4E00%u79CD%u8BBE%u8BA1%u6A21%u5F0F%uFF0C%u53EA%u662F%u628A%u4E00%u4E9B%u76F8%u540C%u7684%u6D41%u7A0B%uFF0C%u62BD%u8C61%u6210%u4E00%u4E2A%u62BD%u8C61%u57FA%u7C7B%uFF0C%u7136%u540E%u6240%u6709%u7684%u6D3E%u751F%u7C7B%u91CD%u7528%u8FD9%u4E2A%u6D41%u7A0B%u3002%u4F46%u8FD9%u5F80%u5F80%u6CA6%u4E3A%u9E21%u808B%uFF0C%u56E0%u4E3A%u6D3E%u751F%u7C7B%u603B%u662F%u5728%u67D0%u4E2A%u4E0D%u786E%u5B9A%u7684%u65F6%u95F4%u8868%u73B0%u51FA%u4E0D%u4E00%u6837%u7684%u884C%u4E3A%uFF0C%u7136%u540E%u6574%u4E2A%u62BD%u8C61%u7684%u7ED3%u6784%u5C31%u88AB%u8865%u4E01%u6253%u7684%u9762%u76EE%u5168%u975E%u3002%u4F5C%u8005%u8BF4%uFF0C%u5BF9TEMPLATE%20METHOD%u4E00%u5B9A%u8981%u614E%u4E4B%u53C8%u614E%uFF0C%u5F80%u5F80%u4F1A%u51FA%u73B0%u6A21%u5F0F%u6EE5%u7528%u7684%u60C5%u51B5%u3002%0ATEMPLATE%20METHOD%u6709%u4E00%u4E2A%u5F88%u5178%u578B%u7684%u4F8B%u5B50%uFF0C%u5C31%u662FBubble%20Sort%u3002%u4E0D%u7BA1%u662F%u5BF9%u6570%u5B57%u505A%u5192%u6CE1%uFF0C%u8FD8%u662F%u5BF9%u5B57%u7B26%u505A%u5192%u6CE1%uFF0C%u8FD8%u662F%u5BF9%u81EA%u5B9A%u4E49%u5BF9%u8C61%u505A%u5192%u6CE1%uFF0C%u5176%u6838%u5FC3%u7B97%u6CD5%u603B%u662F%u4E00%u6837%u7684%u3002%u5176%u4E0D%u540C%u5728%u4E8E%0A1.%20%u4E24%u4E2A%u5BF9%u8C61%u7684%u6BD4%u8F83%u64CD%u4F5C%0A2.%20%u4E24%u4E2A%u5BF9%u8C61%u7684%u4EA4%u6362%u64CD%u4F5C%0A%0A%u5982%u6B64%u5C31%u53EF%u4EE5%u5F88%u597D%u7684%u4F7F%u7528TEMPLATE%20METHOD%u4E86%u3002%u628A%u8FD9%u4E24%u4E2A%u64CD%u4F5C%u4F5C%u4E3A%u63A5%u53E3%u62BD%u8C61%u51FA%u6765%uFF0C%u5192%u6CE1%u6392%u5E8F%u7684%u6838%u5FC3%u7B97%u6CD5%u5C31%u662FTEMPLATE%20METHOD%u4E86%u3002%0A%u6211%u89C9%u5F97%u53EA%u6709%u5728%u8FD9%u79CD%u8D85%u7ECF%u5178%u7684%u73AF%u5883%u4E0B%uFF0C%u624D%u53EF%u4EE5%u4F7F%u7528TEMPLATE%20METHOD%u3002%u5426%u5219%u8FD8%u662F%u8003%u8651%u5176%u4ED6%u6A21%u5F0F%u5427%u3002%0A%0A%23%23%23%23STRATEGY%0A%21%5BAlt%20text%7C300x0%5D%28./1477439436051.png%29%0ASTRATEGY%u662FTEMPLATE%20METHOD%u7684%u6539%u8FDB%u7248%u3002%0A%0A%21%5BAlt%20text%5D%28./1477439257251.png%29%0ASTRATEGY%u7684%u597D%u5904%u662F%uFF0CInt%20Bubble%20Sort%u4E0EBubble%20Sort%u4E92%u76F8%u4E0D%u77E5%u9053%uFF0CInt%20Bubble%20Sort%u53EA%u4F9D%u8D56%u4E8EBubble%20Handler%u63A5%u53E3%uFF0C%u8FD9%u4E5F%u662F%u4E00%u79CD%u4F9D%u8D56%u5012%u7F6E%28DIP%29%u3002%u800CTEMPLATE%20METHOD%u5219%u8FDD%u53CD%u4E86DIP%u3002%u4F46TEMPLATE%20METHOD%u5728%u5B9E%u9645%u5E94%u7528%u4E2D%u662F%u7ECF%u5E38%u51FA%u73B0%u7684%uFF0C%u662F%u4E00%u79CD%u5F88%u7ECF%u5178%u7684%u9762%u5411%u5BF9%u8C61%u91CD%u7528%u5F62%u5F0F%u3002%u57FA%u7C7B%u5B9A%u4E49%u901A%u7528%u7B97%u6CD5%uFF0C%u6D3E%u751F%u7C7B%u901A%u8FC7%u7EE7%u627F%u91CD%u7528%u8BE5%u7B97%u6CD5%u3002%0A%0A%23%23%23FACADE%20%26%20MEDIATOR%0A%23%23%23%23%3Cspan%20id%3D%22facade%22%3EFACADE%3C/span%3E%0A%u5F53%u60F3%u8981%u4E3A%u4E00%u7EC4%u5177%u6709%u590D%u6742%u4E14%u5168%u9762%u7684%u63A5%u53E3%u7684%u5BF9%u8C61%u63D0%u4F9B%u4E00%u4E2A%u7B80%u5355%u4E14%u7279%u5B9A%u7684%u63A5%u53E3%u65F6%uFF0C%u53EF%u4EE5%u4F7F%u7528%u961FFACADE%u6A21%u5F0F%20%u3002%0A%21%5BAlt%20text%7C450x0%5D%28./1478213659914.png%29%0AFACADE%u5728%u5B9E%u9645%u5E94%u7528%u4E2D%u5F88%u591A%uFF0C%u4E4B%u524D%u6211%u4E5F%u662F%u5728%u65E0%u610F%u4E2D%u7528%u5230%u5F88%u591AFACADE%u6A21%u5F0F%uFF0C%u6BD4%u5982%u62BD%u8C61%u5FAE%u535AAPI%u63A5%u53E3%uFF0C%u62BD%u8C61MongoDB%u63A5%u53E3%u3002%u5728%u540E%u6587%u4F1A%u63D0%u5230%uFF0CFACADE%u5B9E%u9645%u662F%u7B80%u5316%u7248%u7684Proxy%u6A21%u5F0F%uFF0C%u5728%u590D%u6742%u5EA6%u4E0D%u9AD8%u7684%u65F6%u5019%uFF0C%u7528FACADE%uFF0C%u4E00%u65E6%u590D%u6742%u5EA6%u5347%u9AD8%u5230%u4E00%u5B9A%u7A0B%u5EA6%u65F6%uFF0C%u53EF%u4EE5%u8003%u8651%u91CD%u6784%u6210Proxy%u6A21%u5F0F%u3002%u5177%u4F53%u4EC0%u4E48%u60C5%u51B5%u4E0B%u9700%u8981%u4F7F%u7528Proxy%uFF0C%u6216%u8005%u4F7F%u7528Proxy%u7684%u597D%u5904%u662F%u4EC0%u4E48%uFF0C%u540E%u6587%u518D%u505A%u8865%u5145%u3002%0A%0A%23%23%23%23MEDIATOR%0A%21%5BAlt%20text%7C450x0%5D%28./1478214139846.png%29%0AMEDIATOR%u7684%u8BCD%u4E49%u662F%u4E2D%u4ECB%uFF0C%u5176%u542B%u4E49%u662F%uFF0C%u5728%u80CC%u540E%u6DFB%u52A0%u5904%u7406%u673A%u5236%u3002%u8FD9%u4E2A%u5B9E%u9645%u4F8B%u5B50%u4E2D%uFF0C%u6240%u8C13mediator%u5C31%u662F%u901A%u8FC7%u76D1%u542C%u6587%u672C%u6846changed%u4E8B%u4EF6%uFF0C%u83B7%u53D6List%u548CTextField%u7684%u5185%u5BB9%u4EE5%u8FDB%u884C%u64CD%u4F5C%u3002%0A%0A%23%23%23SINGLETON%20%26%20MONOSTATE%0A%u8FD9%u4E24%u4E2A%u6A21%u5F0F%u90FD%u662F%u5355%u4F8B%u6A21%u5F0F%uFF0C%u4E00%u4E2A%u5173%u6CE8%u7ED3%u6784%uFF08SINGLETON%uFF09%uFF0C%u4E00%u4E2A%u5173%u6CE8%u884C%u4E3A%uFF08MONOSTATE%uFF09%u3002%0A%23%23%23%23%23%u4F55%u65F6%u9700%u8981%u5355%u4F8B%uFF1F%0A%u4F5C%u8005%u5728%u672C%u7AE0%u5F00%u7BC7%u7684%u65F6%u5019%u8BF4%uFF0C%0A%3E%u90A3%u4E9B%u5F3A%u5236%u5BF9%u8C61%u5355%u4E00%u6027%u7684%u673A%u5236%u4F3C%u4E4E%u6709%u4E9B%u591A%u4F59%u3002%u6BD5%u7ADF%20%uFF0C%u5728%u521D%u59CB%u5316%u5E94%u7528%u7A0B%u5E8F%u65F6%uFF0C%u5B8C%u5168%u53EF%u4EE5%u53EA%u521B%u5EFA%u6BCF%u4E2A%0A%u5BF9%u8C61%u7684%u4E00%u4E2A%u5B9E%u4F8B%uFF0C%u7136%u540E%u4F7F%u7528%u8BE5%u5B9E%u4F8B%u3002%u4E8B%u5B9E%u4E0A%uFF0C**%u8FD9%u901A%u5E38%u4E5F%u662F%u6700%u597D%u7684%u65B9%u6CD5%u3002%u5728%u6CA1%u6709%u6025%u8FEB%u5E76%u4E14%u6709%u610F%u4E49%u7684%u9700%u8981%20%u65F6%uFF0C%u5E94%u8BE5%u907F%u514D%u4F7F%u7528%u8FD9%u4E9B%u673A%u5236**%u3002%0A%0A%u90A3%u5230%u5E95%u4EC0%u4E48%u65F6%u5019%u624D%u662F%u4F7F%u7528SINGLETON%u7684%u6B63%u786E%u65F6%u673A%u5462%uFF1F%u4F5C%u8005%u63A5%u7740%u8BF4%u4E86%0A%3E%u6211%u4EEC%u4E5F%u5E0C%u671B%u4EE3%u7801%u80FD%u591F%u4F20%u8FBE%u6211%u4EEC%u7684%u610F%u56FE%u3002%u5982%u679C%u5F3A%u5236%u5BF9%u8C61%u5355%u4E00%u6027%u7684%u673A%u5236%u662F%u8F7B%u91CF%u7EA7%u7684%uFF0C%u90A3%u4E48**%u4F20%u8FBE%u610F%u56FE**%u5E26%u6765%u7684%u6536%u76CA%u5C31%u4F1A%u80DC%u8FC7%u5B9E%u65BD%u8FD9%u4E9B%u673A%u5236%u7684%u4EE3%u4EF7%u3002%0A%0A%u6240%u4EE5%u4F7F%u7528%u5355%u4F8B%u8981%u7B26%u5408%u4E24%u4E2A%u5143%u7D20%uFF1A%0A1.%20%u673A%u5236%u8F7B%u91CF%u7EA7%uFF0C%u4E5F%u5C31%u662F%u903B%u8F91%u8981%u7B80%u5355%0A2.%20%u9700%u8981%u4F20%u8FBE%u53EA%u5141%u8BB8%u4E00%u4E2A%u5B9E%u4F8B%u7684%u610F%u56FE%0A%0A%u4F5C%u8005%u5728%u672C%u7AE0%u7ED3%u5C3E%u5904%u6307%u51FA%uFF1A%0A%3E%u5982%u679C%u5E0C%u671B%u900F%u8FC7%u6D3E%u751F%u53BB%u7EA6%u675F%u4E00%u4E2A%u73B0%u5B58%u7C7B%uFF0C%u5E76%u4E14%u4E0D%u4ECB%u610F%u5B83%u7684%u6240%u6709%u8C03%u7528%u8005%u90FD%u5FC5%u987B%u8981%u8C03%u7528%60instance%28%29%60%u65B9%u6CD5%u6765%u83B7%u53D6%u8BBF%u95EE%u6743%uFF0C%u90A3%u4E48SINGLETON%u662F%u6700%u5408%u9002%u7684%u3002%u5982%u679C%u5E0C%u671B%u7C7B%u7684%u5355%u4E00%u6027%u672C%u8D28%u5BF9%u4F7F%u7528%u8005%u900F%u660E%uFF0C%u6216%u8005%u5E0C%u671B%u4F7F%u7528%u5355%u4E00%u5BF9%u8C61%u7684%u591A%u6001%u6D3E%u751F%u5BF9%u8C61%uFF0C%u90A3%u4E48MONOSTATE%u662F%u6700%u9002%u5408%u7684%u3002%0A%0A%u5E94%u7528%u573A%u666F%uFF0C%u4F8B%u5982%uFF1A%0A-%20%u5DE5%u5382%u5BF9%20%u8C61%28factories%29%uFF0C%u7528%u6765%u521B%u5EFA%u7CFB%u7EDF%u4E2D%u7684%u5176%u4ED6%u5BF9%u8C61%u3002%0A-%20%u7BA1%u7406%u5668%28managers%29%u5BF9%u8C61%uFF0C%u8D1F%u8D23%u7BA1%u7406%u67D0%u4E9B%u5176%u4ED6%u5BF9%u8C61%u5E76%u4EE5%u5408%u9002%u7684%u65B9%u5F0F%u53BB%u63A7%u5236%u5B83%u4EEC%u3002%0A%0A%u56E0%u4E3A%u8FD9%u4E9B%u7C7B%u5B9E%u4F8B%u4E00%u65E6%u4EA7%u751F%u8D85%u8FC7%u4E00%u4E2A%uFF0C%u5C31%u4F1A%u56E0%u4E3A%u5BF9%u8C61%u4E4B%u95F4%u7684%u540C%u6B65%u95EE%u9898%uFF0C%u4EA7%u751F%u903B%u8F91%u95EE%u9898%u3002%0A%0A%23%23%23%23SINGLETON%0A%60%60%60%0Apublic%20class%20Singleton%20%7B%0A%09private%20static%20Singleton%20theInsLance%20%3D%20null%3B%0A%09private%20Singleton%28%29%20%7B%7D%0A%09public%20static%20Singleton%20Instance%28%29%0A%09%7B%0A%09%09if%20%28theIristance%20%3D%3D%20null%29%0A%09%09%09theInstance%20%3D%20new%20Singleton%28%29%3B%0A%09%09return%20theInstance%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%u79C1%u6709%u6784%u9020%u51FD%u6570%uFF0C%u901A%u8FC7static%u63A5%u53E3%u6765%u505A%u5B9E%u4F8B%u5316%uFF0C%u63A7%u5236%u7C7B%u5B9E%u4F8B%u53EA%u6709%u4E00%u4E2A%u3002%0A%u4E0B%u9762%u7684%u4F8B%u5B50%u662FPhoenix%u4EE3%u7801%u4E2D%u6700%u5E38%u89C1%u7684%u5355%u4F8B%u6A21%u5F0F%u3002%0A%60%60%60%0Aclass%20Child%20%3A%20public%20Parent%0A%7B%0A%09Child%28%29%7B%7D%0A%7D%0Aclass%20Factory%7B%0A%09static%20Parent*%20Instance%20%28%29%0A%09%7B%0A%09%09static%20Child%20child%3B%0A%09%09return%20%26child%3B%0A%09%7D%20%0A%7D%0A%60%60%60%0A%u5229%u7528%u5C40%u90E8%u7684static%u53D8%u91CF%u5B9E%u73B0%u5355%u4F8B%u3002%u4E0D%u7BA1%u7528%u4E0A%u9762%u7684%u54EA%u79CD%u65B9%u5F0F%uFF0C%u5176%u5B9E%u4F8B%u5316%u8FC7%u7A0B%u90FD%u4E0D%u662F%u7ECF%u5178%u7684%u9762%u5411%u5BF9%u8C61%u65B9%u6CD5%uFF0C%u800C%u9700%u8981%u8C03%u7528%u8005%u9075%u5FAA%u7EA6%u5B9A%uFF0C%u8C03%u7528%u7279%u6B8A%u7684%u63A5%u53E3%u4EE5%u521B%u5EFA%u7C7B%u5B9E%u4F8B%u3002%u5176%u521B%u5EFA%u7684%u5B9E%u4F8B%u786E%u5B9E%u90FD%u6307%u5411%u540C%u4E00%u4E2A%u771F%u6B63%u7684%u5BF9%u8C61%u3002%0A%0A%23%23%23%23MONOSTATE%0A%u6B64%u6A21%u5F0F%u4E0ESINGLETON%u4E0D%u540C%uFF0CMONOSTATE%u5F3A%u8C03%u7684%u662F%u6240%u6709%u521B%u5EFA%u7684%u5BF9%u8C61%u5177%u6709%u76F8%u540C%u7684%u884C%u4E3A%u3002%0A%60%60%60%0Apublic%20class%20MonoState%20%7B%0A%09private%20static%20int%20itsX%3B%0A%09public%20void%20setX%28int%20x%29%20%7B%0A%09%09itsX%20%3D%20x%3B%0A%09%7D%0A%09public%20int%20getX%28%29%7B%0A%09%09return%20itsX%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%u8FD9%u91CC%u6709%u4E00%u4E2A%u7EA6%u5B9A%uFF1A**%u6240%u6709%u7684%u7C7B%u6210%u5458%u5747%u4E3Astatic%uFF0C%u6240%u6709%u7684%u65B9%u6CD5%u5747%u4E3A%u975Estatic**%0A%u6240%u6709%u65B9%u6CD5%u4E3A%u975Estatic%u7684%u7528%u610F%u662F%uFF0C%u5176%u63A5%u53E3%u5747%u53EF%u7EE7%u627F%u5230%u6D3E%u751F%u7C7B%u4E2D%u3002%u6240%u6709%u6210%u5458%u53D8%u91CF%u662Fstatic%uFF0C%u4E00%u65B9%u9762%u4FDD%u8BC1%u6240%u6709%u7C7B%u5BF9%u8C61%u5177%u6709%u76F8%u540C%u5C5E%u6027%uFF0C%u53E6%u4E00%u65B9%u9762%u4E5F%u4FDD%u8BC1%u4E86MONOSTATE%u7C7B%u7684%u6D3E%u751F%u7C7B%u90FD%u5177%u6709MONOSTATE%u7279%u6027%u3002%u800C%u5B9E%u9645%u4E0A%uFF0C%u6240%u6709%u6D3E%u751F%u7C7B%u90FD%u5171%u4EAB%u540C%u4E00%u4E2AMONOSTATE%u7684%u4E00%u90E8%u5206%u3002%0A%0A%23%23%23NULL%20OBJECT%u6A21%u5F0F%0A%u8FD9%u662F%u4E00%u4E2A%u5F88%u5B9E%u7528%uFF0C%u4F46%u53C8%u603B%u662F%u5F88%u5BB9%u6613%u88AB%u5FFD%u7565%u7684%u6A21%u5F0F%u3002%u6211%u4EEC%u5728%u5199code%u7684%u65F6%u5019%uFF0C%u4E0B%u9762%u7684%u60C5%u51B5%u5F88%u5E38%u89C1%uFF1A%0A%60%60%60%0AEmployee%20e%20%3D%20DB.getEmployee%28%22Bob%22%29%3B%0Aif%20%28e%20%21%3D%20null%20%26%26%20e.isTimeToPay%28today%29%29%0A%09e.pay%28%29%3B%0A%60%60%60%0A%u5148%u83B7%u5F97%u4E00%u4E2A%u5BF9%u8C61%uFF0C%u5728%u5931%u8D25%u65F6%u8FD4%u56DEnull%uFF0C%u7136%u540E%u6839%u636E%u8FD4%u56DE%u7684%u7ED3%u679C%u505A%u4E0B%u4E00%u6B65%u64CD%u4F5C%u3002%u4F7F%u7528NULL%20OBJECT%u4EE5%u540E%u7684%u6837%u5B50%uFF0C%u53EF%u80FD%u662F%u8FD9%u6837%u7684%uFF1A%0A%60%60%60%0AEmployee%20e%20%3D%20DB.getEmployee%28%22Bob%22%29%3B%0Aif%20%28e.isTimeToPay%28today%29%29%0A%09e.pay%28%29%3B%0A%0Apublic%20class%20NullEmployee%20%7B%0A%09public%20boolean%20isTimeToPay%28Date%20data%29%20%7B%0A%09%09return%20false%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%u8FDB%u9636NULL%20OBJECT%0A%60%60%60%0Aimport%20java.util.Date%3B%0Apublic%20interface%20Employee%0A%7B%0A%09public%20boolean%20isTimeToPay%28Date%20payDate%29%3B%0A%09public%20void%20pay%28%29%3B%0A%09public%20static%20final%20Employee%20NULL%20%3D%20new%20Employee%28%29%0A%09%7B%0A%09%09public%20boolean%20isTimeToPay%28Date%20payDate%29%0A%09%09%7B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%09%09public%20void%20pay%28%29%0A%09%09%7B%0A%09%09%7D%0A%09%7D%3B%0A%7D%0A%60%60%60%0A%u4F7F%u65E0%u6548%u96C7%u5458%u7C7B%u6210%u4E3A%u4E00%u4E2A%u533F%u540D%u5185%u5D4C%u7C7B%u662F%u4E00%u79CD%u786E%u4FDD%u8BE5%u7C7B%u53EA%u6709%u5355%u4E00%u5B9E%u4F8B%u7684%u65B9%u6CD5%u3002%u5B9E%u9645%u4E0A%u5E76%u4E0D%u5B58%u5728NullEmplyee%u7C7B%u672C%u8EAB%u3002%u5176%u4ED6%u4EFB%u4F55%u4EBA%u90FD%u65E0%u6CD5%u521B%u5EFANULL%u7C7B%u5B9E%u4F8B%u3002%u5E76%u4E14static%20final%u53D8%u91CF%u4E5F%u4FDD%u8BC1%u4E86NULL%u7684%u5355%u4F8B%u6027%u3002**%u5982%u679CNULL%u4E0D%u80FD%u505A%u5230%u5355%u4F8B%u7684%u8BDD%uFF0C%u4F1A%u5F15%u53D1%u6B67%u4E49**%uFF0C%u5BFC%u81F4%u4E0D%u53EF%u9884%u77E5%u7684%u9519%u8BEF%u3002%0A%0A%23%23%u7B2C20-22%u7AE0%0A%u672C%u90E8%u5206%u53EA%u8BB2%u4E86%u4E00%u4E2A%u6A21%u5F0F%28FACTORY%29%uFF0C%u4F46%u653E%u5165%u4E86%u4E00%u4E2A%u5F88%u6709%u7528%u7684%u7AE0%u8282%u2014%u2014%u5173%u4E8E%u5305%u7684%u8BBE%u8BA1%u539F%u5219%u3002%u5305%u662F%u7C7B%u7684%u96C6%u5408%uFF0C%u5F53%u8F6F%u4EF6%u8FBE%u5230%u4E00%u5B9A%u89C4%u6A21%u65F6%uFF0C%u5C31%u9700%u8981%u8003%u8651%u5305%u7684%u8BBE%u8BA1%u4E86%u3002%u6211%u89C9%u5F97%u8FD9%u503C%u5F97%u53CD%u590D%u9605%u8BFB%u3002%u6211%u6253%u7B97%u98A0%u5012%u4E66%u4E0A%u7684%u987A%u5E8F%uFF0C%u5148%u7F57%u5217FACTORY%u6A21%u5F0F%uFF0C%u518D%u6765%u770B%u5305%u8BBE%u8BA1%u89C4%u5219%u3002%0A%0A%23%23%23FACTORY%0A%u8FD9%u4E2A%u6A21%u5F0F%uFF0C%u662F%u6211%u9605%u8BFB%u8FD9%u672C%u4E66%u8FC4%u4ECA%u4E3A%u6B62%uFF08%u8FD8%u6709%u7B2C%u56DB%u90E8%u5206%u7684%u4E09%u7AE0%u672A%u770B%uFF09%uFF0C%u6700%u6709%u7528%u7684%u6A21%u5F0F%u3002%u4ED6%u56DE%u7B54%u4E86%u6211%u5230%u5E95%u8BE5%u5728%u54EA%u91CC%u4F20%u5165%u591A%u6001%u7ED1%u5B9A%u4FE1%u606F%u3002%0A%60%60%60%0Aclass%20Child1%20%3A%20Parent%7B%7D%0Aclass%20Child2%20%3A%20Parent%7B%7D%0Aswitch%20%28info%29%7B%0A%09case%20A%3A%0A%09%09Parent*%20obj%20%3D%20new%20Child1%28%29%3B%0A%09%09break%3B%0A%09case%20B%3A%0A%09%09Parent*%20obj%20%3D%20new%20Child2%28%29%3B%0A%09%09break%3B%0A%7D%0A%60%60%60%0A%u4E0A%u9762%u8FD9%u4E00%u6BB5%u4E0D%u7BA1%u662F%u65E9%u7ED1%u5B9A%uFF0C%u8FDF%u7ED1%u5B9A%uFF0C%u603B%u662F%u8981%u51FA%u73B0%u7684%u3002%u653E%u5728%u54EA%u91CC%uFF1F%u653E%u5728FACTORY%u91CC%u3002%0A%u4E3A%u4EC0%u4E48%u8981%u653E%u5230FACTORY%u91CC%uFF1F%u6362%u53E5%u8BDD%u8BF4%uFF1A%0A%0A%23%23%23%23%u4E3A%u4EC0%u4E48%u8981%u4F7F%u7528FACTORY%uFF1F%0A%u4F5C%u8005%u8BF4%uFF1A%0A%3EFACTORY%u6A21%u5F0F%u5141%u8BB8%u6211%u4EEC%u53EA%u4F9D%u8D56%u4E8E%u62BD%u8C61%u63A5%u53E3%u5C31%u80FD%u521B%u5EFA%u51FA%u5177%u4F53%u5BF9%u8C61%u7684%u5B9E%u4F8B%u3002%u6240%20%u4EE5%20%uFF0C%u5728%u6B63%u5728%u8FDB%u884C%u7684%u5F00%u53D1%u671F%u95F4%uFF0C%u5982%u679C%u5177%u4F53%u7C7B%u662F%u9AD9%u5EA6%u6613%u53D8%u7684%uFF0C%u90A3%u4E48%u8BE5%u6A21%u5F0F%u662F%u975E%u5E38%u6709%u7528%u7684%u3002%0A%0A%u4E25%u683C%u6309%u7167DIP%u6765%u8BB2%uFF0C%u5FC5%u987B%u8981%u5BF9%u7CFB%u7EDF%u4E2D%u6240%u6709%u7684%u6613%u53D8%u7C7B%u4F7F%u7528%u5DE5%u5382%u3002%u9488%u5BF9%u8FD9%u53E5%u8BDD%uFF0C%u4F5C%u8005%u53C8%u8BF4%uFF1A%0A%3E%u6211%u4E0D%u662F%u4E00%u5F00%u59CB%u5C31%u4F7F%u7528%u4E01%u5382%u3002%u53EA%u662F%u5728%u975E%u5E38%u9700%u8981%u5B83%u4EEC%u7684%u60C5%u51B5%u4E0B%uFF0C%u6211%u624D%u628A%u5B83%u4EEC%u653E%u5165%u5230%u7CFB%u7EDF%u4E2D%u3002%u4F8B%u5982%uFF0C%0A%3E%20-%20%u5982%u679C%u6709%u5FC5%u8981%u4F7F%u7528PROXY%u6A21%u5F0F%uFF0C%u90A3%u4E48%u5C31%u53EF%u80FD%u6709%u5FC5%u8981%u4F7F%u7528%u5DE5%u5382%u53BB%u521B%u5EFA%u6301%u4E45%u5316%u5BF9%u8C61%u3002%0A%3E%20-%20%u6216%u8005%uFF0C%u5728%u5355%u5143%u6D4B%u8BD5%u671F%u95F4%uFF0C%u5982%u679C%u9047%20%u5230%u5FC5%u987B%u8981%u6B3A%u9A97%u4E00%u4E2A%u5BF9%u8C61%u7684%u521B%u5EFA%u8005%u7684%u60C5%u51B5%u65F6%uFF0C%u90A3%u4E48%u6211%u5F88%u53EF%u80FD%u4F1A%u4F7F%u7528%u5DE5%u5382%u3002%0A%3E%0A%3E%u4F46%u662F%u6211%u4E0D%u662F%u4E00%u5F00%u59CB%u5C31%u5047%u8BBE%u5DE5%u5382%u662F%u5FC5%u8981%u7684%u3002%0A%0A%u4E00%u5F00%u59CB%uFF0C%u4E0D%u7406%u89E3%u8FD9%u53E5%u8BDD%uFF0C%u73B0%u5728%u6DF1%u6DF1%u4F53%u4F1A%uFF0C%u5DE5%u5382%u6A21%u5F0F%u771F%u7684%u597D%uFF0C%u5F88%u5BB9%u6613%u88AB%u6EE5%u7528%u3002%u6211%u73B0%u5728%u5C31%u6709%u6EE5%u7528%u7684%u503E%u5411%u3002%0A%0A%60%60%60%0Apublic%20interface%20IFactory%7B%0A%09public%20IObject%20makeObject%28%29%3B%0A%7D%0Apublic%20class%20Factory%20implements%20IFactory%7B%0A%09@Override%0A%09public%20IObject%20makeObject%28%29%7B%0A%09%09return%20new%20Object%28%29%3B%0A%09%7D%0A%7D%0Apublic%20class%20Invoker%7B%0A%09public%20void%20func%28%29%7B%0A%09%09IFactory%20factory%20%3D%20new%20Factory%28%29%3B%0A%09%09IObject%20%3D%20factory.makeObject%28%29%3B%0A%09%7D%0A%7D%0A%60%60%60%0AInvoker%u7C7B%u5B8C%u5168%u4F9D%u8D56%u4E8E%u62BD%u8C61%u7684%u63A5%u53E3%u2014%u2014%u5DE5%u5382%u63A5%u53E3%u548CObject%u63A5%u53E3%uFF0C%u800C%u4E0D%u4F9D%u8D56%u4E8E%u5177%u4F53%u7684%u7C7B%u3002%u5728%u5F00%u53D1%u9636%u6BB5%uFF0C%u6216%u8005%u7C7B%u7ED3%u6784%u4E0D%u7A33%u5B9A%u9636%u6BB5%uFF0C%u6211%u4EEC%u53EF%u4EE5%u4EFB%u610F%u4FEE%u6539makeObject%u63A5%u53E3%u7684%u5B9E%u73B0%u6765%u751F%u4EA7%u6211%u4EEC%u9700%u8981%u7684%u5BF9%u8C61%u3002%0A%0A%u5DE5%u5382%u6A21%u5F0F%u5728%u5355%u5143%u6D4B%u8BD5%u4E2D%u4E5F%u662F%u5F88%u6709%u7528%u7684%u3002%u6211%u4EEC%u53EF%u4EE5%u901A%u8FC7%u66FF%u6362%u5177%u4F53%u7684%u5DE5%u5382%u7C7B%u6765%u5B9E%u73B0%u771F%u5B9E%u7684%u7C7B%u548Cmock%u7C7B%u4E4B%u95F4%u7684%u5207%u6362%u3002%u5F53%u7136%u6211%u4EEC%u4E5F%u53EF%u4EE5%u7528mockito%u6765%u5E2E%u6211%u4EEC%u505A%u8FD9%u4E9B%u4E8B%u60C5%u3002%u5982%u679C%u7C7B%u5E9E%u5927%u7684mockito%u89E3%u51B3%u4E0D%u4E86%uFF0C%u4E00%u4E2A%u5DE5%u5382%u7C7B%u53EF%u80FD%u4F1A%u7ED9%u6211%u4EEC%u63D0%u4F9B%u610F%u60F3%u4E0D%u5230%u7684%u65B9%u4FBF%u3002%0A%0A%3E%u4F5C%u8005%u7684%u4F8B%u5B50%uFF1A%0A%3E%u5728%20%u67D0%20%u4E9B%20%u60C5%20%u51B5%20%u4E0B%20%uFF0C%20Payroll%20Test%u628A%20Database%u7684%u5F15%u7528%u4F20%u9012%u7ED9Payrol%20l%u662F%u76F8%u5F53%u81EA%u7136%u7684%uFF0C%u5728%u53E6%u4E00%u4E9B%u60C5%u51B5%u4E0B%uFF0C%u6709%u53EF%u80FDPayrollTest%u5FC5%u987B%u8BBE%u7F6E%u4E00%u4E2A%u5168%u5C40%u53D8%u91CF%u4FDD%u5B58%u5BF9Database%u7684%u5F15%u7528%u3002%u8FD8%u6709%u4E00%u4E9B%u60C5%u51B5%u4E0BPayroll%u53EF%u80FD%u5B8C%u5168%u671F%u671B%u81EA%u5DF1%u6765%u521B%u5EFADatabase%u5B9E%u4F8B%u3002%u5728%u6700%u540E%u4E00%u79CD%u60C5%u51B5%u4E2D%uFF0C%u53EF%u4EE5%u4F7F%u7528FACTORY%u6A21%u5F0F%uFF0C%u901A%u8FC7%u4F20%u7ED9Payroll%u53E6%u5916%u4E00%u4E2A%u5DE5%u5382%u5BF9%u8C61%uFF0C%u6765%u6B3A%u9A97Payroll%u521B%u5EFA%u51FADatabase%u7684%u6D4B%u8BD5%u7248%u672C%u3002%0A%0A%21%5BAlt%20text%7C500x0%5D%28./1478441361359.png%29%0A%0A%23%23%23%u5305%u8BBE%u8BA1%u539F%u5219%0A%23%23%23%23%u7C92%u5EA63%u539F%u5219%u2014%u2014%u5982%u4F55%u51B3%u5B9A%u54EA%u4E9B%u7C7B%u5E94%u5F53%u653E%u5165%u4E00%u4E2A%u5305%0A%23%23%23%23%23REP%20%u2014%u2014Reuse-Release%20Equivalence%20Principle%20%u91CD%u7528%u53D1%u5E03%u7B49%u6548%u539F%u5219%0A%u4E00%u4E2A%u5305%u4E2D%u7684%u8F6F%u4EF6%u8981%u4E48%u90FD%u662F%u53EF%u91CD%u7528%u7684%uFF0C%u8981%u4E48%u90FD%u662F%u4E0D%u53EF%u91CD%u7528%u7684%u3002%u6211%u4EEC%u4E0D%u5E0C%u671B%u4E00%u4E2A%u7528%u6237%u53D1%u73B0%u5305%u4E2D%u6240%u5305%u542B%u7684%u7C7B%u4E2D%uFF0C%u4E00%u4E9B%u662F%u4ED6%u6240%u9700%u8981%u7684%uFF0C%u53E6%u4E00%u4E9B%u5BF9%u4ED6%u5374%u5B8C%u5168%u4E0D%u9002%u5408%u3002%0A%u6211%u7406%u89E3%u7684%u610F%u601D%u5C31%u662F%uFF0C%u8003%u8651%u95EE%u9898%u8981%u4EE5%u5305%u4E3A%u6700%u5C0F%u7C92%u5EA6%u3002%u7C7B%u4F3C%u7C7B%u8BBE%u8BA1%u7684SRP%uFF0C%u5355%u4E00%u804C%u8D23%u539F%u5219%u3002%0A%0A%23%23%23%23%23CRP%u2014%u2014Common%20Reuse%20Principle%u5171%u540C%u91CD%u7528%u539F%u5219%0ACRP%u89C4%u5B9A%u76F8%u4E92%u4E4B%u95F4%u6CA1%u6709%u7D27%u5BC6%u8054%u7CFB%u7684%u7C7B%u4E0D%u5E94%u8BE5%u5728%u540C%u4E00%u4E2A%u5305%u4E2D%0A%0A%23%23%23%23%23CCP%u2014%u2014Common%20Close%20Principle%u5171%u540C%u5C01%u95ED%u539F%u5219%0A%u8FD9%u6761%u539F%u5219%u89C4%u5B9A%u4E86%u4E00%u4E2A%u5305%u5C0F%u5E94%u8BE5%u5305%u4ECB%u591A%u4E2A%u5F15%u8D77%u53D8%u5316%u7684%u539F%u56E0%u3002%0A%0A%23%23%23%23%u7A33%u5B9A%u6027%u539F%u5219%0A%u5982%u4F55%u907F%u514D%22%u6668%u540E%u7EFC%u5408%u75C7%22%0A-%20%u6BCF%u5468%u6784%u5EFA%0A-%20ADP%u2014%u2014Acyclic%20Dependencies%20Principle%u65E0%u73AF%u4F9D%u8D56%0A%0A%u6709%u4F9D%u8D56%u73AF%uFF0C%u5219%u4F1A%u5F71%u54CD%u5230%u73AF%u4E0A%u8282%u70B9%u76F8%u5173%u7684%u6240%u6709%u8282%u70B9%uFF0C%u8FDB%u800C%u5BFC%u81F4%u6574%u4E2A%u8F6F%u4EF6%u5305%u7684%u5D29%u6E83%u3002%u6240%u4EE5%u5207%u8BB0%uFF0C%u4F9D%u8D56%u5173%u7CFB%u5206%u6790%u5F88%u91CD%u8981%uFF0C%u7EDD%u4E0D%u80FD%u6709%u4F9D%u8D56%u73AF%u3002%0A%0A%23%23%23%23%23%u89E3%u9664%u4F9D%u8D56%u73AF%u7684%u65B9%u6CD5%0A%21%5BAlt%20text%7C450x0%5D%28./1478442717383.png%29%0A1.%20%u4F9D%u8D56%u5012%u7F6E%uFF08DIP%uFF09%0A%21%5BAlt%20text%7C600x0%5D%28./1478442749395.png%29%0A2.%20%u5B9A%u4E49%u51FA%u5171%u540C%u4F9D%u8D56%u7684%u5305%0A%0A20.5%2620.6%u662F%u672C%u7AE0%u7684%u6838%u5FC3%uFF0C%u5728%u8FD9%u4E24%u8282%u4E2D%uFF0C%u4F5C%u8005%u9610%u8FF0%u4E86%u5982%u4F55%u5B9A%u91CF%u5730%u5206%u6790%u5305%u7684%u7A33%u5B9A%u6027%uFF0C%u5E76%u6307%u5BFC%u6211%u4EEC%u7A76%u7ADF%u6539%u5982%u4F55%u5206%u5E03%u7A33%u5B9A%u7C7B%u548C%u975E%u7A33%u5B9A%u7C7B%u3002%u8FD9%u5176%u4E2D%u6709%u4E00%u53E5%u8BDD%uFF0C%u8BA9%u6211%u5370%u8C61%u9887%u4E3A%u6DF1%u523B%uFF1A%0A%3E%u5E76%u4E0D%u662F%u6240%u6709%u7684%u7C7B%u90FD%u9002%u5408%u4F5C%u4E3A%u7A33%u5B9A%u7C7B%u3002%0A%0A%u8FD9%u4E00%u7AE0%u5185%u5BB9%u9002%u5408%u53CD%u590D%u7814%u8BFB%uFF0C%u6211%u6253%u7B97%u7559%u505A%u4E0B%u4E00%u6B21%u518D%u6765%u505A%u7B14%u8BB0%u3002%0A%0A%23%2323-27%u7AE0%0A%23%23%23COMPOSITE%0A%u8FD9%u4E2A%u6A21%u5F0F%u662F%u5BF9%5BCOMMAND%5D%28%23jump%29%u6A21%u5F0F%u7684%u6269%u5C55%u3002%u4E3A%u7684%u662F%u8BA9%u591A%u4E2A%u5BF9%u8C61%u7684%u884C%u4E3A%u8868%u73B0%u7684%u50CF%u4E00%u4E2A%u5BF9%u8C61%u3002%u4F8B%u5982%uFF1A%0A%21%5BAlt%20text%5D%28./1478938642614.png%29%0A%u5F53sensor%u9700%u8981%u4E00%u6B21%u8FD0%u884C%u591A%u4E2A%u547D%u4EE4%u7684%u65F6%u5019%u600E%u4E48%u529E%uFF1F%u662F%u4FEE%u6539%uFF0Csensor%uFF0C%u4FEE%u6539%u7ED1%u5B9A%u903B%u8F91%uFF0C%u8FD8%u662F%u4FEE%u6539command%u672C%u8EAB%uFF1F%u6700%u7B80%u5355%u7684%u65B9%u6CD5%u5C31%u662F%u4FEE%u6539%u7ED1%u5B9A%u903B%u8F91%u7684%u65F6%u5019%uFF0C%u6539%u4E3A%u7ED1%u5B9A%u4E00%u4E2Acomposite%u547D%u4EE4%uFF0C%u8FD9%u4E2A%u547D%u4EE4%u7EE7%u627F%u81EAcommand%u63A5%u53E3%uFF0C%u5E76%u4E14%u4ED6%u5305%u542B%u4E86%u591A%u6761%u540C%u6837%u884C%u4E3A%u7684%u547D%u4EE4%u3002%0A%0A%23%23%23OBSERVER%0A%u8FD9%u4E00%u7AE0%uFF0C%u4F5C%u8005%u7ED9%u51FA%u4E86%u5982%u4F55%u4ECE%u6700%u57FA%u672C%u7684coding%u65B9%u5F0F%uFF0C%u63A8%u6F14%u51FA%u5982%u4F55%u5957%u7528%u5408%u9002%u7684%u6A21%u5F0F%u3002%u5176%u57FA%u672C%u601D%u60F3%u5C31%u662F%0A%3E**%u4E0D%u8981%u8FC7%u5EA6%u8BBE%u8BA1%uFF0C%u800C%u662F%u5728%u4E0D%u65AD%u7684%u91CD%u6784%u4E2D%uFF0C%u5411%u67D0%u4E00%u79CD%u6A21%u5F0F%u4E0D%u65AD%u9760%u8FD1%uFF0C%u5F53%u5176%u7ED3%u6784%u5DF2%u7ECF%u6F14%u5316%u6210%u67D0%u4E00%u79CD%u6A21%u5F0F%u65F6%uFF0C%u5C06%u6240%u6709%u7684%u540D%u79F0%u4FEE%u6539%u4E3A%u8BE5%u6A21%u5F0F%u7684%u672F%u8BED%uFF0C%u4ECE%u800C%u8FBE%u5230%u4F7F%u7528%u6A21%u5F0F%u7684%u76EE%u7684**%0A%0A%u8FD9%u5B9E%u9645%u662F%u672C%u7AE0%u7684%u7CBE%u9AD3%u3002%0A%u4E0D%u8FC7%u672C%u7AE0%u5728%u9610%u8FF0%u4E0A%u8FF0%u8715%u5316%u6F14%u8FDB%u7684%u8FC7%u7A0B%u7684%u65F6%u5019%uFF0C%u4EE5OBSERVER%u6A21%u5F0F%u4E3A%u4F8B%uFF0C%u4E5F%u5C06%u8FD9%u4E2A%u6A21%u5F0F%u7684%u539F%u7406%u548C%u4F7F%u7528%u65B9%u6CD5%u8BB2%u7684%u5F88%u6E05%u695A%u4E86%u3002%0A%21%5BAlt%20text%5D%28./1479025492315.png%29%0A%21%5BAlt%20text%5D%28./1479025507770.png%29%0ASubject%u4E3B%u9898%uFF0CObserver%u89C2%u5BDF%u8005%u3002%u89C2%u5BDF%u8005%u5411%u4E3B%u9898%u6CE8%u518C%u81EA%u5DF1%uFF0C%u4E3B%u9898%u5728%u53D1%u751F%u53D8%u5316%u65F6%uFF0C%u66F4%u65B0%u89C2%u5BDF%u8005%u3002Subject%u548CObserver%u662F%u7CFB%u7EDF%u53EF%u91CD%u7528%u63A5%u53E3%uFF0C%u5177%u4F53%u7684%u7C7B%u7EE7%u627F%u81EA%u8FD9%u4E24%u4E2A%u63A5%u53E3%uFF0C%u4ECE%u800C%u5177%u6709OBSERVER%u6A21%u5F0F%u7684%u529F%u80FD%u3002%0A%23%23%23%23%23%u4E24%u79CD%u6A21%u5F0F%u2014%u2014%u63A8%26%u62C9%0A%u62C9%u6A21%u5F0F%u9002%u5408%u7B80%u5355%u7684%u4FE1%u606F%u4EA4%u4E92%uFF0CObserver%u77E5%u9053%u53BBSubject%u62C9%u4EC0%u4E48%u4FE1%u606F%u3002%0A%u817F%u6A21%u5F0F%u9002%u5408%u590D%u6742%u4FE1%u606F%u4EA4%u4E92%uFF0C%u7531Subject%u544A%u8BC9Observer%u4EC0%u4E48%u4FE1%u606F%u53D1%u751F%u4E86%u53D8%u5316%u3002%0A%23%23%23ABSTRACT%20SERVER%2C%20ADAPTER%26BRIDGE%0A%23%23%23%23ABSTRACT%20SERVER%0A%u8FD9%u4E2A%u6A21%u5F0F%u5F88%u7B80%u5355%uFF0C%u5F88%u5BB9%u6613%u7406%u89E3%uFF0C%u770B%u4E0B%u9762%u4E24%u5E45%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1479027605482.png%29%0A%u5DE6%u8FB9%u8FDD%u53CD%u4E86OCP%u548CDIP%0A-%20%u5BF9Switch%u7684%u7EE7%u627F%uFF0C%u603B%u662F%u5E26%u4E0A%u4E86Light%u4FE1%u606F%uFF0C%u6709%u53EF%u80FD%u5BFC%u81F4%u4FEE%u6539%0A-%20%u9AD8%u5C42Switch%u4F9D%u8D56%u4E8ELight%0A%0A%u53F3%u8FB9%u7684%u56FE%u5C06Switch%u63A5%u53E3%u62BD%u8C61%u51FA%u6765%uFF0C%u4E0D%u7BA1%u63A7%u5236%u4EC0%u4E48%u8BBE%u5907%uFF0C%u53EA%u8981%u5B9A%u4E49%u4E86%u8BE5%u63A5%u53E3%u5C31%u53EF%u4EE5%u3002%0A%u5728%u8FD9%u91CC%uFF0C%u59CB%u7EC8%u8426%u7ED5%u6211%u7684%u4E00%u4E2A%u95EE%u9898%u53C8%u51FA%u73B0%u4E86%uFF0C%u5C31%u662F%u4F55%u65F6%u5B9E%u4F8B%u5316Light%u7C7B%uFF1F%u6309%u7167%u56FE25.2%u7684%u903B%u8F91%uFF0C%u5E94%u8BE5%u662FSwitch%u5305%u542B%u4E00%u4E2ALight%u5BF9%u8C61%uFF0C%u5728%u8C03%u7528Switch%u7684turnOn%u65F6%uFF0C%u59D4%u6258%u7ED9Light%u7684turnOn%u3002%0A1.%20%u90A3%u4E48%u523025.3%u4E2D%uFF0C%u5C31%u5E94%u8BE5%u662FSwitch%u6301%u6709%u4E00%u4E2ASwitchable%u7684%u5BF9%u8C61%uFF08%u53EF%u80FD%u662FLight%u6216%u8005Fan%u7B49%u7B49%uFF09%u3002%u90A3%u5C31%u53EF%u80FD%u662F%u7531%u67D0%u4E2A%u5DE5%u5382%u6765%u4EA7%u751F%u8FD9%u4E2A%u5BF9%u8C61%u7ED9Switch%u3002%0A2.%20%u8FD8%u6709%u4E00%u79CD%u53EF%u80FD%u5C31%u662F%uFF0C%u7531%u5BA2%u6237%u903B%u8F91%u6765%u5B9E%u73B0Switch%u548CSwitchable%u5BF9%u8C61%u7684%u7ED1%u5B9A%u3002%u4F8B%u5982%60Switch.setSwitchable%28Light%29%60%u3002%u5728Switch%u4E2D%u65E0%u5DEE%u522B%u7684%u4F7F%u7528Switchable%u63A5%u53E3%u3002%0A%0A%u4E24%u4E2A%u90FD%u662F%u6211%u7684%u7406%u89E3%uFF0C%u4E0D%u4E00%u5B9A%u6B63%u786E%u3002%u4EE5%u540E%u82E5%u6709%u673A%u4F1A%u4E0E%u5927%u5E08%u4EA4%u6D41%uFF0C%u53EF%u4EE5%u5F53%u9762%u63D0%u51FA%u8FD9%u4E2A%u95EE%u9898%u3002%0A%23%23%23%23%u8C01%u62E5%u6709%u8FD9%u4E2A%u63A5%u53E3%0A%u5728%u8FD9%u4E00%u7AE0%u4F5C%u8005%u8FD8%u63D0%u51FA%u4E86%u4E00%u4E2A%u5F88%u503C%u5F97%u91CD%u89C6%u7684%u95EE%u9898%uFF08%u5176%u5B9E%u5728%u524D%u9762%u7684%u7AE0%u8282%u5DF2%u7ECF%u51FA%u73B0%u8FC7%uFF09%uFF0C%u5C31%u662F%u63A5%u53E3%u5230%u5E95%u8BE5%u548C%u8C01%u6253%u5305%uFF1F%u770B%u4F5C%u8005%u7684%u9610%u8FF0%uFF1A%0A%3E**%u5BA2%u6237%u548C%u63A5%u95E8%u4E4B%u95F4%u7684%u903B%u8F91%u7ED1%u5B9A%u5173%u7CFB%u8981%u5F3A%u4E8E%u63A5%u53E3%u548C%u5B83%u7684%u6D3E%u751F%u7C7B%u4E4B%u95F4%u7684%u903B%u8F91%u7ED1%u5B9A%u5173%u7CFB**%u3002%u5B83%u4EEC%u4E4B%u95F4%u7684%u5173%u7CFB%u5F3A%u5230%u5728%u6CA1%u6709Switchable%u7684%u60C5%u51B5%u4E0B%u5C31%u65E0%u6CD5%u4F7F%u7528Switch%uFF1B%u4F46%u662F%uFF0C%u5728%u6CA1%u6709%u53E3Light%u7684%u60C5%u51B5%u4E0B%u5374%u5B8C%u5168%u53EF%u4EE5%u4F7F%u7528Switch%u3002%u903B%u8F91%u5173%u7CFB%u7684%u5F3A%u5EA6%u548C%u5B9E%u4F53%20%u5173%u7CFB%u7684%u5F3A%u5EA6%u662F%u4E0D%u4E00%u81F4%u7684%u3002%u7EE7%u627F%u662F%u4E00%u4E2A%u6BD4%u5173%u8054%u5F3A%u5F97%u591A%u7684%u5B9E%u4F53%u5173%u7CFB%u3002%0A%0A%u6362%u53E5%u8BDD%u8BF4%uFF0C%u6211%u4EEC%u5E94%u5F53%u6309%u7167%u903B%u8F91%u5173%u7CFB%u7684%u5F3A%u5F31%u6765%u51B3%u5B9A%u5305%u7684%u8FB9%u754C%uFF0C%u5373%u63A5%u53E3%u7684%u5BA2%u6237%u5E94%u5F53%u63A5%u53E3%u7684%u5B9A%u4E49%u3002%u7EE7%u627F%u5173%u7CFB%u662F%u5929%u7136%u7684%uFF0C%u6211%u4EEC%u5E94%u5F53%u53C2%u8003%u7684%u662F%u7C7B%u4E4B%u95F4%u7684%u903B%u8F91%u5173%u7CFB%u3002%0A%23%23%23%3Cspan%20id%3D%22adapter%22%3EADAPTER%3C/span%3E%0A%u5148%u770B%u4EC0%u4E48%u662FADAPTER%u6A21%u5F0F%0A%u4E00%u822C%u5F62%u5F0F%u7684ADAPTER%uFF1A%0A%21%5BAlt%20text%7C450x0%5D%28./1479029079969.png%29%0A%u7C7B%u5F62%u5F0F%u7684ADAPTER%uFF1A%0A%21%5BAlt%20text%7C450x0%5D%28./1479029186606.png%29%0A%u4E0D%u540C%u7684%u662F%u524D%u8005%u7528%u7EC4%u5408%uFF0C%u540E%u8005%u7528%u591A%u91CD%u7EE7%u627F%u6765%u7EC4%u7EC7%u9002%u914D%u5668%uFF0C%u539F%u7406%u662F%u4E00%u6837%u7684%u3002%u5176%u5B9E%u7EE7%u627F%u5C31%u662F%u4E00%u79CD%u7EC4%u5408%u3002%0A%u8FD9%u91CC%u5176%u5B9E%u8FD8%u770B%u4E0D%u51FAADAPTER%u7684%u5999%u7528%uFF0C%u6211%u7684%u7406%u89E3%u662FADAPTER%u5728%u4E24%u8FB9%u63A5%u4E0D%u62E2%u7684%u65F6%u5019%u6D3E%u4E0A%u7528%u573A%u7684%u3002%u4F5C%u8005%u7ED9%u7684%u4F8B%u5B50%u662F%u5173%u4E8E%u89E3%u8C03%u5668%u7684%u3002%u5176%u5B9E%u6211%u4EEC%u5728%u5B9E%u9645%u5F00%u53D1%u4E2D%u7ECF%u5E38%u9047%u5230%u7C7B%u4F3C%u7684%u95EE%u9898%u3002ADAPTER%u6A21%u5F0F%u5F88%u6709%u542F%u53D1%u3002%u4E0B%u9762%u6211%u7B80%u5355%u7F57%u5217%u4F5C%u8005%u7684%u4F8B%u5B50%uFF1A%0A%21%5BAlt%20text%7C450x0%5D%28./1479029463531.png%29%0A%u8FD9%u662FModem%u7684%u7ECF%u5178%u4F7F%u7528%u573A%u666F%uFF0C%u6709%u4E0D%u540C%u7684Modem%uFF0C%u4ED6%u4EEC%u9075%u5FAA%u540C%u4E00%u4E2A%u63A5%u53E3%u3002%u4E0A%u5C42%u6309%u7167%u63A5%u53E3%u4F7F%u7528%u8FD9%u4E9BModem%u3002%0A%21%5BAlt%20text%7C500x0%5D%28./1479029552237.png%29%0A%u6709%u4E00%u5929%u8981%u52A0%u5165%u4E00%u79CD%u65B0%u7684Modem%uFF0C%u73B0%u6709%u63A5%u53E3%u53EA%u6709%u4E00%u90E8%u5206%u5BF9%u4E4B%u6709%u610F%u4E49%u3002%u4E0A%u56FE%u662F%u7406%u60F3%u89E3%u51B3%u65B9%u6848%uFF0C%u628A%u539F%u5148%u7684%u63A5%u53E3%u5206%u6210%u4E24%u90E8%u5206%uFF0C%u4F46%u662F%u8FD9%u4E0D%u53EF%u80FD%uFF0C%u56E0%u4E3A%u5F88%u591Acode%u5DF2%u7ECF%u4F9D%u8D56%u4E8E%u8FD9%u4E2A%u63A5%u53E3%u4E86%u3002%0A%21%5BAlt%20text%7C500x0%5D%28./1479029706216.png%29%0A%u89E3%u51B3%u529E%u6CD5%u4E4B%u4E00%uFF0C%u5728%u65B0%u7EE7%u627F%u51FA%u7684%u7C7B%u4E2D%uFF0C%u5BF9%u4E0D%u9700%u8981%u7684%u63A5%u53E3%u505A%u5047%u7684%u5C01%u88C5%u3002%u8FD9%u6837%u662F%u53EF%u884C%u7684%uFF0C%u4F46%u4E5F%u9690%u85CF%u4E86%u98CE%u9669%u3002%u5982%u679C%u6709%u4E00%u5929Modem%u63A5%u53E3%u4E2D%uFF0C%u65B0%u7C7B%u7528%u4E0D%u5230%u7684%u63A5%u53E3%u53D1%u751F%u53D8%u5316%uFF0C%u90A3%u8FD9%u4E2A%u65B0%u7684%u7C7B%u4E5F%u8981%u8DDF%u7740%u53D8%u5316%uFF0C%u8FD9%u662F%u4E0D%u5408%u7406%u7684%uFF0C%u4E5F%u4EE4%u4EBA%u5F88%u6CAE%u4E27%u3002%0A%21%5BAlt%20text%7C500x0%5D%28./1479039815430.png%29%0A%u7528ADAPTER%u6765%u89E3%u51B3%u8FD9%u4E2A%u95EE%u9898%u3002%u6240%u6709%u548C%u539F%u5148%u63A5%u53E3%u517C%u5BB9%u7684%u95EE%u9898%uFF0C%u7531ADAPTER%u6765%u641E%u5B9A%u3002%u65B0%u7684Modem%u7C7Bfocus%u5728%u81EA%u5DF1%u9700%u8981%u7684%u529F%u80FD%u4E0A%u3002ADAPTER%u662F%u4E00%u4E2A%u5F88%u597D%u7684%u9694%u79BB%u7CFB%u7EDF%uFF0C%u89E3%u51B3%u77DB%u76FE%u7684%u5E2E%u624B%u3002%0A%0A%23%23%23%23BRIDGE%0ABridge%u6A21%u5F0F%u5728%u8FD9%u672C%u4E66%u4E0A%u7684%u5185%u5BB9%u6CA1%u770B%u61C2%uFF0C%u53BB%u53C2%u8003%u8BBE%u8BA1%u6A21%u5F0F%u5723%u7ECF%u2014%u2014%5B%u300A%u8BBE%u8BA1%u6A21%u5F0F%u300B%5D%28https%3A//www.amazon.cn/%25E8%25AE%25A1%25E7%25AE%2597%25E6%259C%25BA%25E7%25A7%2591%25E5%25AD%25A6%25E4%25B8%259B%25E4%25B9%25A6-%25E8%25AE%25BE%25E8%25AE%25A1%25E6%25A8%25A1%25E5%25BC%258F-%25E5%258F%25AF%25E5%25A4%258D%25E7%2594%25A8%25E9%259D%25A2%25E5%2590%2591%25E5%25AF%25B9%25E8%25B1%25A1%25E8%25BD%25AF%25E4%25BB%25B6%25E7%259A%2584%25E5%259F%25BA%25E7%25A1%2580-Erich-Gamma/dp/B001130JN8%29%u3002%u4E0D%u6127%u4E3A%u7ECF%u5178%u4E66%uFF0C%u8BB2%u89E3%u7684%u5F88%u6E05%u695A%u900F%u5F7B%u3002%0A%u4E66%u4E2D%u7ED9%u7684%u4F8B%u5B50%u662FWindow%20System%uFF0C%u770B%u4E0B%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1480073561975.png%29%0A%u7A97%u53E3%u7CFB%u7EDF%u5728%u4E0D%u540C%u7684%u5E73%u53F0%u4E0A%u6709%u5BF9%u5E94%u7684%u5B50%u7C7B%u3002%u5F53%u6211%u4EEC%u8981%u6D3E%u751FWindow%u7C7B%u751F%u6210%u65B0%u7684%u7A97%u53E3%u7C7B%u7684%u65F6%u5019%uFF0C%u5C31%u8981%u9762%u4E34%u9488%u5BF9%u4E0D%u540C%u5E73%u53F0%u6D3E%u751F%u65B0%u7684%u7C7B%u3002%u8FD9%u6837%u5982%u679C%u6709%u5F88%u591A%u7EE7%u627F%u5C42%u6B21%u7684%u8BDD%uFF0C%u7C7B%u5F88%u5FEB%u5C31%u53D8%u7684%u6CA1%u6CD5%u7BA1%u7406%u4E86%u3002%0A%u8FD9%u91CC%u7684%u95EE%u9898%u662F%uFF0C%u6709%u4E24%u4E2A%u7EE7%u627F%u5C42%u6B21%uFF1A%0A1.%20Window%u7CFB%u7EDF%u81EA%u8EAB%u7684%u6F14%u5316%0A2.%20%u5404%u4E2A%u5E73%u53F0%u5BF9Window%u7CFB%u7EDF%u7684%u5B9E%u73B0%0A%u5982%u679C%u4ED6%u4EEC%u90FD%u4F9D%u8D56%u4E8E%u540C%u4E00%u4E2A%u7EE7%u627F%u5173%u7CFB%uFF0C%u90A3%u5C31%u4F1A%u51FA%u73B0%u7C7B%u7EE7%u627F%u5931%u63A7%u7684%u73B0%u8C61%u3002Bridge%u6A21%u5F0F%u7684%u51FA%u73B0%u5C31%u662F%u4E3A%u4E86%u89E3%u51B3%u8FD9%u4E2A%u95EE%u9898%u3002%0A%21%5BAlt%20text%5D%28./1480075355062.png%29%0A%0A%u8FD9%u5C31%u662F%u4E00%u4E2A%u7ECF%u5178%u7684Bridge%u6A21%u5F0F%u3002%u62BD%u8C61%u7684Window%u7C7B%u548C%u5404%u5E73%u53F0%u7684%u5B9E%u73B0%u90E8%u5206%u5728%u5404%u81EA%u7684%u7C7B%u5C42%u6B21%u7ED3%u6784%u4E2D%u5206%u522B%u6F14%u5316%u3002Window%u4E0EWindowImp%u4E4B%u95F4%u7684%u5173%u7CFB%u79F0%u4E3A%u6865%u63A5%u3002%u4EE3%u7801%u793A%u4F8B%u5982%u4E0B%uFF1A%0A%60%60%60%0Aclass%20Window%20%0A%7B%0Apublic%3A%0A%09virtual%20void%20DrawLine%28const%20Point%26%2C%20const%20Point%26%29%20%3D%200%3B%0A%0Aprotected%3A%0A%09WindowImp*%20GetWindowImp%28%29%3B%20//**********%0A%0Aprivate%3A%0A%09WindowImp*%20_imp%3B%0A%09View*%20_contents%3B%0A%7D%0Aclass%20WindowImp%0A%7B%0Apublic%3A%0A%09virtual%20void%20DrawLineImp%28const%20Point%26%2C%20const%20Point%26%29%20%3D%200%3B%0A%7D%0Aclass%20IconWindow%20%3A%20public%20Window%0A%7B%0Apublic%3A%0A%09virtual%20void%20DrawLine%28const%20Point%26%20a%2C%20const%20Point%26%20b%29%0A%09%7B%0A%09%09WindowImp*%20imp%20%3D%20GetWindowImp%28%29%3B%0A%09%09imp-%3EDrawLineImp%28a%2C%20b%29%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%u8FD9%u91CC%u5F88%u6709%u610F%u601D%u7684%u662FWindow%u7C7B%u7684%u6D3E%u751F%u7C7B%uFF0C%u901A%u8FC7Window%u7684protected%u63A5%u53E3%u6765%u8BBF%u95EE%u5230%u5BF9%u5E94%u7684Imp%u63A5%u53E3%u3002%u800CGetWindowImp%u53EF%u80FD%u5229%u7528%u4E00%u4E2A%u62BD%u8C61%u5DE5%u5382%uFF0C%u6765%u751F%u6210%u9700%u8981%u7684%u5BF9%u8C61%u3002GetWindowImp%u53EF%u4EE5%u5728%u8FD9%u4E2A%u5DE5%u5382%u4E2D%u68C0%u6D4B%u5F53%u524D%u7684%u5E73%u53F0%u6765%u5B9E%u4F8B%u5316%u5BF9%u5E94%u7684WindowImp%u7C7B%u3002%0A%0A%23%23%23%23Bridge%u6A21%u5F0F%u4E00%u4E9B%u503C%u5F97%u6CE8%u610F%u7684%u5730%u65B9%0A1.%20%u4EC5%u6709%u4E00%u4E2AImplementor%u7684%u65F6%u5019%uFF0C%u6CA1%u6709%u5FC5%u8981%u521B%u5EFA%u4E00%u4E2A%u62BD%u8C61%u7684Implementor%u7C7B%0A2.%20%u5B9E%u4F8B%u5316Imp%u7C7B%u7684%u65B9%u6CD5%u6709%uFF1A%0A%09-%20%u5982%u679C%u6839%u62BD%u8C61%u7C7B%u77E5%u9053%u6240%u6709%u7684Implementor%u5B9E%u73B0%u7C7B%uFF0C%u5219%u53EF%u5728%u5176%u6784%u9020%u51FD%u6570%u4E2D%u6839%u636E%u9700%u8981%u6765%u5B9E%u4F8B%u5316%u4E00%u4E2AImplementor%u7C7B%0A%09-%20%u9996%u5148%u9009%u62E9%u4E00%u4E2A%u9ED8%u8BA4%u7684%u5B9E%u73B0%uFF0C%u7136%u540E%u6839%u636E%u9700%u8981%u6539%u53D8%u8FD9%u4E2A%u5B9E%u73B0%0A%09-%20%u91C7%u7528%u5DE5%u5382%u6A21%u5F0F%u6765%u751F%u4EA7%u5BF9%u5E94%u7684Imp%u7C7B%u5BF9%u8C61%0A3.%20%u5728C++%u4E2D%uFF0C%u53EF%u4EE5%u4F7F%u7528%u591A%u91CD%u7EE7%u627F%u7ED3%u5408%u4E24%u4E2A%u62BD%u8C61%u5C42%u6B21%u3002%u4F46%u662F%u8FD9%u79CD%u529E%u6CD5%u4F9D%u8D56%u4E8E%u9759%u6001%u7EE7%u627F%u3002%u56E0%u6B64%u4E0D%u53EF%u80FD%u7528%u591A%u91CD%u7EE7%u627F%u7684%u65B9%u6CD5%u6765%u5B9E%u73B0%u771F%u6B63%u7684Bridge%u6A21%u5F0F%u3002%u4EE5Window%u7CFB%u7EDF%u4E3A%u4F8B%uFF0C%u5982%u679C%u4E00%u4E2A%u7A97%u53E3%u7C7B%u7EE7%u627FWindow%u548CWindowImp%u62BD%u8C61%u7C7B%uFF0C%u4F46%u662F%u4ED6%u5E76%u6CA1%u6709%u83B7%u5F97XWindow%u7684%u5B9E%u73B0%u3002%0A%0A%23%23%23%23%u654F%u6377%u8F6F%u4EF6%u5F00%u53D1%u4E2D%u7684Bridge%u6A21%u5F0F%0A%u518D%u56DE%u5230%u300A%u654F%u6377%u8F6F%u4EF6%u5F00%u53D1%u300B%u8FD9%u672C%u4E66%uFF0C%u770B%u4E0B%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1480115182591.png%29%0A%u56E0%u4E3A%u65B0%u7684Dedicated%20Modem%uFF08%u5373%u53EA%u6709%u6570%u636E%u4F20%u8F93%u529F%u80FD%u7684Modem%uFF09%u7684%u5F15%u5165%uFF0CModem%u7684%u7C7B%u7ED3%u6784%u4E2D%u5C31%u5F15%u5165%u4E86%u4E00%u4E2A%u65B0%u7684%u5C42%u6B21%u7ED3%u6784%u3002%u56E0%u4E3A%u539F%u6709%u7684%u62BD%u8C61%u7ED3%u6784%u603B%u6709%u4E00%u4E9B%u4E0D%u5C3D%u4EBA%u610F%u7684%u5730%u65B9%u3002%u6BD4%u5982%uFF0C%u5728%u539F%u5148%u7684%u8BBE%u8BA1%u4E2D%uFF0C%u53EF%u80FD%u6709%u5728Send%u4E4B%u524D%u8981%u5148Dial%u7684%u7EA6%u675F%uFF0C%u90A3%u4E48%u5728%u65B0%u7684Modem%u7C7B%u4E2D%uFF0C%u5C31%u4E0D%u9002%u5408%u4E86%u3002%u5982%u679C%u60F3%u4E0D%u56E0%u4E3A%u5F15%u5165%u65B0%u7684Modem%u7C7B%u578B%u800C%u9700%u8981%u4FEE%u6539%u4E0A%u5C42%u5E94%u7528%u7A0B%u5E8F%u7684%u8BDD%uFF0C%u5C31%u8981%u7528%u5230Bridge%u6A21%u5F0F%u3002%0A-%20ModemConnectionController%u5B9A%u4E49%u4E86%u4E24%u4E2A%u63A5%u53E3%uFF1A%u539F%u6709%u7684Modem%u548C%u65B0%u7684DedicatedModem%u3002%0A-%20ModemConnectionController%u4E2D%u6240%u6709%u7684Imp%u63A5%u53E3%u5747%u4E3AProtected%uFF0C%u53EA%u80FD%u88AB%u5176%u5B50%u7C7B%u4F7F%u7528%u3002%0A-%20ModemConnectionController%u5728%u9002%u5F53%u7684%u65F6%u673A%uFF0C%u5B9E%u4F8B%u5316%u5BF9%u5E94Modem%u7684%u786C%u4EF6%u5B9E%u73B0%uFF0C%u5E76%u5C06%u6240%u6709%u7684Imp%u63A5%u53E3%u59D4%u6258%u7ED9%u8FD9%u4E2A%u5B9E%u4F8B%u3002%0A%0A%u7528%u4EE3%u7801%u6765%u9610%u8FF0%u53EF%u80FD%u66F4%u76F4%u89C2%uFF1A%0A%60%60%60%0Apublic%20interface%20Modem%20%7B%0A%09public%20void%20Dial%28%29%3B%0A%7D%0Apublic%20interface%20DedicatedModem%20%7B%0A%09public%20void%20Send%28%29%3B%0A%7D%0Apublic%20abstract%20class%20ModemConnectionController%20implements%20Modem%2C%20DedicatedModem%7B%0A%20%20%20%20private%20ModemImplementation%20_imp%3B%0A%09protected%20ModemImplementation%20GetImp%28int%20token%29%7B%0A%09%09switch%20%28token%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20case%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20Object%28%29%3B%0A%09%20%20%20%20%7D%0A%20%20%20%20%7D%0A%09%0A%09protected%20void%20DialImpl%28%29%7B%0A%20%20%20%20%20%20%20%20return%20GetImp%28mToken%29.Dial%28%29%3B%20//%20delegate%0A%09%7D%0A%0A%20%20%20%20protected%20void%20SendImpl%28%29%7B%0A%20%20%20%20%20%20%20%20return%20GetImp%28mToken%29.Send%28%29%3B%20//%20delegate%0A%09%7D%0A%0A%20%20%20%20public%20void%20Dial%28%29%20%7B%7D%0A%20%20%20%20public%20void%20Send%28%29%20%7B%7D%0A%7D%0Apublic%20class%20DedModemController%20extends%20ModemConnectionController%20%7B%0A%20%20%20%20public%20void%20Dial%28%29%7B%20/*%20own%20version%20of%20Dial%20*/%20%7D%0A%20%20%20%20public%20void%20Send%28%29%7B%20return%20DialImpl%28%29%3B%20%7D%0A%7D%0Apublic%20class%20DedUser%20%7B%0A%20%20%20%20void%20main%28%29%7B%0A%20%20%20%20%20%20%20%20DedicatedModem%20dedModem%20%3D%20%28DedicatedModem%29new%20DedModemController%3B%0A%20%20%20%20%20%20%20%20dedModem.Dial%28%29%3B%0A%20%20%20%20%20%20%20%20dedModem.Send%28%29%3B%0A%20%20%20%20%7D%0A%7D%0Apublic%20class%20OldUser%20%7B%0A%20%20%20%20void%20main%28%29%7B%0A%20%20%20%20%20%20%20%20Modem%20modem%20%3D%20%28Modem%29new%20HayesModem%3B%0A%20%20%20%20%20%20%20%20modem.Dial%28%29%3B%0A%20%20%20%20%20%20%20%20modem.Send%28%29%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%u56E0%u4E3A*Impl%u51FD%u6570%u7684%u5B58%u5728%uFF0CDedModem%u53EF%u4EE5%u6F14%u53D8%u6210%u72EC%u7ACB%u7684%u7C7B%u6F14%u5316%u5E8F%u5217%u3002%0A%0A%23%23%23PROXY%0A%u4E0B%u56FE%u662F%u4E00%u4E2A%u5178%u578B%u7684PROXY%u6A21%u5F0F%uFF1A%0A%21%5BAlt%20text%7C450x0%5D%28./1480238359796.png%29%0A%3E%u6BCF%u4E2A%u8981%u88AB%u4EE3%u7406%u7684%u5BF9%u8C61%u90FD%u88AB%u5206%u62103%u4E2A%u90E8%u5206%uFF1A%0A%3E1.%20%u4E00%u4E2A%u63A5%u53E3%uFF0C%u58F0%u660E%u4E86%u5BA2%u6237%u8981%u8C03%u7528%u7684%u6240%u6709%u65B9%u6CD5%0A%3E2.%20%u4E00%u4E2A%20%u7C7B%u5728%u4E0D%u6D89%u53CA%u6570%u636E%u5E93%u903B%u8F91%u7684%u60C5%u51B5%u4E0B%u5B9E%u73B0%u4E86%u63A5%u53E3%u4E2D%u7684%u65B9%u6CD5%0A%3E3.%20%u4E00%u4E2A%u77E5%u6653%u6570%u636E%u5E93%u7684%u4EE3%u7406%0A%0A%21%5BAlt%20text%7C500x0%5D%28./1480238530929.png%29%0A%u8FD9%u4E24%u5E45%u56FE%u5176%u5B9E%u5DF2%u7ECF%u5F88%u597D%u7684%u9610%u660E%u4E86PROXY%u6A21%u5F0F%u3002%u4F5C%u8005%u4E5F%u6307%u51FA%uFF0CPROXY%u5176%u5B9E%u662F%u4E00%u4E2A%u5F88%u91CD%u7684%u6A21%u5F0F%uFF0C%u5728%u5B9E%u73B0%u7684%u65F6%u5019%uFF0C%u56E0%u4E3A%u5404%u79CD%u539F%u56E0%uFF08%u662F%u5426%u9700%u8981%u7F13%u5B58%uFF0C%u662F%u5426%u9700%u8981%u8C03%u7528Imp%u5B9E%u73B0%u7B49%u7B49%uFF09%uFF0C%u5E76%u4E0D%u4F1A%u4E25%u683C%u9075%u5B88%u89C4%u8303%u7684%u6A21%u5F0F%u3002%0A%3E%u8FD9%u4E2A%u4F8B%u5B50%u5E94%u8BE5%u5DF1%u7ECF%u6D88%u9664%u4E86%u6240%u6709%u5173%u4E8E%u4F7F%u7528%u4EE3%u7406%u662F%u7B80%u5355%u548C%u4F18%u96C5%u7684%u9519%u8BEF%u8BA4%u8BC6%u3002%u4F7F%u7528%u4EE3%u7406%u662F%u6709%u4EE3%u4EF7%u7684%u3002%u89C4%u8303%u6A21%u5F0F%u4E2D%u6240%u9690%u542B%u7684%u7B80%u5355%u59D4%u6258%u6A21%u578B%u5F88%u5C11%u80FD%u591F%u88AB%u4F18%u7F8E%u5730%u5B9E%u73B0%u3002%u76F8%u53CD%uFF0C%u6211%u4EEC%u7ECF%u5E38%u4F1A%u53D6%u6D88%u5BF9%u4E8E%u7E41%u7410%u7684%u83B7%u53D6%u548C%u8BBE%u7F6E%u65B9%u6CD5%u7684%u59D4%u6258%u3002%0A%0A%u5173%u4E8E%u7F13%u5B58%0A%3E%u4F60%u53EF%u80FD%u4F1A%u8BA4%u4E3AProductProxy%u7684%u5B9E%u73B0%u662F%u975E%u5E38%u4F4E%u6548%u7684%u3002%u5728%u6BCF%u4E2A%u8BBF%u95EE%u65B9%u6CD5%u4E2D%uFF0C%u5B83%u90FD%u4F1A%u53BB%u4F7F%u7528%u6570%u636E%u5E93%u3002%u5982%u679C%u5B83%u628AProductData%u6761%u76EE%u8FDB%u884C%u7F13%u5B58%u6765%u907F%u514D%u8BBF%u95EE%u6570%u636E%u5E93%u4E0D%u662F%u4F1A%u66F4%u597D%u4E00%u4E9B%u5417%uFF1F%0A%3E%u867D%u7136%u8FD9%u4E2A%u66F4%u6539%u975E%u5E38%u7B80%u5355%uFF0C%u4F46%u662F%u4FC3%u4F7F%u6211%u4EEC%u8FD9%u6837%u505A%u7684%u60DF%u4E00%u539F%u56E0%u5C31%u662F%u6211%u4EEC%u7684**%u6050%u60E7**%u3002%u6B64%u65F6%20%uFF0C%u8FD8%u6CA1%u6709%u6570%u636E%u663E%u793A%u51FA%u8FD9%u4E2A%u7A0B%u5E8F%u5177%u6709%u6027%u80FD%u95EE%u9898%u3002%u6B64%20%u5916%uFF0C%u6570%u636E%u5E93%u5F15%u64CE%u672C%u8EAB%u4E5F%u4F1A%u505A%u4E00%u4E9B%u7F13%u5B58%u5904%u7406%uFF0C%u6240%u4EE5%u5EFA%u7ACB%u81EA%u5DF1%u7684%u7F13%u5B58%u4F1A%u7ED9%u6211%u4EEC%u5E26%u6765%u4EC0%u4E48%u597D%u5904%u5E76%u4E0D%u660E%u663E%u3002%u5728%u505A%u8FD9%u4E9B%u9EBB%u70E6%u7684%u5DE5%u4F5C%u524D%uFF0C%u6211%u4EEC%u5E94%u8BE5%u7B49%u5F85%uFF0C%u76F4%u5230%u6211%u4EEC%u770B%u5230%u6027%u80FD%u95EE%u9898%u7684%u8FF9%u8C61%u3002%0A%3E%u5982%u679C%u4F60%u62C5%u5FC3%u6027%u80FD%u53EF%u80FD%u662F%u4E2A%u95EE%u9898%uFF0C%u6211%u5EFA%u8BAE%u4F60%u505A%u4E00%u4E9B%u8BD5%u9A8C%u53BB%u8BC1%u660E%u5B83%u786E%u5B9E%u662F%u4E00%u4E2A%u95EE%u9898%u3002**%u5F53%u4E14%u4EC5%u5F53%u5F97%u5230%u8BC1%u5B9E%u65F6**%uFF0C%u4F60%u624D%u5E94%u8BE5%u8003%u8651%u5982%u4F55%u53BB%u63D0%u901F%u3002%0A%0A%23%23%23STAIRWAY%20TO%20HEAVEN%0ASTAIRWAY%20TO%20HEAVEN%u4F7F%u7528%u4E86%u7C7B%u5F62%u5F0F%uFF08class%20form%20%29%u7684%5BADAPTER%5D%28%23adapter%29%u6A21%u5F0F%u7684%u4E00%u4E2A%u53D8%u4F53.%0A%21%5BAlt%20text%7C300x0%5D%28./1480341485379.png%29%0A%u4F20%u8BF4%u4E2D%u7684%u6B7B%u4EA1%u83F1%u5F62%u3002%u5728%u63D0%u5230%u8FD9%u4E2A%u83F1%u5F62%u7684%u65F6%u5019%uFF0C%u6D89%u53CA%u5230%u4E00%u4E2A%u865A%u62DF%u7EE7%u627F%u7684%u6982%u5FF5%uFF0C%u53EF%u4EE5%u53C2%u8003%u8FD9%u7BC7%u6587%u7AE0%uFF1A%5B%u5173%u4E8EC++%u4E2D%u7684%u865A%u62DF%u7EE7%u627F%u7684%u4E00%u4E9B%u603B%u7ED3%5D%28http%3A//www.cnblogs.com/BeyondAnyTime/archive/2012/06/05/2537451.html%29%u3002%0A-%20%u6838%u5FC3%u90E8%u5206%u5C31%u662F%u4E0A%u534A%u90E8%u5206%u7684Product%uFF0CPersistentObject%u548CPersistentProduct%uFF0C%u4E0B%u9762Assembly%u76F8%u5173%u7684%u90E8%u5206%u662F%u5BF9Product%u90E8%u5206%u7684%u6269%u5C55%0A-%20PersistentProduct%u901A%u8FC7Product%u5F97%u5230%u4EA7%u54C1%u903B%u8F91%uFF0C%u901A%u8FC7PersistentObject%u83B7%u5F97%u969C%u788D%uFF08%u6570%u636E%u5E93%uFF0C%u7F51%u7EDC%u7B49%u7B49%uFF09%u64CD%u4F5C%u903B%u8F91%u3002%0A%u5BF9%u6BD4%u770BPROXY%u7684%u9759%u6001%u6A21%u578B%0A%21%5BAlt%20text%7C450x0%5D%28./1480238359796.png%29%0A%u5176%u5B9E%u4E24%u8005%u7684%u6838%u5FC3%u662F%u4E00%u6837%u7684%u3002%u4E0D%u540C%u7684%u662F%uFF0CSTAIRWAY%20TO%20HEAVEN%u7528%u7684%u662F%u7EE7%u627F%uFF0C%u903B%u8F91%u66F4%u52A0%u6E05%u6670%uFF0C%u66F4%u7B26%u5408OO%u89C2%u5FF5%uFF0CPROXY%u4F7F%u7528%u7684%u662F%u59D4%u6258%28%u7EC4%u5408%29%uFF0C%u5728%u5B9E%u73B0%u7684%u65F6%u5019%u5F80%u5F80%u4E0D%u591F%u7B80%u5355%u3002%0A%u4F5C%u8005%u4E5F%u66F4%u63A8%u8350%u7528STAIRWAY%20TO%20HEAVEN%u6765%u9694%u79BB%u4E1A%u52A1%u89C4%u5219%u548C%u969C%u788D%u903B%u8F91%u3002%u4ED6%u552F%u4E00%u7684%u7F3A%u70B9%u5C31%u662F%u9700%u8981%u8BED%u8A00%u652F%u6301%u591A%u91CD%u7EE7%u627F%u3002%0A%0A%23%23%23%u7BA1%u7406%u7B2C%u4E09%u65B9API%0A%u5728%u6211%u4EEC%u521A%u5F00%u59CB%u4F7F%u7528%u7B2C%u4E09%u65B9API%u7684%u65F6%u5019%uFF0C%u5F80%u5F80%u662F%u8FD9%u6837%u7684%uFF1A%0A%21%5BAlt%20text%7C300x0%5D%28./1480342229279.png%29%0A%u7136%u540E%u6211%u4EEC%u60F3%u51FA%u4E00%u4E2A%u9694%u79BB%u5C42%uFF0C%u662F%u8FD9%u6837%u7684%uFF1A%0A%21%5BAlt%20text%7C350x0%5D%28./1480342297651.png%29%0A%u8FD9%u65F6%u5019%u53D1%u73B0%u662F%u6709%u4F20%u9012%u4F9D%u8D56%u5173%u7CFB%u3002%u5982%u679CAPI%u4E00%u53D1%u751F%u53D8%u52A8%uFF08%u4F8B%u5982%uFF1A%u4F20%u5165%u53C2%u6570%u53D8%u4E86%uFF09%uFF0C%u5219Application%u4EE3%u7801%u4E5F%u8981%u8DDF%u7740%u6539%u3002%u6700%u597D%u80FD%u6709%u4E0B%u9762%u8FD9%u6837%u7684%u4F9D%u8D56%u5173%u7CFB%u5012%u7F6E%uFF1A%0A%21%5BAlt%20text%7C400x0%5D%28./1480342394296.png%29%0APROXY%u548CSTAIRWAY%20TO%20HEAVEN%u5C31%u662F%u89E3%u51B3%u8FD9%u4E2A%u95EE%u9898%u7684%3A%0A%21%5BAlt%20text%7C380x0%5D%28./1480342442529.png%29%0A%21%5BAlt%20text%5D%28./177cde61%20f80d%204a54%20ae25%209fc575e6f156.jpg%20%201200%D71080%20.png%29%0A%0A%u4F5C%u8005%u5728%u672C%u7AE0%u6700%u540E%u8FD8%u63D0%u5230%u4E86%u51E0%u4E2A%u64CD%u4F5C%u7B2C%u4E09%u65B9API%u7684%u6A21%u5F0F%uFF1A%0A-%20Extension%20Object%0A-%20VISITOR%0A-%20Decorator%0A-%20%5BFacade%5D%28%23facade%29%0A%0A%u4F5C%u8005%u6700%u540E%u7684%u7ED3%u8BBA%u5F88%u6709%u6307%u5BFC%u610F%u4E49%uFF1A%0A%3E%u8FDC%u5728%u771F%u6B63%u9700%u8981PROXY%u6A21%u5F0F%u6216%u8005STAIRWAY%20TO%20HEAVEN%u6A21%u5F0F%u524D%uFF0C%u5C31%u53BB%u9884%u6D4B%u5BF9%u4E8E%u5B83%u4EEC%u7684%u9700%u8981%u662F%u975E%u5E38%u6709%u8BF1%u60D1%u529B%u7684%u3002%u4F46%u8FD9%u51E0%u4E4E%u4ECE%u6765%u90FD%u4E0D%u662F%u4E00%u4E2A%u597D%u4E3B%u610F%uFF0C%u7279%u522B%u662F%u5BF9%u4E8EPROXY%u6A21%20%u5F0F%u3002%u6211%u5EFA%u8BAE%u5728%u5F00%u59CB%u65F6%u5148%u4F7F%u7528FACADE%u6A21%u5F0F%uFF0C%u7136%u540E%u5728%u5FC5%u8981%u65F6%u8FDB%u884C%u91CD%u6784%u3002%u5982%u679C%u8FD9%u6837%u505A%u7684%u8BDD%uFF0C%u5C31%u4F1A%u4E3A%u81EA%u5DF1%u8282%u7701%u65F6%u95F4%u5E76%u7701%u53BB%u9EBB%u70E6%u3002%0A%0A%u6211%u5728%u505A%u5FAE%u4FE1IoT%u6253%u5370%u5B89%u5353%u7AEF%u5F00%u53D1%u7684%u65F6%u5019%uFF0C%u4E5F%u662F%u8C28%u9075%u4F5C%u8005%u7684%u6559%u8BF2%u3002FACADE%u6A21%u5F0F%u524D%u9762%u6709%u4E13%u95E8%u7684%u7AE0%u8282%u4ECB%u7ECD%u3002%u8FD9%u91CC%u518D%u653E%u4E00%u4E2A%u672C%u7AE0%u7684%u5173%u4E8EFACADE%u7684%u622A%u56FE%u3002%0A%21%5BAlt%20text%7C380x0%5D%28./1480343121833.png%29%0A%u518D%u653E%u4E00%u4E2A%u4E4B%u524D%u7684%u622A%u56FE%u4F5C%u4E3A%u6BD4%u8F83%uFF1A%0A%21%5BAlt%20text%7C450x0%5D%28./1478213659914.png%29%0A%u6240%u8C13%u7684FACADE%u4E5F%u5C31%u662F%u56FE26.6%uFF0C%u6709%u4F20%u9012%u4F9D%u8D56%u7684Layer%u5C42%uFF0C%u5F53%u6211%u4EEC%u53D1%u73B0%u4F20%u9012%u4F9D%u8D56%u5E26%u6765%u95EE%u9898%u7684%u65F6%u5019%uFF0C%u6211%u4EEC%u53EF%u4EE5%u9009%u62E9%u5C06FACADE%u91CD%u6784%u4E3APROXY%u6216%u8005STAIRWAY%20TO%20HEAVEN%u3002%0A%0A%23%2328-30%u7AE0%0A%23%23%23VISITOR%0AVISITOR%u6A21%u5F0F%u662F%u4E00%u4E2A%u5F88%u597D%u7684%u6A21%u5F0F%uFF0C%u4ED6%u53EF%u4EE5%u7ED9%u73B0%u6709%u7684%u6846%u67B6%u6253%u8865%u4E01%u3002%u4F5C%u8005%u7ED9%u7684%u4F8B%u5B50%u662F%u5173%u4E8EModem%u7684%0A%21%5BAlt%20text%7C400x0%5D%28./1482786464781.png%29%0A%u5F53%u6211%u4EEC%u53D1%u73B0Modem%u7684%u884C%u4E3A%u5728Unix%u5E95%u4E0B%u9700%u8981%u4E00%u4E9B%u7279%u522B%u7684%u4EE3%u7801%uFF0C%u4E8E%u662F%u5F80%u63A5%u53E3%u91CC%u5934%u6DFB%u52A0configureForUnix%uFF0C%u7136%u540E%u4FEE%u6539%u4E86%u5404%u4E2A%u6D3E%u751F%u7C7B%u3002%u63A5%u4E0B%u6765%uFF0C%u5982%u679C%u8981%u4E3AWindows%u6DFB%u52A0%u600E%u4E48%u529E%uFF1F%u5982%u679C%u6CA1%u6709VISITOR%uFF0C%u53EA%u80FD%u518D%u4FEE%u6539%u63A5%u53E3%u548C%u5B9A%u4E49%u4E86%u8BE5%u63A5%u53E3%u7684%u7C7B%u3002%u8FD9%u662F%u5F88%u7E41%u7410%u7684%u4E8B%u60C5%0A%u4E0B%u9762%u770BVISITOR%u6A21%u5F0F%u7684%u89E3%u51B3%u65B9%u6CD5%uFF1A%0A%21%5BAlt%20text%7C550x0%5D%28./1482786625185.png%29%0A%u67E5%u770B%u5177%u4F53%u5B9E%u73B0%u4EE3%u7801%u540E%uFF0C%u624D%u771F%u6B63%u7406%u89E3%u4E86%u8FD9%u5E45%u56FE%u7684%u610F%u601D%uFF1A%0A1.%20%u4E00%u6B21%u6B21%u4FEE%u6539%u53D8%u6210%u4E00%u6B21%u6027%u64CD%u4F5C%u3002%u5728Modem%u7684%u63A5%u53E3%u4E2D%u6DFB%u52A0VISITOR%u63A5%u53E3%uFF0C%u5373%u4E0A%u56FE%u4E2D%u7684accept%u3002%0A2.%20%u5F53%u5BA2%u6237%u4EE3%u7801%u8981%u4E3AUnix%u914D%u7F6E%u7684%u65F6%u5019%uFF0C%u8C03%u7528%u5BF9%u5E94%u5B9E%u4F53Modem%u7C7B%u7684accept%u63A5%u53E3%uFF0C%u8BE5%u63A5%u53E3%u4F1A%u8C03%u7528Visitor-%3Evisit%uFF0C%u5E76%u4F20%u5165%u81EA%u8EAB%u4E0A%u4E0B%u6587%0A3.%20%20%u5728visit%u91CC%u9762%u5C31%u53EF%u4EE5%u8C03%u7528%u5404%u4E2AModem%u66B4%u9732%u51FA%u6765%u7684public%u65B9%u6CD5%u4E86%uFF0C%u6CE8%u610F%u4E0D%u662FModem%u63A5%u53E3%u54E6%uFF0C%u662F%u5177%u4F53%u7C7B%u7684public%u65B9%u6CD5%0A4.%20%20%u5982%u679C%u6211%u4EEC%u9700%u8981%u5176%u4ED6%u7684%u8BBF%u95EE%u4EE3%u7801%uFF0C%u6211%u4EEC%u53EF%u4EE5%u52A0%u4E00%u4E2A%u7C7B%uFF0C%u5E76%u5B9A%u4E49ModemVisitor%u63A5%u53E3%u5C31%u53EF%u4EE5%u4E86%u3002%u8FD9%u4E2A%u7C7B%u53EF%u4EE5%u505A%u4EFB%u610F%u60F3%u505A%u7684%u4E8B%u60C5%uFF0C%u4E0D%u5C40%u9650%u4E8EModemConfigurator%0A%0A%u8FD9%u91CC%u8FD8%u5B66%u5230%u4E00%u4E2Ajava%u7684%u5C0F%u77E5%u8BC6%uFF1A%0A%u6211%u4EEC%u77E5%u9053%u6709private%2C%20protected%2C%20public%uFF0C%u5982%u679C%u4E0D%u5199%u9ED8%u8BA4%u662F%u4EC0%u4E48%uFF1F%0A-%20C++%u91CC%u9ED8%u8BA4%u662Fprivate%0A-%20Java%u91CC%u4E0D%u5199%u7684%u8BDD%uFF0C%u8868%u793A%u5305%u7EA7%u8BBF%u95EE%u6743%u9650%uFF0C%u610F%u5373%u53EA%u6709%u540C%u4E00%u4E2A%u5305%u91CC%u7684%u4EE3%u7801%u53EF%u4EE5%u8C03%u7528%u3002%u5982%u679C%u8F6F%u4EF6%u53EA%u6709%u4E00%u4E2A%u5305%uFF0C%u5C31%u7B49%u540C%u4E8Epublic%u3002%u56E0%u4E3AJava%u4E2D%u6CA1%u6709friend%u5173%u952E%u5B57%uFF0C%u8FD9%u4E00%u529F%u80FD%u53EF%u4EE5%u8D77%u5230%u4E00%u90E8%u5206friend%u7684%u4F5C%u7528%u3002%u5176%u5B9E%u4E5F%u5C31%u662FJava%u7684%u4F5C%u8005%u8BA4%u4E3A%uFF0C%u5305%u5185%u7684%u7C7B%u90FD%u662F%u53CB%u5143%u3002%0A%0A%23%23%23ACYCLIC%20VISITOR%u6A21%u5F0F%0Aacyclic%20%u2014%u2014%20%u65E0%u73AF%u7684%uFF0C%u8FD9%u91CC%u6307%u6CA1%u6709%u4F9D%u8D56%u73AF%u3002%0A%0A%23%23%23%23%u4E3A%u4F55%u6709ACYCLIC%u53D8%u4F53%0A%u4F5C%u8005%u5728%u672C%u8282%u4E00%u5F00%u59CB%u7684%u65F6%u5019%u5C31%u4ECB%u7ECD%u4E86%u4E3A%u4EC0%u4E48%u8981%u5728VISITOR%u7684%u57FA%u7840%u4E0A%u5F15%u5165ACYCLIC%u53D8%u4F53%u3002%u4E0D%u8FC7%u6211%u60F3%u4E86%u597D%u4E45%uFF0C%u4E5F%u6CA1%u592A%u7406%u89E3%u3002%u6682%u4E14%u7F57%u5217%u5982%u4E0B%uFF1A%0A%3E%u8BF7%u6CE8%u610F%uFF0C**%u88AB%u8BBF%u95EE%20%28Modem%29%u5C42%u6B21%u7ED3%u6784%u7684%u57FA%u7C7B%u4F9D%u8D56%u4E8E%u8BBF%u95EE%u8005%u5C42%u6B21%u7ED3%u6784%uFF08ModemVisitor%uFF09%u7684%u57FA%u7C7B**%u3002%u540C%u6837%u8BF7%u6CE8%u610F%uFF0C%u8BBF%u95EE%u8005%u5C42%u6B21%u7ED3%u6784%u7684%u57FA%u7C7B%u4E2D%u5BF9%u4E8E%u88AB%u8BBF%u95EE%u5C42%u6B21%u7ED3%u6784%u4E2D%u7684%u6BCF%u4E2A%u6D3E%u751F%u7C7B%u90FD%u6709%u4E00%u4E2A%u5BF9%u5E94%u51FD%u6570%u3002%u56E0%u6B64%uFF0C%u5C31%u6709%u4E00%u4E2A**%u4F9D%u8D56%u73AF**%u628A%u6240%u6709%u88AB%u8BBF%u95EE%u7684%u6D3E%u751F%u7C7B%uFF08%u6240%u6709%u7684%u8C03%u5236%u89E3%u8C03%u5668%uFF09%u7ED1%u5B9A%u5728%u4E00%20%u8D77%u3002%u8FD9%u6837%uFF0C%u5C31%u5F88%u96BE%u5B9E%u73B0%u5BF9%u8BBF%u95EE%u8005%u7ED3%u6784%u7684%u589E%u91CF%u7F16%u8BD1%uFF0C%u5E76%u4E14%u4E5F%u5F88%u96BE%u5411%u88AB%u8BBF%u95EE%u5C42%u6B21%u7ED3%u6784%u4E2D%u589E%u52A0%u65B0%u7684%u6D3E%u751F%u7C7B%u3002%0A%3E%u5982%u679C%u7A0B%u5E8F%u4E2D%u8981%u66F4%u6539%u7684%u5C42%u6B21%u7ED3%u6784%u4E0D%u9700%u8981%u7ECF%u5E38%u5730%u589E%u52A0%u65B0%u7684%u6D3E%u751F%u7C7B%uFF0C%u90A3%u4E48VISITOR%u6A21%u5F0F%u5DE5%u4F5C%u7684%u5F88%u597D%u3002%u5982%u679C%u6211%u4EEC%u5F88%u53EF%u80FD%u53EA%u9700%u8981Hayes%u3001Zoom%u4EE5%u53CAErnie%uFF0C%u6216%u8005%u5F88%u5C11%u4F1A%u53BB%u589E%u52A0%u65B0%u7684Modem%u6D3E%u751F%u7C7B%2C%u90A3%u4E48VISITOR%u6A21%u5F0F%u5C06%u4F1A%u975E%u5E38%u5408%u9002%u3002%0A%3E%u53E6%u4E00%u65B9%u9762%uFF0C%u5982%u679C%u88AB%u8BBF%u95EE%u5C42%u6B21%u7ED3%u6784%u975E%u5E38%u4E0D%u7A33%u5B9A%uFF0C%u7ECF%u5E38%u9700%u8981%u521B%u5EFA%u8BB8%u591A%u65B0%u7684%u6D3E%u751F%u7C7B%uFF0C%u90A3%u4E48%u6BCF%u5F53%u5411%u88AB%u8BBF%u95EE%20%u5C42%u6B21%u7ED3%u6784%u4E2D%u589E%u52A0%u4E00%u4E2A%u65B0%u7684%u6D3E%u751F%u7C7B%u65F6%uFF0C%u5C31%u5FC5%u987B%u8981%u66F4%u6539%u5E76%u4E14%u91CD%u65B0%u7F16%u8BD1VISITOR%u57FA%u7C7B%uFF08%u4E5F%u5C31%u662FModemVisitor%uFF09%u4EE5%u53CA%u5B83%u7684%u6240%u6709%u6D3E%u751F%u7C7B%u3002%u5728C++%u4E2D%uFF0C%u60C5%u51B5%u751A%u81F3%u66F4%u7CDF%u3002%u6BCF%u5F53%u589E%u52A0%u4EFB%u4F55%u4E00%u4E2A%u65B0%u7684%u6D3E%u751F%u7C7B%u65F6%uFF0C%u6574%u4E2A%u88AB%u8BBF%u95EE%u5C42%u6B21%u7ED3%u6784%u5C31%u5FC5%u987B%u8981%u88AB%u91CD%u65B0%u7F16%u8BD1%u3001%u91CD%u65B0%u90E8%u7F72%u3002%0A%0A%u8C08%u4E00%u4E0B%u6211%u7684%u7406%u89E3%u3002%u8FD9%u53EF%u80FD%u548CJava%u7684%u7F16%u8BD1%u8FC7%u7A0B%u6709%u5173%u7CFB%u3002%u5148%u628AVISITOR%u4E2D%u7684%u7C7B%u56FE%u62F7%u8FC7%u6765%uFF1A%0A%21%5BAlt%20text%7C550x0%5D%28./1482786625185.png%29%0A%u9488%u5BF9%u4F9D%u8D56%u5173%u7CFB%uFF0C%u6211%u4E5F%u6536%u5F55%u8FC7%u4E00%u7BC7%u7B14%u8BB0%u2014%u2014%5B23%u79CD%u8BBE%u8BA1%u6A21%u5F0F-%u4F9D%u8D56%u3001%u5173%u8054%u3001%u805A%u5408%u548C%u7EC4%u5408%u4E4B%u95F4%u533A%u522B%u7684%u7406%u89E3%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/f0dd90c0-b3d0-4576-b603-085cb5bf1e48%29%0Aaccept%u7684%u53C2%u6570%u662FModemVisitor%uFF0C%u6240%u4EE5Modem%u4F9D%u8D56%u4E8EModemVisitor%0A%u6240%u4EE5%u4E00%u65E6%u6DFB%u52A0%u65B0Modem%u6D3E%u751F%u7C7B%uFF0C%u5219%0A-%20ModemVisitor%u8981%u6DFB%u52A0%u4E00%u4E2A%u63A5%u53E3%0A-%20%u56E0%u4E3A%u4F9D%u8D56%u5173%u7CFBModem%u8981%u91CD%u65B0%u7F16%u8BD1%0A-%20%u5B9A%u4E49%u4E86Modem%u63A5%u53E3%u7684%u7C7B%u90FD%u8981%u91CD%u65B0%u7F16%u8BD1%0A%0A%u5173%u4E8EC++%u7684%u63CF%u8FF0%uFF1A%0A%3E%u5728C++%u4E2D%uFF0C%u60C5%u51B5%u751A%u81F3%u66F4%u7CDF%u3002%u6BCF%u5F53%u589E%u52A0%u4EFB%u4F55%u4E00%u4E2A%u65B0%u7684%u6D3E%u751F%u7C7B%u65F6%uFF0C%u6574%u4E2A%u88AB%u8BBF%u95EE%u5C42%u6B21%u7ED3%u6784%u5C31%u5FC5%u987B%u8981%u88AB%u91CD%u65B0%u7F16%u8BD1%u3001%u91CD%u65B0%u90E8%u7F72%u3002%0A%0A%u5728C++%u4E2D%uFF0Cinterface%u4E00%u822C%u4F1A%u662F%u4E00%u4E2A%u5934%u6587%u4EF6%uFF0C%u88AB%u6240%u6709%u5B9E%u4F53%u7C7B%u5305%u542B%uFF0C%u4E00%u4E2A%u5934%u6587%u4EF6%u6539%u52A8%uFF0C%u5219%u8BE5%u7C7B%u56FE%u4E2D%u6240%u6709%u7684%u7C7B%u90FD%u4F1A%u9700%u8981%u91CD%u65B0%u7F16%u8BD1%u3002%0A%0A*%u8FD9%u91CC%u53EA%u5F3A%u8C03%u7F16%u8BD1%uFF0C%u94FE%u63A5%u603B%u662F%u90FD%u8981%u91CD%u65B0%u505A%u7684%u3002%0A%0A%23%23%23%23ACYCLIC%20VISITOR%0A%u7406%u89E3%u4E86%u4E3A%u4F55%u8981%u6709ACYCLIC%u53D8%u4F53%u4EE5%u540E%uFF0C%u518D%u770B%u4EC0%u4E48%u662FACYCLIC%20VISITOR%uFF1A%0A%21%5BAlt%20text%5D%28./1482884059208.png%29%0A%u8FD9%u91CC%u53C8%u5B66%u5230%u4E00%u4E2A%u6280%u5DE7%uFF0C%u539F%u6765%u8FD8%u53EF%u4EE5%u5B9A%u4E49%u4E00%u4E2A%u7A7A%u63A5%u53E3%uFF0C%u7136%u540E%u518D%u4F7F%u7528%u7684%u65F6%u5019%u505A%u5F3A%u5236%u7C7B%u578B%u8F6C%u6362%u3002%u611F%u89C9%u5F88%u5DE7%u5999%u3002%u5177%u4F53%u770B%u8FD9%u4E2A%u7C7B%u56FE%uFF1A%0A1.%20%u9488%u5BF9%u6BCF%u4E2AModem%u7C7B%u90FD%u6709%u4E00%u4E2AVisitor%u63A5%u53E3%uFF0C%u6CE8%u610F%u662F**%u63A5%u53E3**%0A2.%20UnixModemConfigurator%u5B9A%u4E49%u4E86%u6240%u6709Modem%u7684Visitor%u63A5%u53E3%uFF0C%u5E76%u4E14%u4E5F%u5B9A%u4E49%u4E86%u90A3%u4E2A%u7A7A%u7684%u63A5%u53E3ModemVisitor%u3002%u8FD9%u6837Modem%u5C31%u53EF%u4EE5%u901A%u8FC7ModemVisitor%u63A5%u53E3%u8BBF%u95EE%u5230UnixModemConfigurator%u4E86%u3002%0A3.%20%u56E0%u4E3AModemVisitor%u662F%u4E00%u4E2A%u7A7A%u63A5%u53E3%uFF08%u9000%u5316%u7684%uFF09%uFF0C%u6240%u4EE5%u4E0D%u7BA1%u6DFB%u52A0%u591A%u5C11Modem%u5B9E%u4F53%u7C7B%uFF0CModemVisitor%u90FD%u4E0D%u7528%u4FEE%u6539%uFF0C%u90A3Modem%u63A5%u53E3%u4E0D%u7528%u8DDF%u7740%u91CD%u65B0%u7F16%u8BD1%u3002%u53EA%u6709%u65B0%u589E%u52A0%u7684Modem%u5B9E%u4F53%u7C7B%u548CUnixModemConfigurator%u4F1A%u88AB%u7F16%u8BD1%u3002%0A%0AACYCLIC%20VISITOR%u5F88%u5DE7%u5999%u5730%u89E3%u51B3%u4E86%u4F9D%u8D56%u73AF%u7684%u95EE%u9898%u3002%u4ED6%u7684%u7F3A%u70B9%u662F%uFF0C%u5728%u5B9E%u4F53Modem%u7C7B%u4E2D%uFF0C%u9700%u8981%u5BF9%u4F20%u5165%u7684ModemVisitor%u63A5%u53E3%u8FDB%u884C%u5F3A%u5236%u7C7B%u578B%u8F6C%u5316%uFF0C%u53D8%u6210%u5BF9%u5E94%u7684Visitor%u63A5%u53E3%u3002%u8FD9%u4F1A%u5BF9%u6267%u884C%u6548%u7387%u5F15%u5165%u4E0D%u786E%u5B9A%u6027%u3002%0A%0A%3E%u66F4%u7CDF%u7CD5%u7684%u662F%uFF0C%u8F6C%u578B%u82B1%u8D39%u7684%u65F6%u95F4%u4F9D%u8D56%u4E8E%u88AB%u8BBF%u95EE%u5C42%u6B21%u7ED3%u6784%u7684%u5BBD%u5EA6%u548C%u6DF1%u5EA6%uFF0C%u6240%u4EE5%u5F88%u96BE%u8FDB%u884C%u6D4B%u5B9A%u3002%u7531%u4E8E%u8F6C%u578B%u9700%u8981%u82B1%u8D39%u5927%u91CF%u7684%u6267%u884C%u65F6%u95F4%uFF0C%u5E76%u4E14%u8FD9%u4E9B%u65F6%u95F4%u662F%u5C0F%u53EF%u9884%u6D4B%u7684%uFF0C%u6240%u4EE5ACYCLIC%20VISITOR%u6A21%u5F0F%u4E0D%u9002%u7528%u4E8E%u4E25%u683C%u7684%u5B9E%u65F6%u7CFB%u7EDF%u3002%0A%3E%u5BF9%u4E8E%u90A3%u4E9B%u88AB%u8BBF%u95EE%u7684%u5C42%u6B21%u7ED3%u6784%u4E0D%u7A33%u5B9A%uFF0C%u5E76%u4E14%u589E%u6688%u7F16%u8BD1%u6BD4%u8F83%u91CD%u8981%u7684%u7CFB%u7EDF%u6765%u8BF4%uFF0C%u8BE5%u6A21%u5F0F%u662F%u4E00%u4E2A%u4E0D%u9519%u7684%u9009%u62E9%20%u3002%0A%0A%23%23%23%23%u4F55%u65F6%u4F7F%u7528VISITOR%u6A21%u5F0F%0A%23%23%23%23%23%u62A5%u8868%u751F%u6210%u5668%0A%21%5BAlt%20text%7C450x0%5D%28./1482965780669.png%29%0A%23%23%23%23%23%u5176%u4ED6%0A%3E%u4E00%u822C%u6765%u8BF4%uFF0C%u5982%u679C%u4E00%u4E2A%u5E94%u7528%u7A0B%u5E8F%u4E2D%u5B58%u5728%u6709%u9700%u8981%u4EE5%u591A%u79CD%u4E0D%u540C%u65B9%u5F0F%u8FDB%u884C%u89E3%u91CA%u7684%u6570%u636E%u7ED3%u6784%uFF0C%u5C31%u53EF%u4EE5%u4F7F%u7528VISITOR%u6A21%u5F0F%u3002%0A%0A%u5176%u5B9E%u5C31%u662F%u5B9E%u73B0%u6570%u636E%u4E0E%u89C6%u56FE%u7684%u5206%u79BB%uFF0C%u7C7B%u4F3CMVC%u7684%u6982%u5FF5%u3002%0A%0A%23%23%23DECORATOR%0A%u6700%u65E9%u63A5%u89E6decorator%u662F%u5728python%u7684@%u8BED%u6CD5%uFF0C%u53C2%u770B%u8FD9%u7BC7%u7B14%u8BB0%5B%u7406%u89E3Python%u4E2D%u7684%u88C5%u9970%u5668%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/a0af7764-4908-4c1c-81af-b4a6bf7822da%29%u3002%u90A3%u65F6%u5019%u8FD8%u4E0D%u61C2%u4EC0%u4E48%u8BBE%u8BA1%u6A21%u5F0F%u3002%0A%u6700%u8FD1%u5728%u505AAndroid%u7A0B%u5E8F%u7684JUnit%u4EE3%u7801%u91CC%u4E5F%u6709%u88C5%u9970%u5668%u3002%u53EF%u89C1%u5176%u5E94%u7528%u4E4B%u5E7F%u3002%0A%u73B0%u5728%u5C31%u53EF%u4EE5%u770B%u4E00%u4E0B%u6B63%u89C4%u7684Decorator%u600E%u4E48%u505A%uFF1F%0A%21%5BAlt%20text%7C450x0%5D%28./1482969133162.png%29%0A%u5982%u679C%u6CA1%u6709Decorator%uFF0C%u5219%u8BBE%u7F6E%u97F3%u91CF%u7684%u4EE3%u7801%uFF0C%u5FC5%u987B%u51FA%u73B0%u5728%u62E8%u53F7%u4E4B%u524D%uFF0C%u4E0D%u7BA1%u901A%u8FC7%u4F55%u79CD%u65B9%u5F0F%u3002%u7528Decorator%u4E4B%u540E%uFF0C%u9700%u8981%u8BBE%u7F6E%u97F3%u91CF%u7684%u62E8%u53F7%u4EE3%u7801%uFF0C%u5C31%u53EF%u4EE5%u7528%u76F8%u5E94%u7684Modem%u5BF9%u8C61%u6765%u5B9E%u4F8B%u5316LoudDialModem%u3002LoudDialModem%u4F1A%u5148%u8BBE%u7F6E%u8BE5Modem%u97F3%u91CF%uFF0C%u518D%u5C06%u62E8%u53F7%u529F%u80FD%u59D4%u6258%u7ED9%u5BF9%u5E94%u7684Modem%u5BF9%u8C61%u3002%0A%0ADecorator%u7684%u4E3B%u8981%u4F5C%u7528%u5C31%u662F%u6D88%u9664%u91CD%u590D%u4EE3%u7801%u3002%0A%0A%u5982%u679C%u6709%u591A%u4E2ADecorator%uFF0C%u8981%u6D88%u9664%u59D4%u6258%u4EE3%u7801%u7684%u91CD%u590D%uFF0C%u53EF%u4EE5%u7528%u4E0B%u9762%u7684%u7C7B%u56FE%uFF1A%0A%21%5BAlt%20text%7C400x0%5D%28./1482970521968.png%29%0A%u8FD9%u6837%u6BCF%u6DFB%u52A0%u4E00%u4E2ADecorator%u53EA%u9700%u8981%u4ECEModemDecorator%u7C7B%u6D3E%u751F%u5C31%u53EF%u4EE5%u4E86%u3002%0A%0A%23%23%23EXTENSION%20OBJECT%0A%21%5BAlt%20text%5D%28./1483086640627.png%29%0AEXTENSION%20OBJECT%u662F%u4E00%u4E2A%u5F88%u91CD%u7684%u6A21%u5F0F%uFF0C%u5B9E%u73B0%u8D77%u6765%u6709%u70B9%u5E9E%u5927%uFF0C%u4F46%u662F%u5F88%u597D%u7406%u89E3%u3002%0A-%20Part%u7528HashMap%u7BA1%u7406PartExtension%0A-%20PartExtension%u662F%u4E00%u4E2A%u9000%u5316%u7684%u63A5%u53E3%uFF08%u5373%u65E0%u65B9%u6CD5%u7684%u63A5%u53E3%uFF09%uFF0C%u6240%u4EE5%u4F7F%u7528%u7684%u65F6%u5019%u4F1A%u8981%u505A%u5F3A%u5236%u7C7B%u578B%u8F6C%u6362%0A-%20PartPiece%u548CAssembly%u5728%u6784%u9020%u7684%u65F6%u5019%u6DFB%u52A0%u5BF9%u5E94%u7684extension%20object%uFF0C%u5219%u5728%u9700%u8981%u7684%u65F6%u5019%u53EF%u4EE5get%u51FA%u6765%0A-%20PartPiece%u548CAssembly%u5728extension%u6784%u9020%u7684%u65F6%u5019%uFF0C%u628A%u81EA%u5DF1%u4F20%u7ED9%u8BE5extension%uFF0C%u5219%u5B9E%u73B0%u4E86Visit%u529F%u80FD%u3002%0A%0A%23%23%23%23%u4E3A%u4EC0%u4E48%u8981%u6709EXTENSION%20OBJECT%0AVisitor%u53EF%u4EE5%u5B9E%u73B0%u4E0D%u53BB%u4FEE%u6539%u7C7B%u5C42%u6B21%u7ED3%u6784%u7684%u60C5%u51B5%u4E0B%uFF0C%u5411%u5176%u4E2D%u6DFB%u52A0%u65B0%u529F%u80FD%u3002%u4F46%u662F%u6240%u6709%u7684%u8BBF%u95EE%u529F%u80FD%u90FD%u5728%u4E00%u4E2A%u7C7B%u5F53%u4E2D%uFF0C%u5982%u6211%u4EEC%u4F8B%u5B50%u662F%u5728UnixModemConfigurator%u4E2D%uFF0C%u800C%u4E14%u5BF9%u6BCF%u4E2AModem%u7C7B%u53EA%u6709%u4E00%u4E2Avisit%u51FD%u6570%u3002%0A%u5F53%u6211%u4EEC%u9700%u8981%u9694%u79BB%u5BF9%u5404%u4E2A%u7C7B%u7684%u8BBF%u95EE%u8FDB%u884C%u9694%u79BB%uFF0C%u6216%u8005%u9700%u8981%u5BF9%u4E00%u4E2A%u7C7B%u6709%u4E0D%u540C%u7684%u8BBF%u95EE%u65B9%u5F0F%uFF0CVISITOR%u6A21%u5F0F%u5C31%u505A%u4E0D%u5230%u4E86%u3002%0A%u4E8E%u662F%u6709%u5347%u7EA7%u7248%u7684VISITOR%uFF0C%u4E5F%u5C31%u662FEXTENSION%20OBJECT%u3002%u6BCF%u4E00%u4E2A%u7C7B%u53EF%u4EE5%u6709%u4EFB%u610F%u591A%u7684%u8BBF%u95EE%u65B9%u5F0F%uFF0C%u4E14%u6BCF%u4E2A%u7C7B%u4E4B%u95F4%u7684%u8BBF%u95EE%u548C%u4E0D%u540C%u8BBF%u95EE%u65B9%u5F0F%u4E4B%u95F4%u90FD%u662F%u9694%u79BB%u7684%u3002%u4F8B%u5982%u672C%u4F8B%u4E2D%uFF0C%u6709%u4E24%u4E2A%u88AB%u8BBF%u95EE%u7684%u7C7B%uFF08PartPiece%20%26%20Assembly%uFF09%uFF0C%u6709%u4E24%u79CD%u8BBF%u95EE%u65B9%u5F0F%uFF08XML%20%26%20CSV%uFF09%u3002%u6240%u4EE5%u603B%u5171%u67094%u4E2Aextension%20object%u3002%0A%0A*%u4F5C%u8005%u65F6%u65F6%u5728%u63D0%u9192%u6211%u4EEC%0A-%20%u6240%u6709%u4EE3%u7801%u662F%u4ECE%u6D4B%u8BD5%u7528%u4F8B%u6F14%u5316%u800C%u6765%uFF0C%u6240%u6709%u4EE3%u7801%u90FD%u521A%u597D%u8BA9%u6D4B%u8BD5%u901A%u8FC7%uFF0C%u4E0D%u591A%u4E5F%u4E0D%u5C11%u3002%uFF08%u8FD9%u4E2A%u8282%u594F%u5F88%u96BE%u628A%u63E1%uFF0C%u8FD8%u5728%u5B66%u4E60%u4E2D%uFF09%0A-%20%u4E0D%u8981%u4E3A%u4E86%u6A21%u5F0F%u800C%u6A21%u5F0F%uFF0C%u800C%u662F%u5148%u6709%u4EE3%u7801%uFF0C%u8981%u6D88%u9664%u91CD%u590D%uFF0C%u91CD%u6784%u65F6%u624D%u6162%u6162%u6F14%u5316%u6210%u9002%u5F53%u7684%u6A21%u5F0F%u3002%u800C%u6A21%u5F0F%u5E76%u4E0D%u4E00%u5B9A%u662F%u6807%u51C6%u7684%uFF0C%u6709%u53EF%u80FD%u662F%u7ECF%u8FC7%u4FEE%u6539%u800C%u9002%u5408%u4F7F%u7528%u7684%0A%0A%u770B%u770B%u6700%u4E00%u5F00%u59CB%u7684%u4EE3%u7801%u53EF%u80FD%u662F%u8FD9%u6837%u7684%0A%60%60%60%0Apublic%20PartExtension%20getExtension%28String%20extensionType%29%0A%7B%0A%09if%20%28extensionType.equals%28%22%22XML%22%29%29%0A%09%09return%20new%20XMLPiecePartExtension%28this%29%3B%0A%09else%20if%20%28extensionType.equals%28%22CSV%22%29%29%0A%09%09return%20new%20XMLAssemblyExetnsion%28this%29%3B%0A%09return%20new%20BadPartExtertsion%28%29%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23STATE%0ASTATE%u6A21%u5F0F%u8FD9%u5C31%u662F%u6709%u9650%u72B6%u6001%u673A%u3002%u5176%u5E94%u7528%u76F8%u5F53%u5E7F%u6CDB%u2014%u2014UI%uFF0C%u6570%u636E%u63A5%u53E3%uFF08%u4F8B%u5982control%20panel%u7684%u547D%u4EE4%uFF09%u7B49%u7B49%u3002%u4E0B%u9762%u662F%u5341%u5B57%u8F6C%u95E8%u7684%u72B6%u6001%u8FC1%u79FB%u56FE%u3002%0A%21%5BAlt%20text%5D%28./1483088195524.png%29%0A%u901A%u5E38%u7684%u5B9E%u73B0%u65B9%u6CD5%uFF0C%u6700%u5BB9%u6613%u60F3%u5230%u7684%u5C31%u662Fswitch/case%uFF08%u8FD9%u4E5F%u662F%u76EE%u524Dcontrol%20panel%u4EE3%u7801%u4E2D%u4F7F%u7528%u7684%uFF09%uFF0C%u518D%u9AD8%u7EA7%u4E00%u70B9%u5C31%u662F%u8FC1%u79FB%u8868%uFF0C%u6BCF%u4E2A%u8868%u9879%u5305%u542B%u4E86%u521D%u59CB%u72B6%u6001%uFF0C%u7ED3%u679C%u72B6%u6001%uFF0C%u89E6%u53D1%u4E8B%u4EF6%u548C%u8FC1%u79FB%u52A8%u4F5C%u3002%0A%0A%u770B%u770B%u771F%u6B63%u7684STATE%u6A21%u5F0F%u662F%u600E%u4E48%u5B9E%u73B0%u7684%uFF1A%0A%21%5BAlt%20text%5D%28./1483089394893.png%29%0A-%20TurstyleState%u7684%u6D3E%u751F%u7C7B%uFF0C%u4EE3%u8868%u72B6%u6001%u672C%u8EAB%0A-%20Turnstyle%u4EE3%u8868%u4E86%u6574%u4E2A%u7CFB%u7EDF%uFF0C%u5176%u5305%u542B%u4E86%u6240%u6709%u72B6%u6001%u5BF9%u8C61%uFF0C%u4E5F%u5305%u542B%u4E86%u6240%u6709%u72B6%u6001%u8FC1%u79FB%u65F6%u4EA7%u751F%u7684%u52A8%u4F5C%0A-%20TurstyleState%u7684%u6D3E%u751F%u7C7B%u8D1F%u8D23%u8C03%u7528Turnstyle%u7684%u72B6%u6001%u8FC1%u79FB%u63A5%u53E3%uFF0C%u548C%u8FC1%u79FB%u52A8%u4F5C%u3002%0A%0ASTATE%u6A21%u5F0F%u5F7B%u5E95%u5730%u5206%u79BB%u4E86%u72B6%u6001%u673A%u7684%u903B%u8F91%u548C%u52A8%u4F5C%u3002%u52A8%u4F5C%u662F%u5728Context%u7C7B%u4E2D%u5B9E%u73B0%u7684%uFF0C%u800C%u903B%u8F91%u5219%u662F%u5206%u5E03%u5728STATE%u7C7B%u7684%u6D3E%u751F%u7C7B%u4E2D%u3002%u8FD9%u5C31%u4F7F%u5F97%u4E8C%u8005%u53EF%u4EE5%u975E%u5E38%u5BB9%u6613%u5730%u72EC%u7ACB%u53D8%u5316%u3001%u4E92%u4E0D%u5F71%u54CD%u3002%0A%0A%23%23%23%23STATE%20vs.%20STRATEGY%0A%3E%u5728STATE%u6A21%u5F0F%u4E2D%uFF0C%u6D3E%u751F%u7C7B%u6301%u6709%u56DE%u6307%u5411%u4E0A%u4E0B%u6587%u7C7B%u7684%u5F15%u7528%u3002%u6D3E%u751F%u7C7B%u7684%u4E3B%u8981%u529F%u80FD%u662F%u4F7F%u7528%u8FD9%u4E2A%u5F15%20%u7528%u9009%u62E9%u5E76%u8C03%u7528%u4E0A%u4E0B%u6587%u7C7B%u4E2D%u7684%u65B9%u6CD5%u3002%u5728STRATEGY%u6A21%u5F0F%u4E2D%uFF0C%u4E0D%u5B58%u5728%u8FD9%u6837%u7684%u9650%u5236%u4EE5%u53CA%u610F%u56FE%u3002STRATEGY%u7684%u6D3E%u751F%u7C7B%u4E0D%u5FC5%u6301%u6709%u6307%u5411%u4E0A%u4E0B%u6587%u7C7B%u7684%u5F15%u7528%uFF0C%u5E76%u4E14%u4E5F%u4E0D%u9700%u8981%u53BB%u8C03%u7528%u4E0A%u4E0B%u6587%u7C7B%u7684%u65B9%u6CD5%u3002%u6240%u4EE5%uFF0C%u6240%u6709%u7684STATE%u6A21%u5F0F%u5B9E%u4F8B%u540C%u6837%u4E5F%u662FSTRATEGY%u6A21%u5F0F%u5B9E%u4F8B%uFF0C%u4F46%u662F%u5E76%u975E%u6240%u6709%u7684STRATEGY%u6A21%u5F0F%u5B9E%u4F8B%u90FD%u662FSTATE%u6A21%u5F0F%u5B9E%u4F8B%20%0A%21%5BAlt%20text%5D%28./1483089759732.png%29%0A%0A%23%23%23%23SMC%u2014%u2014%u72B6%u6001%u673A%u7F16%u8BD1%u5668%0A%u8FD9%u662F%u4E00%u4E2A%u4EE3%u7801%u751F%u6210%u5668%u3002%u5728%u524D%u9762%u4ECB%u7ECDSTATE%u6A21%u5F0F%u7684%u65F6%u5019%uFF0C%u4F1A%u53D1%u73B0%uFF0C%u5176%u5B9E%u6700%u6838%u5FC3%u7684%u90E8%u5206%u5C31%u662F%u72B6%u6001%u8FC1%u79FB%u8868%u3002%u8FD9%u6837%u4E00%u7AE0%u8868%u683C%u5176%u5B9E%u5305%u542B%u4E86%u6574%u4E2A%u6709%u9650%u72B6%u6001%u673A%u7CFB%u7EDF%u6240%u6709%u7684%u903B%u8F91%u3002%u800CSMC%u5C31%u662F%u6839%u636E%u8FD9%u6837%u4E00%u5F20%u7C7B%u4F3C%u7684%u8868%u683C%u6765%u751F%u6210STATE%u6A21%u5F0F%u4E2D%u7684%u5404%u4E2A%u7C7B%u3002%0A%21%5BAlt%20text%5D%28./1483186443050.png%29%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A

Edit


今日在做微信IoT打印机的项目,其中涉及到用Android程序访问WPS服务来实现将word文档另存为PDF的功能。于是,秉着TDD的精神,开始学习如何在Android中做单元测试。

入门

JUnit

首先看到的是Android的官网文档Getting Started with Testing, Building Local Unit Tests。有两种类型的测试,一种是跑在主机上的,叫Local Unit Test,另一种跑在目标机上,叫Instrumented Unit Test。
Local Unit Test基于JUnit,上面的关于Local Unit Test的链接已经有了如何在Android Studio中使能JUnit的范例了。配置好Dependencies就可以了。Android Studio会去maven库中抓取JUnit的jar包并导入到项目中,之后就可以使用了。
遇到错误Error:(23, 17)"Failed to resolve: junit:junit:4.12,在build.gradle下面加

repositories {
maven { url 'http://repo1.maven.org/maven2' }
jcenter { url "http://jcenter.bintray.com/" }
}

或者自行去下载junit-4.12.jar,再放到libs目录底下就可以了。

Mockito

在C++中做Unit Test的时候,我们往往需要自己构建stub,来隔离需要测试的code。在Java中,我们有现成的框架可以用,这就是Mockito。网上关于Mockito+Android单元测试的文章一搜一大摞。我也简单的摘录了几个。

import android.os.classA
class B {
public void methodC (){
classA a = new classA();
a.methodA();
}
}

请问这里我要怎么在methodC中模拟对象A的行为。诸如此类很多问题,会在下面一章进行罗列。于是在Google之中就知道了PowerMock。

PowerMock

PowerMock是Mock框架的扩展,他同时支持EasyMock和Mockito。网上的文章也是千千万,具体测试语句的写法也是各不相同,所以最靠谱的还是官网。PowerMock提供了以下模拟的途径:

  • 模拟构造函数
  • 模拟静态类
  • 突破访问权限控制,操纵私有成员,私有静态成员
  • 调用私有方法。

进阶

在实际的编码过程中,遇到很多问题,Google了很久,现将所有问题以及解决方案罗列一下:

对static方法的模拟

Looper mockLooper = mock(Looper.class);
PowerMockito.mockStatic(Looper.class);
PowerMockito.when(Looper.class, "getMainLooper").thenReturn(mockLooper);

对构造函数的模拟

解决上一章提到的问题,可以用模拟classA的构造函数来解决,同样是用到PowerMockito

PowerMockito.whenNew(Intent.class).withNoArguments().thenReturn(mockIntent);
PowerMockito.whenNew(Intent.class).withArguments(anyString()).thenReturn(mockIntent);

针对有参数和没有参数的两种情况

操作private成员

// 操作私有非静态成员
Whitebox.setInternalState(mockObj, "mPrivateStaticVariable", value);
Whitebox.getInternalState(mockObj, "mPrivateStaticVariable");

// 操作私有静态成员
Whitebox.setInternalState(xxx.class, "mPrivateStaticVariable", value, xxx.class);
Whitebox.getInternalState(xxx.class, "mPrivateStaticVariable", xxx.class);

局部模拟

这个会用到Mockito中的spy关键字。在很多情况下,我们无法剥离需要模拟的类和待测试的类。例如,实际中用到的下面的类:

public class ConverterFacade extends Service{
private void bindOfficeService(){
if (bindService(intent, connection, BIND_AUTO_CREATE)) {
...
}
}
}

ConverterFacade继承自Android自有的类Service,Service继承自Context,bindService是Context接口的一个方法。如果不对之进行mock,测试的时候会报错。因为我们要测试ConverterFacade,又不能将之mock掉,所以只能退而求其次,采用partial mock。插入官网的介绍,Mockito.spy。官方并不推荐使用spy,因为这样会让模拟的code和真实的code混在一起。

Real spies should be used carefully and occasionally.
例子:

   List list = new LinkedList();
List spy = spy(list);

//optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);

//using the spy calls real methods
spy.add("one");
spy.add("two");

//prints "one" - the first element of a list
System.out.println(spy.get(0));

//size() method was stubbed - 100 is printed
System.out.println(spy.size());

//optionally, you can verify
verify(spy).add("one");
verify(spy).add("two");

为什么要用doReturn().when()而不能用when().doReturn()

 //Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

java.lang.NoClassDefFoundError

遇到了这个问题,原因是没有导入moffice-service-base包。在这里弄好就行了

java.lang.ClassNotFoundException
This exception indicates that the class was not found on the classpath. This indicates that we were trying to load the class definition, and the class did not exist on the classpath.
java.lang.NoClassDefFoundError
This exception indicates that the JVM looked in its internal class definition data structure for the definition of a class and did not find it. This is different than saying that it could not be loaded from the classpath. Usually this indicates that we previously attempted to load a class from the classpath, but it failed for some reason - now we’re trying to use the class again (and thus need to load it, since it failed last time), but we’re not even going to try to load it, because we failed loading it earlier (and reasonably suspect that we would fail again). The earlier failure could be a ClassNotFoundException or an ExceptionInInitializerError (indicating a failure in the static initialization block) or any number of other problems. The point is, a NoClassDefFoundError is not necessarily a classpath problem.

mockStatic导致内部类无法有效引用外部类的成员

解决方法是,不要mockStatic(ConverterFacade.class);mockStatic(ConverterFacade.class, CALLS_REAL_METHODS);

捕获参数

Message m = mock(Message.class);
m.what = 1;
Handler mHandler = mock(Handler.class);
mHandler.sendMessage(m);

m.what = 2;
mHandler.sendMessage(m);

ArgumentCaptor<Message> argumentCaptor2 = ArgumentCaptor.forClass(Message.class);
verify(mHandler, times(2)).sendMessage(argumentCaptor2.capture());
List<Message> msgList = argumentCaptor2.getAllValues();

ArgumentCaptor可以帮助捕获参数调用情况。argumentCaptor.getValue()可以捕获最后一次调用的参数,argumentCaptor.getAllValues()可以捕获多次调用或者一次调用传递多个参数的情况。
这其中牵涉到Java对象传递的方法。如上程序代码,虽然最终得到的List的size是2,但是这两个表项的what值都指向2,用Android Studio查看对象地址,发现这俩都指向同一个对象,所以其值相同也就不难理解了。如果想要捕获到两个不同的值,就要new两次。

%23Android%u5355%u5143%u6D4B%u8BD5%0A@%28%u5B66%u4E60%u7B14%u8BB0%29%5BAndroid%2C%20unittest%2C%20mockito%2C%20powermock%5D%0A%u4ECA%u65E5%u5728%u505A%u5FAE%u4FE1IoT%u6253%u5370%u673A%u7684%u9879%u76EE%uFF0C%u5176%u4E2D%u6D89%u53CA%u5230%u7528Android%u7A0B%u5E8F%u8BBF%u95EEWPS%u670D%u52A1%u6765%u5B9E%u73B0%u5C06word%u6587%u6863%u53E6%u5B58%u4E3APDF%u7684%u529F%u80FD%u3002%u4E8E%u662F%uFF0C%u79C9%u7740TDD%u7684%u7CBE%u795E%uFF0C%u5F00%u59CB%u5B66%u4E60%u5982%u4F55%u5728Android%u4E2D%u505A%u5355%u5143%u6D4B%u8BD5%u3002%0A%23%23%u5165%u95E8%0A%23%23%23JUnit%0A%u9996%u5148%u770B%u5230%u7684%u662FAndroid%u7684%u5B98%u7F51%u6587%u6863%5BGetting%20Started%20with%20Testing%5D%28https%3A//developer.android.com/training/testing/start/index.html%29%2C%20%5BBuilding%20Local%20Unit%20Tests%5D%28https%3A//developer.android.com/training/testing/unit-testing/local-unit-tests.html%29%u3002%u6709%u4E24%u79CD%u7C7B%u578B%u7684%u6D4B%u8BD5%uFF0C%u4E00%u79CD%u662F%u8DD1%u5728%u4E3B%u673A%u4E0A%u7684%uFF0C%u53EBLocal%20Unit%20Test%uFF0C%u53E6%u4E00%u79CD%u8DD1%u5728%u76EE%u6807%u673A%u4E0A%uFF0C%u53EBInstrumented%20Unit%20Test%u3002%0ALocal%20Unit%20Test%u57FA%u4E8EJUnit%uFF0C%u4E0A%u9762%u7684%u5173%u4E8ELocal%20Unit%20Test%u7684%u94FE%u63A5%u5DF2%u7ECF%u6709%u4E86%u5982%u4F55%u5728Android%20Studio%u4E2D%u4F7F%u80FDJUnit%u7684%u8303%u4F8B%u4E86%u3002%u914D%u7F6E%u597DDependencies%u5C31%u53EF%u4EE5%u4E86%u3002Android%20Studio%u4F1A%u53BBmaven%u5E93%u4E2D%u6293%u53D6JUnit%u7684jar%u5305%u5E76%u5BFC%u5165%u5230%u9879%u76EE%u4E2D%uFF0C%u4E4B%u540E%u5C31%u53EF%u4EE5%u4F7F%u7528%u4E86%u3002%0A%u9047%u5230%u9519%u8BEF%60Error%3A%2823%2C%2017%29%22Failed%20to%20resolve%3A%20junit%3Ajunit%3A4.12%60%uFF0C%u5728build.gradle%u4E0B%u9762%u52A0%0A%60%60%60%0Arepositories%20%7B%0A%20%20%20%20%20%20%20%20maven%20%7B%20url%20%27http%3A//repo1.maven.org/maven2%27%20%7D%0A%20%20%20%20%20%20%20%20jcenter%20%7B%20url%20%22http%3A//jcenter.bintray.com/%22%20%7D%0A%7D%0A%60%60%60%0A%u6216%u8005%u81EA%u884C%u53BB%u4E0B%u8F7Djunit-4.12.jar%uFF0C%u518D%u653E%u5230libs%u76EE%u5F55%u5E95%u4E0B%u5C31%u53EF%u4EE5%u4E86%u3002%0A%0A%23%23%23Mockito%0A%u5728C++%u4E2D%u505AUnit%20Test%u7684%u65F6%u5019%uFF0C%u6211%u4EEC%u5F80%u5F80%u9700%u8981%u81EA%u5DF1%u6784%u5EFAstub%uFF0C%u6765%u9694%u79BB%u9700%u8981%u6D4B%u8BD5%u7684code%u3002%u5728Java%u4E2D%uFF0C%u6211%u4EEC%u6709%u73B0%u6210%u7684%u6846%u67B6%u53EF%u4EE5%u7528%uFF0C%u8FD9%u5C31%u662F%5BMockito%5D%28https%3A//github.com/mockito/mockito%29%u3002%u7F51%u4E0A%u5173%u4E8EMockito+Android%u5355%u5143%u6D4B%u8BD5%u7684%u6587%u7AE0%u4E00%u641C%u4E00%u5927%u645E%u3002%u6211%u4E5F%u7B80%u5355%u7684%u6458%u5F55%u4E86%u51E0%u4E2A%u3002%0A-%20%5BAndroid%u6D4B%u8BD5%u4E8C%uFF1AMockito%u4E0E%u5355%u5143%u6D4B%u8BD5%5D%28https%3A//www.evernote.com/shard/s24/nl/2724128/360fa827-de1f-46e7-b815-465c074a5b9e%29%0A-%20%5BAndroid%20%u5355%u5143%u6D4B%u8BD5%u4E4BJUnit%u548CMockito%5D%28https%3A//www.evernote.com/shard/s24/nl/2724128/beaaf776-621e-4fdb-9dca-e6eedc6a1029%29%0A-%20%5BAndroid%u6700%u4F73Mock%u5355%u5143%u6D4B%u8BD5%u65B9%u6848%3AJunit%20+%20Mockito%20+%20Powermock%5D%28https%3A//www.evernote.com/shard/s24/nl/2724128/78565e6e-82eb-4f74-80c8-177863a6499c%29%0AMockito%u7684%u4E3B%u8981%u4F5C%u7528%u5C31%u662F%u6A21%u62DF%u5916%u90E8%u7C7B%u7684%u884C%u4E3A%uFF0C%u8FBE%u5230%u9694%u79BB%u5F85%u6D4B%u4EE3%u7801%u7684%u76EE%u7684%u3002%u5982%u4E0B%u56FE%u3002%0A%21%5BAlt%20text%5D%28./1476833497231.png%29%0A%u5728Android%u7684%u6D4B%u8BD5%u4E2D%uFF0CMockito%u7684%u4E3B%u8981%u4F5C%u7528%u5C31%u662F%u6A21%u62DF%u6240%u6709Android%u7684%u7C7B%u3002%60ClassA%20mockObj%20%3D%20mock%28ClassA%29%60%u5C31%u4F1A%u751F%u6210%u4E00%u4E2Amock%u7684%u5BF9%u8C61%u3002%u7136%u540E%u6211%u4EEC%u5C31%u53EF%u4EE5%u901A%u8FC7Mockito%u63D0%u4F9B%u7684%u5404%u79CD%u624B%u6BB5%u6765%u5B9A%u5236%u8FD9%u4E2A%u5BF9%u8C61%u7684%u5404%u79CD%u884C%u4E3A%u3002%u4F46%u8FD9%u6709%u5F88%u5927%u7684%u5C40%u9650%u6027%u3002%u770B%u4E0B%u9762%u7684%u4EE3%u7801%0A%60%60%60%0Aimport%20android.os.classA%0Aclass%20B%20%7B%0A%09public%20void%20methodC%20%28%29%7B%0A%09%09classA%20a%20%3D%20new%20classA%28%29%3B%0A%09%09a.methodA%28%29%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%u8BF7%u95EE%u8FD9%u91CC%u6211%u8981%u600E%u4E48%u5728methodC%u4E2D%u6A21%u62DF%u5BF9%u8C61A%u7684%u884C%u4E3A%u3002%u8BF8%u5982%u6B64%u7C7B%u5F88%u591A%u95EE%u9898%uFF0C%u4F1A%u5728%u4E0B%u9762%u4E00%u7AE0%u8FDB%u884C%u7F57%u5217%u3002%u4E8E%u662F%u5728Google%u4E4B%u4E2D%u5C31%u77E5%u9053%u4E86PowerMock%u3002%0A%0A%23%23%23PowerMock%0APowerMock%u662FMock%u6846%u67B6%u7684%u6269%u5C55%uFF0C%u4ED6%u540C%u65F6%u652F%u6301EasyMock%u548CMockito%u3002%u7F51%u4E0A%u7684%u6587%u7AE0%u4E5F%u662F%u5343%u5343%u4E07%uFF0C%u5177%u4F53%u6D4B%u8BD5%u8BED%u53E5%u7684%u5199%u6CD5%u4E5F%u662F%u5404%u4E0D%u76F8%u540C%uFF0C%u6240%u4EE5%u6700%u9760%u8C31%u7684%u8FD8%u662F%5B%u5B98%u7F51%5D%28https%3A//github.com/jayway/powermock%29%u3002PowerMock%u63D0%u4F9B%u4E86%u4EE5%u4E0B%u6A21%u62DF%u7684%u9014%u5F84%uFF1A%0A-%20%u6A21%u62DF%u6784%u9020%u51FD%u6570%0A-%20%u6A21%u62DF%u9759%u6001%u7C7B%0A-%20%u7A81%u7834%u8BBF%u95EE%u6743%u9650%u63A7%u5236%uFF0C%u64CD%u7EB5%u79C1%u6709%u6210%u5458%uFF0C%u79C1%u6709%u9759%u6001%u6210%u5458%0A-%20%u8C03%u7528%u79C1%u6709%u65B9%u6CD5%u3002%0A%0A%23%23%u8FDB%u9636%0A%u5728%u5B9E%u9645%u7684%u7F16%u7801%u8FC7%u7A0B%u4E2D%uFF0C%u9047%u5230%u5F88%u591A%u95EE%u9898%uFF0CGoogle%u4E86%u5F88%u4E45%uFF0C%u73B0%u5C06%u6240%u6709%u95EE%u9898%u4EE5%u53CA%u89E3%u51B3%u65B9%u6848%u7F57%u5217%u4E00%u4E0B%uFF1A%0A%23%23%23%20%u5BF9static%u65B9%u6CD5%u7684%u6A21%u62DF%0A%60%60%60%0ALooper%20mockLooper%20%3D%20mock%28Looper.class%29%3B%0APowerMockito.mockStatic%28Looper.class%29%3B%0APowerMockito.when%28Looper.class%2C%20%22getMainLooper%22%29.thenReturn%28mockLooper%29%3B%0A%60%60%60%0A%0A%23%23%23%u5BF9%u6784%u9020%u51FD%u6570%u7684%u6A21%u62DF%0A%u89E3%u51B3%u4E0A%u4E00%u7AE0%u63D0%u5230%u7684%u95EE%u9898%uFF0C%u53EF%u4EE5%u7528%u6A21%u62DFclassA%u7684%u6784%u9020%u51FD%u6570%u6765%u89E3%u51B3%uFF0C%u540C%u6837%u662F%u7528%u5230PowerMockito%0A%60%60%60%0APowerMockito.whenNew%28Intent.class%29.withNoArguments%28%29.thenReturn%28mockIntent%29%3B%0APowerMockito.whenNew%28Intent.class%29.withArguments%28anyString%28%29%29.thenReturn%28mockIntent%29%3B%0A%60%60%60%0A%u9488%u5BF9%u6709%u53C2%u6570%u548C%u6CA1%u6709%u53C2%u6570%u7684%u4E24%u79CD%u60C5%u51B5%0A%0A%23%23%23%u64CD%u4F5Cprivate%u6210%u5458%0A%60%60%60%0A//%20%u64CD%u4F5C%u79C1%u6709%u975E%u9759%u6001%u6210%u5458%0AWhitebox.setInternalState%28mockObj%2C%20%22mPrivateStaticVariable%22%2C%20value%29%3B%0AWhitebox.getInternalState%28mockObj%2C%20%22mPrivateStaticVariable%22%29%3B%0A%0A//%20%u64CD%u4F5C%u79C1%u6709%u9759%u6001%u6210%u5458%0AWhitebox.setInternalState%28xxx.class%2C%20%22mPrivateStaticVariable%22%2C%20value%2C%20xxx.class%29%3B%0AWhitebox.getInternalState%28xxx.class%2C%20%22mPrivateStaticVariable%22%2C%20xxx.class%29%3B%0A%60%60%60%0A%0A%23%23%23%u5C40%u90E8%u6A21%u62DF%0A%u8FD9%u4E2A%u4F1A%u7528%u5230Mockito%u4E2D%u7684spy%u5173%u952E%u5B57%u3002%u5728%u5F88%u591A%u60C5%u51B5%u4E0B%uFF0C%u6211%u4EEC%u65E0%u6CD5%u5265%u79BB%u9700%u8981%u6A21%u62DF%u7684%u7C7B%u548C%u5F85%u6D4B%u8BD5%u7684%u7C7B%u3002%u4F8B%u5982%uFF0C%u5B9E%u9645%u4E2D%u7528%u5230%u7684%u4E0B%u9762%u7684%u7C7B%uFF1A%0A%60%60%60%0Apublic%20class%20ConverterFacade%20extends%20Service%7B%0A%09private%20void%20bindOfficeService%28%29%7B%0A%09%09if%20%28bindService%28intent%2C%20connection%2C%20BIND_AUTO_CREATE%29%29%20%7B%0A%09%09%09...%0A%09%09%7D%0A%09%7D%0A%7D%0A%60%60%60%0AConverterFacade%u7EE7%u627F%u81EAAndroid%u81EA%u6709%u7684%u7C7BService%uFF0CService%u7EE7%u627F%u81EAContext%uFF0CbindService%u662FContext%u63A5%u53E3%u7684%u4E00%u4E2A%u65B9%u6CD5%u3002%u5982%u679C%u4E0D%u5BF9%u4E4B%u8FDB%u884Cmock%uFF0C%u6D4B%u8BD5%u7684%u65F6%u5019%u4F1A%u62A5%u9519%u3002%u56E0%u4E3A%u6211%u4EEC%u8981%u6D4B%u8BD5ConverterFacade%uFF0C%u53C8%u4E0D%u80FD%u5C06%u4E4Bmock%u6389%uFF0C%u6240%u4EE5%u53EA%u80FD%u9000%u800C%u6C42%u5176%u6B21%uFF0C%u91C7%u7528partial%20mock%u3002%u63D2%u5165%u5B98%u7F51%u7684%u4ECB%u7ECD%uFF0C%5BMockito.spy%5D%28http%3A//site.mockito.org/mockito/docs/current/org/mockito/Mockito.html%23spy%28T%29%29%u3002%u5B98%u65B9%u5E76%u4E0D%u63A8%u8350%u4F7F%u7528spy%uFF0C%u56E0%u4E3A%u8FD9%u6837%u4F1A%u8BA9%u6A21%u62DF%u7684code%u548C%u771F%u5B9E%u7684code%u6DF7%u5728%u4E00%u8D77%u3002%0A%3E%20Real%20spies%20should%20be%20used%20**carefully%20and%20occasionally**.%0A%u4F8B%u5B50%uFF1A%0A%60%60%60%0A%20%20%20List%20list%20%3D%20new%20LinkedList%28%29%3B%0A%20%20%20List%20spy%20%3D%20spy%28list%29%3B%0A%0A%20%20%20//optionally%2C%20you%20can%20stub%20out%20some%20methods%3A%0A%20%20%20when%28spy.size%28%29%29.thenReturn%28100%29%3B%0A%0A%20%20%20//using%20the%20spy%20calls%20real%20methods%0A%20%20%20spy.add%28%22one%22%29%3B%0A%20%20%20spy.add%28%22two%22%29%3B%0A%0A%20%20%20//prints%20%22one%22%20-%20the%20first%20element%20of%20a%20list%0A%20%20%20System.out.println%28spy.get%280%29%29%3B%0A%0A%20%20%20//size%28%29%20method%20was%20stubbed%20-%20100%20is%20printed%0A%20%20%20System.out.println%28spy.size%28%29%29%3B%0A%0A%20%20%20//optionally%2C%20you%20can%20verify%0A%20%20%20verify%28spy%29.add%28%22one%22%29%3B%0A%20%20%20verify%28spy%29.add%28%22two%22%29%3B%0A%60%60%60%0A%u4E3A%u4EC0%u4E48%u8981%u7528%60doReturn%28%29.when%28%29%60%u800C%u4E0D%u80FD%u7528%60when%28%29.doReturn%28%29%60%0A%60%60%60%0A%20//Impossible%3A%20real%20method%20is%20called%20so%20spy.get%280%29%20throws%20IndexOutOfBoundsException%20%28the%20list%20is%20yet%20empty%29%0Awhen%28spy.get%280%29%29.thenReturn%28%22foo%22%29%3B%0A%0A//You%20have%20to%20use%20doReturn%28%29%20for%20stubbing%0AdoReturn%28%22foo%22%29.when%28spy%29.get%280%29%3B%0A%60%60%60%0A%0A%23%23%23java.lang.NoClassDefFoundError%0A%u9047%u5230%u4E86%u8FD9%u4E2A%u95EE%u9898%uFF0C%u539F%u56E0%u662F%u6CA1%u6709%u5BFC%u5165moffice-service-base%u5305%u3002%u5728%u8FD9%u91CC%u5F04%u597D%u5C31%u884C%u4E86%0A%21%5BAlt%20text%5D%28./1476841513603.png%29%0A%u4E0D%u8FC7%u521A%u770B%u5230%u8FD9%u4E2Aexception%u7684%u65F6%u5019%uFF0C%u4E5F%u633A%u552C%u4EBA%u7684%u3002%u5728StackOverflow%u4E0A%u641C%u5230%u4E86%u8FD9%u4E2A%u5E16%u5B50%uFF0C%u4E5F%u7B97%u662F%u5BF9%u8FD9%u4E2A%u9519%u8BEF%u7684%u4E00%u4E2A%u5C0F%u5C0F%u7684%u5165%u95E8%uFF1A%0A%3E%20**java.lang.ClassNotFoundException**%0A%3E%20This%20exception%20indicates%20that%20the%20class%20was%20not%20found%20on%20the%20classpath.%20This%20indicates%20that%20we%20were%20trying%20to%20load%20the%20class%20definition%2C%20and%20the%20class%20did%20not%20exist%20on%20the%20classpath.%0A%3E**java.lang.NoClassDefFoundError**%0A%3EThis%20exception%20indicates%20that%20the%20JVM%20looked%20in%20its%20internal%20class%20definition%20data%20structure%20for%20the%20definition%20of%20a%20class%20and%20did%20not%20find%20it.%20This%20is%20different%20than%20saying%20that%20it%20could%20not%20be%20loaded%20from%20the%20classpath.%20Usually%20this%20indicates%20that%20we%20previously%20attempted%20to%20load%20a%20class%20from%20the%20classpath%2C%20but%20it%20failed%20for%20some%20reason%20-%20now%20we%27re%20trying%20to%20use%20the%20class%20again%20%28and%20thus%20need%20to%20load%20it%2C%20since%20it%20failed%20last%20time%29%2C%20but%20we%27re%20not%20even%20going%20to%20try%20to%20load%20it%2C%20because%20we%20failed%20loading%20it%20earlier%20%28and%20reasonably%20suspect%20that%20we%20would%20fail%20again%29.%20The%20earlier%20failure%20could%20be%20a%20ClassNotFoundException%20or%20an%20ExceptionInInitializerError%20%28indicating%20a%20failure%20in%20the%20static%20initialization%20block%29%20or%20any%20number%20of%20other%20problems.%20The%20point%20is%2C%20a%20NoClassDefFoundError%20is%20not%20necessarily%20a%20classpath%20problem.%0A%0A%23%23%23mockStatic%u5BFC%u81F4%u5185%u90E8%u7C7B%u65E0%u6CD5%u6709%u6548%u5F15%u7528%u5916%u90E8%u7C7B%u7684%u6210%u5458%0A%u89E3%u51B3%u65B9%u6CD5%u662F%uFF0C%u4E0D%u8981%60mockStatic%28ConverterFacade.class%29%3B%60%u8981%60mockStatic%28ConverterFacade.class%2C%20CALLS_REAL_METHODS%29%3B%60%0A%0A%23%23%23%u6355%u83B7%u53C2%u6570%0A%60%60%60%0AMessage%20m%20%3D%20mock%28Message.class%29%3B%0Am.what%20%3D%201%3B%0AHandler%20mHandler%20%3D%20mock%28Handler.class%29%3B%0AmHandler.sendMessage%28m%29%3B%0A%0Am.what%20%3D%202%3B%0AmHandler.sendMessage%28m%29%3B%0A%0AArgumentCaptor%3CMessage%3E%20argumentCaptor2%20%3D%20ArgumentCaptor.forClass%28Message.class%29%3B%0Averify%28mHandler%2C%20times%282%29%29.sendMessage%28argumentCaptor2.capture%28%29%29%3B%0AList%3CMessage%3E%20msgList%20%3D%20argumentCaptor2.getAllValues%28%29%3B%0A%60%60%60%0AArgumentCaptor%u53EF%u4EE5%u5E2E%u52A9%u6355%u83B7%u53C2%u6570%u8C03%u7528%u60C5%u51B5%u3002%60argumentCaptor.getValue%28%29%60%u53EF%u4EE5%u6355%u83B7%u6700%u540E%u4E00%u6B21%u8C03%u7528%u7684%u53C2%u6570%uFF0C%60argumentCaptor.getAllValues%28%29%60%u53EF%u4EE5%u6355%u83B7%u591A%u6B21%u8C03%u7528%u6216%u8005%u4E00%u6B21%u8C03%u7528%u4F20%u9012%u591A%u4E2A%u53C2%u6570%u7684%u60C5%u51B5%u3002%0A%u8FD9%u5176%u4E2D%u7275%u6D89%u5230Java%u5BF9%u8C61%u4F20%u9012%u7684%u65B9%u6CD5%u3002%u5982%u4E0A%u7A0B%u5E8F%u4EE3%u7801%uFF0C%u867D%u7136%u6700%u7EC8%u5F97%u5230%u7684List%u7684size%u662F2%uFF0C%u4F46%u662F%u8FD9%u4E24%u4E2A%u8868%u9879%u7684what%u503C%u90FD%u6307%u54112%uFF0C%u7528Android%20Studio%u67E5%u770B%u5BF9%u8C61%u5730%u5740%uFF0C%u53D1%u73B0%u8FD9%u4FE9%u90FD%u6307%u5411%u540C%u4E00%u4E2A%u5BF9%u8C61%uFF0C%u6240%u4EE5%u5176%u503C%u76F8%u540C%u4E5F%u5C31%u4E0D%u96BE%u7406%u89E3%u4E86%u3002%u5982%u679C%u60F3%u8981%u6355%u83B7%u5230%u4E24%u4E2A%u4E0D%u540C%u7684%u503C%uFF0C%u5C31%u8981new%u4E24%u6B21%u3002

Edit


我有史以来,见过的翻译的最最最烂的中文译本,没有之一。大家记住这个名字徐家福。通篇狗屁不通半文半白的叙述,业务不精还以为自己是孔圣人。每次看他的译本就有真想抽丫的冲动。
书是好书,Martin Fowler-很有经验的UML专家。书中不乏他关于使用UML的真知灼见。刚阅览了第九章,忍不住要写点笔记记录一下。

Chapter 8. Deployment Diagrams

The nodes contain artifacts, which are the physical manifestations of software: usually, files. These files might be executables (such as .exe files, binaries, DLLs, JAR files, assemblies, or scripts), or data files, configuration files, HTML documents, and so on. Listing an artifact within a node shows that the artifact is deployed to that node in the running system.

Chapter 9. Use Cases

Use cases are well known as an important part of the UML. However, the surprise is that in many ways, the definition of use cases in the UML is rather sparse.

Use case在UML中很重要,但他的定义却比较随意。

What the UML describes is a use case diagram, which shows how use cases relate to each other.

UML中提到的use case,往往指的是用例图,但其实用例图用处并不大,真正重要的use case本身,按Martin的说发就是,那一条条的steps和extensions。

定义

Use Scenario

A scenario is a sequence of steps describing an nteraction between a user and a system.

Use Case

Use cases are a technique for capturing the functional requirements of a system.
A use case is a set of scenarios tied together by a common user goal.
Use Case = several Use Scenarios

Extension

An extension within the use case names a condition that results in different interactions from those described in the main success scenario (MSS) and states what those differences are.

翻成扩展吧,感觉就是steps中的特例。具体可以看下面的例子。

Levels

这个很有意思。按Martin的说法,分成三个level

  • Sea Level
    • Sea-level use cases typically represent a discrete interaction between a primary actor and the system.
  • Fish Level
    • Use cases that are there only because they are included by sea-level use cases are fish level. Sea level的子use case,被sea level use case包含。
  • Kite Level
    • kite-level use cases show how the sea-level use cases fit into wider business interactions. 在business case的时候用到这个level的use case。

Fowler大师给出建议:

You should have most of your use cases at the sea level.

在系统设计的时候,尽量只用sea level的use case,也就是中间级,既不是太细也不太粗。

Feature

Many approaches use features of a system—Extreme Programming calls them user stories—to help describe requirements.

所谓Feature,我理解,是系统的特性,根据use case要用到的特性来定义系统需要提供什么,这是一种对正在设计的系统的requirement。
但是Feature本身与use case并没有对应关系,他们是系统设计时,先后被用到的两个用途的两件东西。现有use case,再有features (user stories)。我认为feature这个词更贴切,以区分use case。

Fowler大师再次给出建议:

Although you can go directly to describing features, many people find it helpful to develop use cases first and then generate a list of features.

Misc.

  • A pre-condition describes what the system should ensure is true before the system allows
    the use case to begin. This is useful for telling the programmers what conditions they don’t
    have to check for in their code.
  • A guarantee describes what the system will ensure at the end of the use case. Success guarantees hold after a successful scenario; minimal guarantees hold after any scenario.
  • A trigger specifies the event that gets the use case started.

这些在严格定义use case,并促成系统界限设定时用得上。
此时Fowler大师再次给出建议:

It’s better to do too little than too much. The amount of detail you need in a use case depends on the amount of risk in that use case.

后面Fowler大师接着说(我就不放原文了),通常,在开始的时候,你只需要几个关键的use case,慢慢地其他的use case会被添进来。你并不需要把他们都写下来,口头的交流效率往往更高。
不要花太多的时间画用例图,focus在文字描述上。画图容易让事情变得复杂而失去焦点,并且图越复杂,看得懂的人越少。

例子

什么时候用Use Case

Use cases are a valuable tool to help understand the functional requirements of a system.

接着Fowler大师又给出真知灼见:

A couple of pages per use case is just fine for most cases.

一般一个use case一到两页纸足矣。不要太多或太少。

Chapter 10. State Machine Diagrams

When to Use State Diagrams

State diagrams are good at describing the behavior of an object across several use cases. State diagrams are not very good at describing behavior that involves a number of objects collaborating.
Many people find that UI and control objects have the kind of behavior that is useful to depict with a state diagram.

例子&基本概念

When developers talk about objects, they often refer to the state of the objects to mean the combination of all the data in the fields of the objects.

开发人员说的object,一般指的是object的某一个状态。

高级概念

Internal Activities

Activity States

regular activities occur “instantaneously” and cannot be interrupted by regular events, while do-activities can take finite time and can be interrupted

Superstates

Concurrent States

history pseudostate. This indicates that when the clock is switched on, the radio/CD choice goes back to the state the clock was in when it was turned off.上一次关机时的状态,就是history pseudostate。

Implementing State Diagrams

有三个方法implement

  • nested switch
  • the State pattern
  • state tables
    第一个最简单也最常见就是switch-case。Fowler大师说不建议用这个,即便是简单的case。因为很容易失控。
    第二个是state设计模式,具体请见[Gang of Four]The state pattern is easier to put together when you need it, and although it needs a new class for each state, it’s a small amount of code to write in each case.

Obviously, the state table is more work to do once, but then you can use it every time you have a state problem to hold.

Chapter 11. Activity Diagrams

基本概念

我翻译之为活动图。其最重要的功能就是阐明动作序列——串行&并行。

  • Initial node & activity final
  • fork & join
  • decision & merge
  • 每一个圆角的方框框是一个action,所有的这一切组成一个activity

如果需要每一个action可以转化成一个子活动(sub activity)。然后在主图中用一个叉子(rake)表示。

When to Use Activity Diagrams

The great strength of activity diagrams lies in the fact that they support and encourage parallel behavior.

不过在这一章节中,Fowler大师这里有一段话颇为耐人寻味:

In principle, you can take advantages of the forks and joins to describe parallel algorithms for concurrent programs. Although I don’t travel in concurrent circles that much, I haven’t seen much evidence of people using them there.
I think the reason is that **most of the complexity of concurrent programming is in avoiding
contention on data, and activity diagrams don’t help much with that**.

并没有很多人或者有很强的理由使用活动图来描述并行结构,原因是活动图并不能很好的描述对资源的争夺(contention)。

高级用法

Partitions

通过泳道图来阐明actions都由哪写object来完成的。这个对阐述流程的时候没什么用,但是在business process modeling的时候比较有用,可以清楚的表明,每个部门或者角色需要做哪些事情。典型的partitions如下图

Signals

这个在描述流程的时候比较有用。他提供了一种活动起点的描述。比方,系统响应一个外部事件,来开始一个activity。下面是例子

  • send signal
  • accept signal
  • time signal

Tokens

这个按照Fowler大师的说法,有些UML的大部头著作花了大篇幅的文章介绍token的使用。在复杂系统中token可以让系统可易于理解,可视化更好。

You can visualize the tokens with coins or counters moving across the diagram. As you get to more complicated examples of activity diagrams, tokens often make it easier to visualize things.

Flows and Edges

这里提供了几种图例,来丰富活动图的画法。看例子就可以了:

Pins and Transformations

看一个pin and transformation的例图:

Pins are best when you want to look at the data needed and produced by the various actions.
If you use pins, it’s safe to show multiple flows coming into the same action. The pin notation
reinforces the implicit join

Expansion Regions

这个主要用来描述一个activity的输出会触发若干个activity。看例图:

Flow Final

Flow Final提供了提前结束一个activity分支的描述。看下面的例子,有一个分支在某一情况下,直接结束了。

Join Specifications

join之前的判断

总得看来,activity diagram可以用来画flow chart,而且提供了一下更酷的功能。

%23UML%20Distilled%20%28UML%u7CBE%u7CB9%29%0A@%28%u5B66%u4E60%u7B14%u8BB0%29%5BUML%5D%0A%u6211%u6709%u53F2%u4EE5%u6765%uFF0C%u89C1%u8FC7%u7684%u7FFB%u8BD1%u7684%u6700%u6700%u6700%u70C2%u7684%u4E2D%u6587%u8BD1%u672C%uFF0C%u6CA1%u6709%u4E4B%u4E00%u3002%u5927%u5BB6%u8BB0%u4F4F%u8FD9%u4E2A%u540D%u5B57%u5F90%u5BB6%u798F%u3002%u901A%u7BC7%u72D7%u5C41%u4E0D%u901A%u534A%u6587%u534A%u767D%u7684%u53D9%u8FF0%uFF0C%u4E1A%u52A1%u4E0D%u7CBE%u8FD8%u4EE5%u4E3A%u81EA%u5DF1%u662F%u5B54%u5723%u4EBA%u3002%u6BCF%u6B21%u770B%u4ED6%u7684%u8BD1%u672C%u5C31%u6709%u771F%u60F3%u62BD%u4E2B%u7684%u51B2%u52A8%u3002%0A%u4E66%u662F%u597D%u4E66%uFF0CMartin%20Fowler-%u5F88%u6709%u7ECF%u9A8C%u7684UML%u4E13%u5BB6%u3002%u4E66%u4E2D%u4E0D%u4E4F%u4ED6%u5173%u4E8E%u4F7F%u7528UML%u7684%u771F%u77E5%u707C%u89C1%u3002%u521A%u9605%u89C8%u4E86%u7B2C%u4E5D%u7AE0%uFF0C%u5FCD%u4E0D%u4F4F%u8981%u5199%u70B9%u7B14%u8BB0%u8BB0%u5F55%u4E00%u4E0B%u3002%0A%0A%5BTOC%5D%0A%0A%23%23Chapter%208.%20Deployment%20Diagrams%0A%21%5BAlt%20text%5D%28./1470561176490.png%29%0A%3EThe%20nodes%20contain%20artifacts%2C%20which%20are%20the%20physical%20manifestations%20of%20software%3A%20usually%2C%20files.%20These%20files%20might%20be%20executables%20%28such%20as%20.exe%20files%2C%20binaries%2C%20DLLs%2C%20JAR%20files%2C%20assemblies%2C%20or%20scripts%29%2C%20or%20data%20files%2C%20configuration%20files%2C%20HTML%20documents%2C%20and%20so%20on.%20Listing%20an%20artifact%20within%20a%20node%20shows%20that%20the%20artifact%20is%20deployed%20to%20that%20node%20in%20the%20running%20system.%0A%23%23Chapter%209.%20Use%20Cases%0A%3EUse%20cases%20are%20well%20known%20as%20an%20important%20part%20of%20the%20UML.%20However%2C%20the%20surprise%20is%20that%20in%20many%20ways%2C%20the%20definition%20of%20use%20cases%20in%20the%20UML%20is%20rather%20sparse.%20%0A%0AUse%20case%u5728UML%u4E2D%u5F88%u91CD%u8981%uFF0C%u4F46%u4ED6%u7684%u5B9A%u4E49%u5374%u6BD4%u8F83%u968F%u610F%u3002%0A%3EWhat%20the%20UML%20describes%20is%20a%20use%20case%20diagram%2C%20which%20shows%20how%20use%20cases%20relate%20to%20each%20other.%20%0A%0AUML%u4E2D%u63D0%u5230%u7684use%20case%uFF0C%u5F80%u5F80%u6307%u7684%u662F%u7528%u4F8B%u56FE%uFF0C%u4F46%u5176%u5B9E%u7528%u4F8B%u56FE%u7528%u5904%u5E76%u4E0D%u5927%uFF0C%u771F%u6B63%u91CD%u8981%u7684use%20case%u672C%u8EAB%uFF0C%u6309Martin%u7684%u8BF4%u53D1%u5C31%u662F%uFF0C%u90A3%u4E00%u6761%u6761%u7684steps%u548Cextensions%u3002%0A%23%23%23%u5B9A%u4E49%0A%23%23%23%23Use%20Scenario%0A%3EA%20scenario%20is%20a%20sequence%20of%20steps%20describing%20an%20nteraction%20between%20a%20user%20and%20a%20system.%20%0A%23%23%23%23Use%20Case%0A%3EUse%20cases%20are%20a%20technique%20for%20capturing%20the%20functional%20requirements%20of%20a%20system.%20%0A%3EA%20use%20case%20is%20a%20set%20of%20scenarios%20tied%20together%20by%20a%20common%20user%20goal.%0A%3E**Use%20Case%20%3D%20several%20Use%20Scenarios**%0A%23%23%23%23Extension%0A%3EAn%20extension%20within%20the%20use%20case%20names%20a%20condition%20that%20results%20in%20different%20interactions%20from%20those%20described%20in%20the%20main%20success%20scenario%20%28MSS%29%20and%20states%20what%20those%20differences%20are.%0A%0A%u7FFB%u6210%u6269%u5C55%u5427%uFF0C%u611F%u89C9%u5C31%u662Fsteps%u4E2D%u7684%u7279%u4F8B%u3002%u5177%u4F53%u53EF%u4EE5%u770B%u4E0B%u9762%u7684%u4F8B%u5B50%u3002%0A%23%23%23%23Levels%0A%u8FD9%u4E2A%u5F88%u6709%u610F%u601D%u3002%u6309Martin%u7684%u8BF4%u6CD5%uFF0C%u5206%u6210%u4E09%u4E2Alevel%0A-%20Sea%20Level%0A%09-%20%20Sea-level%20use%20cases%20typically%20represent%20a%20discrete%20interaction%20between%20a%20primary%20actor%20and%20the%20system.%0A-%20Fish%20Level%0A%09-%20Use%20cases%20that%20are%20there%20only%20because%20they%20are%20included%20by%20sea-level%20use%20cases%20are%20fish%20level.%20Sea%20level%u7684%u5B50use%20case%uFF0C%u88ABsea%20level%20use%20case%u5305%u542B%u3002%0A-%20Kite%20Level%0A%09-%20kite-level%20use%20cases%20show%20how%20the%20sea-level%20use%20cases%20fit%20into%20wider%20business%20interactions.%20%u5728business%20case%u7684%u65F6%u5019%u7528%u5230%u8FD9%u4E2Alevel%u7684use%20case%u3002%0A%0AFowler%u5927%u5E08%u7ED9%u51FA%u5EFA%u8BAE%uFF1A%0A%3E**You%20should%20have%20most%20of%20your%20use%20cases%20at%20the%20sea%20level.%20**%0A%0A%u5728%u7CFB%u7EDF%u8BBE%u8BA1%u7684%u65F6%u5019%uFF0C%u5C3D%u91CF%u53EA%u7528sea%20level%u7684use%20case%uFF0C%u4E5F%u5C31%u662F%u4E2D%u95F4%u7EA7%uFF0C%u65E2%u4E0D%u662F%u592A%u7EC6%u4E5F%u4E0D%u592A%u7C97%u3002%0A%23%23%23%23Feature%0A%3EMany%20approaches%20use%20features%20of%20a%20system%u2014Extreme%20Programming%20calls%20them%20**user%20stories**%u2014to%20help%20describe%20requirements.%20%0A%0A%u6240%u8C13Feature%uFF0C%u6211%u7406%u89E3%uFF0C%u662F%u7CFB%u7EDF%u7684%u7279%u6027%uFF0C%u6839%u636Euse%20case%u8981%u7528%u5230%u7684%u7279%u6027%u6765%u5B9A%u4E49%u7CFB%u7EDF%u9700%u8981%u63D0%u4F9B%u4EC0%u4E48%uFF0C%u8FD9%u662F%u4E00%u79CD%u5BF9%u6B63%u5728%u8BBE%u8BA1%u7684%u7CFB%u7EDF%u7684requirement%u3002%0A%u4F46%u662FFeature%u672C%u8EAB%u4E0Euse%20case%u5E76%u6CA1%u6709%u5BF9%u5E94%u5173%u7CFB%uFF0C%u4ED6%u4EEC%u662F%u7CFB%u7EDF%u8BBE%u8BA1%u65F6%uFF0C%u5148%u540E%u88AB%u7528%u5230%u7684%u4E24%u4E2A%u7528%u9014%u7684%u4E24%u4EF6%u4E1C%u897F%u3002%u73B0%u6709use%20case%uFF0C%u518D%u6709features%20%28user%20stories%29%u3002%u6211%u8BA4%u4E3Afeature%u8FD9%u4E2A%u8BCD%u66F4%u8D34%u5207%uFF0C%u4EE5%u533A%u5206use%20case%u3002%0A%0AFowler%u5927%u5E08%u518D%u6B21%u7ED9%u51FA%u5EFA%u8BAE%uFF1A%0A%3EAlthough%20you%20can%20go%20directly%20to%20describing%20features%2C%20many%20people%20find%20it%20helpful%20to%20**develop%20use%20cases%20first%20and%20then%20generate%20a%20list%20of%20features.**%20%0A%0A%23%23%23%23Misc.%0A-%20A%20**pre-condition**%20describes%20what%20the%20system%20should%20ensure%20is%20true%20before%20the%20system%20allows%0Athe%20use%20case%20to%20begin.%20This%20is%20useful%20for%20telling%20the%20programmers%20what%20conditions%20they%20don%27t%0Ahave%20to%20check%20for%20in%20their%20code.%0A-%20A%20**guarantee**%20describes%20what%20the%20system%20will%20ensure%20at%20the%20end%20of%20the%20use%20case.%20Success%20guarantees%20hold%20after%20a%20successful%20scenario%3B%20minimal%20guarantees%20hold%20after%20any%20scenario.%0A-%20A%20**trigger**%20specifies%20the%20event%20that%20gets%20the%20use%20case%20started.%0A%0A%u8FD9%u4E9B%u5728%u4E25%u683C%u5B9A%u4E49use%20case%uFF0C%u5E76%u4FC3%u6210%u7CFB%u7EDF%u754C%u9650%u8BBE%u5B9A%u65F6%u7528%u5F97%u4E0A%u3002%0A%u6B64%u65F6Fowler%u5927%u5E08%u518D%u6B21%u7ED9%u51FA%u5EFA%u8BAE%uFF1A%0A%3E**It%27s%20better%20to%20do%20too%20little%20than%20too%20much.%20The%20amount%20of%20detail%20you%20need%20in%20a%20use%20case%20depends%20on%20the%20amount%20of%20risk%20in%20that%20use%20case.%20**%0A%0A%u540E%u9762Fowler%u5927%u5E08%u63A5%u7740%u8BF4%uFF08%u6211%u5C31%u4E0D%u653E%u539F%u6587%u4E86%uFF09%uFF0C%u901A%u5E38%uFF0C%u5728%u5F00%u59CB%u7684%u65F6%u5019%uFF0C%u4F60%u53EA%u9700%u8981%u51E0%u4E2A%u5173%u952E%u7684use%20case%uFF0C%u6162%u6162%u5730%u5176%u4ED6%u7684use%20case%u4F1A%u88AB%u6DFB%u8FDB%u6765%u3002%u4F60%u5E76%u4E0D%u9700%u8981%u628A%u4ED6%u4EEC%u90FD%u5199%u4E0B%u6765%uFF0C%u53E3%u5934%u7684%u4EA4%u6D41%u6548%u7387%u5F80%u5F80%u66F4%u9AD8%u3002%0A**%u4E0D%u8981%u82B1%u592A%u591A%u7684%u65F6%u95F4%u753B%u7528%u4F8B%u56FE%uFF0Cfocus%u5728%u6587%u5B57%u63CF%u8FF0%u4E0A%u3002%u753B%u56FE%u5BB9%u6613%u8BA9%u4E8B%u60C5%u53D8%u5F97%u590D%u6742%u800C%u5931%u53BB%u7126%u70B9%uFF0C%u5E76%u4E14%u56FE%u8D8A%u590D%u6742%uFF0C%u770B%u5F97%u61C2%u7684%u4EBA%u8D8A%u5C11%u3002**%0A%23%23%23%u4F8B%u5B50%0A%21%5BAlt%20text%5D%28./1469631172614.png%29%0A%23%23%23%u4EC0%u4E48%u65F6%u5019%u7528Use%20Case%0A%3EUse%20cases%20are%20a%20valuable%20tool%20to%20help%20understand%20the%20functional%20requirements%20of%20a%20system.%20%0A%0A%u63A5%u7740Fowler%u5927%u5E08%u53C8%u7ED9%u51FA%u771F%u77E5%u707C%u89C1%uFF1A%0A%3EA%20couple%20of%20pages%20per%20use%20case%20is%20just%20fine%20for%20most%20cases.%0A%0A%u4E00%u822C%u4E00%u4E2Ause%20case%u4E00%u5230%u4E24%u9875%u7EB8%u8DB3%u77E3%u3002%u4E0D%u8981%u592A%u591A%u6216%u592A%u5C11%u3002%20%0A%23%23Chapter%2010.%20State%20Machine%20Diagrams%0A%23%23%23When%20to%20Use%20State%20Diagrams%0A%3EState%20diagrams%20are%20good%20at%20describing%20the%20behavior%20of%20**an%20object%20across%20several%20use%20cases**.%20State%20diagrams%20are%20not%20very%20good%20at%20describing%20behavior%20that%20involves%20a%20number%20of%20objects%20collaborating.%0A%3EMany%20people%20find%20that%20**UI%20and%20control%20objects**%20have%20the%20kind%20of%20behavior%20that%20is%20useful%20to%20depict%20with%20a%20state%20diagram.%0A%23%23%23%u4F8B%u5B50%26%u57FA%u672C%u6982%u5FF5%0A%21%5BAlt%20text%5D%28./1470056081607.png%29%0A%u7BAD%u5934%u4E0A%u7684%u6587%u5B57%u683C%u5F0F%u4E3A%60trigger-signature%20%5Bguard%5D/activity%60%uFF0C%u4F8B%u5982%60candle%20removed%5Bdoor%20closed%5D/reveal%20lock%60%uFF0C%u610F%u601D%u662F%u5F53%u95E8%u5173%u8D77%u6765%u7684%u65F6%u5019%28guard%29%uFF0C%u8721%u70DB%u88AB%u4ECE%u70DB%u53F0%u62FF%u8D70%28event%29%uFF0C%u9501%u5373%u663E%u73B0%u51FA%u6765%28activity%29%u3002%u8FD9%u4E09%u4E2A%u90E8%u5206%u5747%u4E3A%u53EF%u9009%u9879%uFF0C%u4E0D%u662F%u5FC5%u987B%u6709%u7684%u3002%u5982%u679C%u51E0%u4E2Atransision%u6709%u76F8%u540C%u7684event%u548Cactivity%uFF0C%u90A3%u4E48guard%u5FC5%u987B%u4E92%u65A5%uFF0C%u8FD9%u6837%u624D%u80FD%u786E%u5B9A%u8D70%u54EA%u4E2Atransision%u3002%0AFowler%u5927%u5E08%u8BF4%uFF1A%0A%3EWhen%20developers%20talk%20about%20objects%2C%20they%20often%20refer%20to%20the%20state%20of%20the%20objects%20to%20mean%20the%20combination%20of%20all%20the%20data%20in%20the%20fields%20of%20the%20objects.%0A%0A%u5F00%u53D1%u4EBA%u5458%u8BF4%u7684object%uFF0C%u4E00%u822C%u6307%u7684%u662Fobject%u7684%u67D0%u4E00%u4E2A%u72B6%u6001%u3002%0A%23%23%23%u9AD8%u7EA7%u6982%u5FF5%0A%23%23%23%23Internal%20Activities%0A%21%5BAlt%20text%5D%28./1470057983821.png%29%0A%u4ECE%u81EA%u5DF1%u5230%u81EA%u5DF1%u7684transision%u4E2D%u7684%u6D3B%u52A8%u90E8%u5206%u5C31%u662Finternal%20activity%u3002%0A%23%23%23%23Activity%20States%0A%21%5BAlt%20text%5D%28./1470058049870.png%29%0A%u8017%u65F6%u6BD4%u8F83%u957F%u7684activity%u672C%u8EAB%u4E5F%u53EF%u4EE5%u6210%u4E3A%u4E00%u4E2Astate%uFF0C%u4F8B%u5982searching%u3002%0A%3Eregular%20activities%20occur%20%22instantaneously%22%20and%20cannot%20be%20interrupted%20by%20regular%20events%2C%20while%20**do-activities%20can%20take%20finite%20time%20and%20can%20be%20interrupted**%0A%23%23%23%23Superstates%0A%21%5BAlt%20text%5D%28./1470058186471.png%29%0A%u591A%u4E2Astate%u5171%u4EAB%u76F8%u540C%u7684transition%u548Cinternal%20activities%uFF0C%u8FD9%u6837%u53EF%u4EE5%u62BD%u8C61%u51FAsuperstates%uFF0C%u7136%u540E%u653E%u5230%u4E00%u4E2A%u6846%u6846%u91CC%u3002%0A%23%23%23%23Concurrent%20States%0A%21%5BAlt%20text%5D%28./1470058339705.png%29%0A%u51E0%u4E2Astate%u53EF%u80FD%u662F%u6B63%u4EA4%u7684%uFF08orthogonal%uFF09%uFF0C%u5373%u53EF%u80FD%u662F%u5E76%u884C%u72B6%u6001%u3002%u8FD9%u65F6%u5019%u5C31%u80FD%u8FD9%u6837%u8868%u793A%u3002%0A%3E%20**history%20pseudostate**.%20This%20indicates%20that%20when%20the%20clock%20is%20switched%20on%2C%20the%20radio/CD%20choice%20goes%20back%20to%20the%20state%20the%20clock%20was%20in%20when%20it%20was%20turned%20off.%u4E0A%u4E00%u6B21%u5173%u673A%u65F6%u7684%u72B6%u6001%uFF0C%u5C31%u662Fhistory%20pseudostate%u3002%20%0A%23%23%23Implementing%20State%20Diagrams%0A%u6709%u4E09%u4E2A%u65B9%u6CD5implement%0A-%20%20nested%20switch%0A-%20%20the%20State%20pattern%0A-%20%20state%20tables%0A%u7B2C%u4E00%u4E2A%u6700%u7B80%u5355%u4E5F%u6700%u5E38%u89C1%u5C31%u662Fswitch-case%u3002Fowler%u5927%u5E08%u8BF4%u4E0D%u5EFA%u8BAE%u7528%u8FD9%u4E2A%uFF0C%u5373%u4FBF%u662F%u7B80%u5355%u7684case%u3002%u56E0%u4E3A%u5F88%u5BB9%u6613%u5931%u63A7%u3002%0A%u7B2C%u4E8C%u4E2A%u662Fstate%u8BBE%u8BA1%u6A21%u5F0F%uFF0C%u5177%u4F53%u8BF7%u89C1%uFF3BGang%20of%20Four%uFF3DThe%20state%20pattern%20is%20easier%20to%20put%20together%20when%20you%20need%20it%2C%20and%20although%20it%20needs%20a%20new%20class%20for%20each%20state%2C%20it%27s%20a%20small%20amount%20of%20code%20to%20write%20in%20each%20case.%0A%21%5BAlt%20text%5D%28./1470058566116.png%29%0A%u7B2C%u4E09%u4E2A%u662Fstate%20table%uFF0C%u5F62%u5982%uFF1A%0A%21%5BAlt%20text%5D%28./1470058643590.png%29%0A%3EObviously%2C%20the%20state%20table%20is%20more%20work%20to%20do%20once%2C%20but%20then%20you%20can%20use%20it%20every%20time%20you%20have%20a%20state%20problem%20to%20hold.%20%0A%0A%23%23Chapter%2011.%20Activity%20Diagrams%0A%23%23%23%u57FA%u672C%u6982%u5FF5%0A%u6211%u7FFB%u8BD1%u4E4B%u4E3A%u6D3B%u52A8%u56FE%u3002%u5176%u6700%u91CD%u8981%u7684%u529F%u80FD%u5C31%u662F%u9610%u660E%u52A8%u4F5C%u5E8F%u5217%u2014%u2014%u4E32%u884C%26%u5E76%u884C%u3002%0A%21%5BAlt%20text%5D%28./1469861506321.png%29%0A%u6211%u89C9%u5F97%u6D3B%u52A8%u56FE%u5176%u5B9E%u5C31%u662F%u6D41%u7A0B%u56FE%28flow%20chart%29%uFF0C%u4F5C%u8005%u8BF4activity%20diagram%u4E0Eflow%20chart%u7684%u4E3B%u8981%u5DEE%u522B%u5C31%u662F%uFF0Cactivity%20diagram%u6709%u6807%u51C6%u8BED%u8A00%u6765%u63CF%u8FF0%u5E76%u884C%u7684%u52A8%u4F5C%u3002%0A%u4E00%u526F%u6D3B%u52A8%u56FE%u4E2D%u7684%u57FA%u672C%u6784%u6210%u5143%u7D20%u53EF%u53C2%u770B%u4E0A%u56FE%uFF1A%0A-%20Initial%20node%20%26%20activity%20final%0A-%20fork%20%26%20join%0A-%20decision%20%26%20merge%0A-%20%u6BCF%u4E00%u4E2A%u5706%u89D2%u7684%u65B9%u6846%u6846%u662F%u4E00%u4E2Aaction%uFF0C%u6240%u6709%u7684%u8FD9%u4E00%u5207%u7EC4%u6210%u4E00%u4E2Aactivity%0A%0A%u5982%u679C%u9700%u8981%u6BCF%u4E00%u4E2Aaction%u53EF%u4EE5%u8F6C%u5316%u6210%u4E00%u4E2A%u5B50%u6D3B%u52A8%28sub%20activity%29%u3002%u7136%u540E%u5728%u4E3B%u56FE%u4E2D%u7528%u4E00%u4E2A%u53C9%u5B50%28rake%29%u8868%u793A%u3002%0A%21%5BAlt%20text%5D%28./1469861910016.png%29%0A%0A%23%23%23When%20to%20Use%20Activity%20Diagrams%0A%3EThe%20great%20strength%20of%20activity%20diagrams%20lies%20in%20the%20fact%20that%20they%20support%20and%20encourage%20parallel%20behavior.%20%0A%0A%u4E0D%u8FC7%u5728%u8FD9%u4E00%u7AE0%u8282%u4E2D%uFF0CFowler%u5927%u5E08%u8FD9%u91CC%u6709%u4E00%u6BB5%u8BDD%u9887%u4E3A%u8010%u4EBA%u5BFB%u5473%uFF1A%0A%3EIn%20principle%2C%20you%20can%20take%20advantages%20of%20the%20forks%20and%20joins%20to%20describe%20parallel%20algorithms%20for%20concurrent%20programs.%20Although%20I%20don%27t%20travel%20in%20concurrent%20circles%20that%20much%2C%20I%20haven%27t%20seen%20much%20evidence%20of%20people%20using%20them%20there.%20%0A%3EI%20think%20the%20reason%20is%20that%20**most%20of%20the%20complexity%20of%20concurrent%20programming%20is%20in%20avoiding%0Acontention%20on%20data%2C%20and%20activity%20diagrams%20don%27t%20help%20much%20with%20that**.%0A%0A%u5E76%u6CA1%u6709%u5F88%u591A%u4EBA%u6216%u8005%u6709%u5F88%u5F3A%u7684%u7406%u7531%u4F7F%u7528%u6D3B%u52A8%u56FE%u6765%u63CF%u8FF0%u5E76%u884C%u7ED3%u6784%uFF0C%u539F%u56E0%u662F%u6D3B%u52A8%u56FE%u5E76%u4E0D%u80FD%u5F88%u597D%u7684%u63CF%u8FF0%u5BF9%u8D44%u6E90%u7684%u4E89%u593A%28contention%29%u3002%0A%23%23%23%u9AD8%u7EA7%u7528%u6CD5%0A%23%23%23%23Partitions%0A%u901A%u8FC7%u6CF3%u9053%u56FE%u6765%u9610%u660Eactions%u90FD%u7531%u54EA%u5199object%u6765%u5B8C%u6210%u7684%u3002%u8FD9%u4E2A%u5BF9%u9610%u8FF0%u6D41%u7A0B%u7684%u65F6%u5019%u6CA1%u4EC0%u4E48%u7528%uFF0C%u4F46%u662F%u5728business%20process%20modeling%u7684%u65F6%u5019%u6BD4%u8F83%u6709%u7528%uFF0C%u53EF%u4EE5%u6E05%u695A%u7684%u8868%u660E%uFF0C%u6BCF%u4E2A%u90E8%u95E8%u6216%u8005%u89D2%u8272%u9700%u8981%u505A%u54EA%u4E9B%u4E8B%u60C5%u3002%u5178%u578B%u7684partitions%u5982%u4E0B%u56FE%0A%21%5BAlt%20text%5D%28./1469862941546.png%29%0A%0A%23%23%23%23Signals%0A%u8FD9%u4E2A%u5728%u63CF%u8FF0%u6D41%u7A0B%u7684%u65F6%u5019%u6BD4%u8F83%u6709%u7528%u3002%u4ED6%u63D0%u4F9B%u4E86%u4E00%u79CD%u6D3B%u52A8%u8D77%u70B9%u7684%u63CF%u8FF0%u3002%u6BD4%u65B9%uFF0C%u7CFB%u7EDF%u54CD%u5E94%u4E00%u4E2A%u5916%u90E8%u4E8B%u4EF6%uFF0C%u6765%u5F00%u59CB%u4E00%u4E2Aactivity%u3002%u4E0B%u9762%u662F%u4F8B%u5B50%0A%21%5BAlt%20text%5D%28./1469863153757.png%29%0A%u4F8B%u5B50%u91CC%u9762%u5305%u542B%u4E86%uFF1A%0A-%20send%20signal%0A-%20accept%20signal%0A-%20time%20signal%0A%23%23%23%23Tokens%0A%u8FD9%u4E2A%u6309%u7167Fowler%u5927%u5E08%u7684%u8BF4%u6CD5%uFF0C%u6709%u4E9BUML%u7684%u5927%u90E8%u5934%u8457%u4F5C%u82B1%u4E86%u5927%u7BC7%u5E45%u7684%u6587%u7AE0%u4ECB%u7ECDtoken%u7684%u4F7F%u7528%u3002%u5728%u590D%u6742%u7CFB%u7EDF%u4E2Dtoken%u53EF%u4EE5%u8BA9%u7CFB%u7EDF%u53EF%u6613%u4E8E%u7406%u89E3%uFF0C%u53EF%u89C6%u5316%u66F4%u597D%u3002%0A%3EYou%20can%20visualize%20the%20tokens%20with%20coins%20or%20counters%20moving%20across%20the%20diagram.%20As%20you%20get%20to%20more%20complicated%20examples%20of%20activity%20diagrams%2C%20tokens%20often%20make%20it%20easier%20to%20visualize%20things.%0A%23%23%23%23Flows%20and%20Edges%0A%u8FD9%u91CC%u63D0%u4F9B%u4E86%u51E0%u79CD%u56FE%u4F8B%uFF0C%u6765%u4E30%u5BCC%u6D3B%u52A8%u56FE%u7684%u753B%u6CD5%u3002%u770B%u4F8B%u5B50%u5C31%u53EF%u4EE5%u4E86%uFF1A%0A%21%5BAlt%20text%5D%28./1469863497950.png%29%0A%u540E%u4E24%u4E2A%u56FE%u63D0%u4F9B%u4E86%u5728action%u4E4B%u95F4%u4F20%u9012object%u7684%u65B9%u6CD5%uFF0C%u4ED6%u4EEC%u7565%u6709%u533A%u522B%u3002%u540E%u9762%u4E13%u95E8%u653E%u4E86%u4E00%u8282%u8BB2pin%u3002pin%u53EF%u4EE5%u505A%u53D8%u6362%28transformations%29%uFF0C%u800Cobject%20node%u505A%u4E0D%u5230%u3002%0A%u770B%u7B2C%u4E09%u5E45%u56FE%uFF0Cobject%20node%u7684%u6846%u6846%u662F%u5C16%u89D2%u77E9%u5F62%uFF0C%u800Caction%u662F%u5706%u89D2%u77E9%u5F62%u3002%0A%23%23%23%23Pins%20and%20Transformations%0A%u770B%u4E00%u4E2Apin%20and%20transformation%u7684%u4F8B%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1469863936140.png%29%0A%3E%20Pins%20are%20best%20when%20you%20want%20to%20look%20at%20the%20data%20needed%20and%20produced%20by%20the%20various%20actions.%20%0A%3E%20If%20you%20use%20pins%2C%20it%27s%20safe%20to%20show%20multiple%20flows%20coming%20into%20the%20same%20action.%20The%20pin%20notation%0Areinforces%20the%20implicit%20join%0A%23%23%23%23Expansion%20Regions%0A%u8FD9%u4E2A%u4E3B%u8981%u7528%u6765%u63CF%u8FF0%u4E00%u4E2Aactivity%u7684%u8F93%u51FA%u4F1A%u89E6%u53D1%u82E5%u5E72%u4E2Aactivity%u3002%u770B%u4F8B%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1469864217899.png%29%0A%u5982%u679C%u6B64%u82E5%u5E72%u4E2Aactivity%u662F%u540C%u4E00%u79CDactivity%u7684%u8BDD%uFF0C%u53EF%u4EE5%u7528expansion%20region%u7684%u7B80%u5199%u6CD5%uFF1A%0A%21%5BAlt%20text%5D%28./1469864349862.png%29%0A%0A%23%23%23%23Flow%20Final%0AFlow%20Final%u63D0%u4F9B%u4E86%u63D0%u524D%u7ED3%u675F%u4E00%u4E2Aactivity%u5206%u652F%u7684%u63CF%u8FF0%u3002%u770B%u4E0B%u9762%u7684%u4F8B%u5B50%uFF0C%u6709%u4E00%u4E2A%u5206%u652F%u5728%u67D0%u4E00%u60C5%u51B5%u4E0B%uFF0C%u76F4%u63A5%u7ED3%u675F%u4E86%u3002%0A%21%5BAlt%20text%5D%28./1469867539007.png%29%0A%0A%23%23%23%23Join%20Specifications%0Ajoin%u4E4B%u524D%u7684%u5224%u65AD%0A%21%5BAlt%20text%5D%28./1469867666058.png%29%0A%0A%u603B%u5F97%u770B%u6765%uFF0Cactivity%20diagram%u53EF%u4EE5%u7528%u6765%u753Bflow%20chart%uFF0C%u800C%u4E14%u63D0%u4F9B%u4E86%u4E00%u4E0B%u66F4%u9177%u7684%u529F%u80FD%u3002%0A

Edit


一直想做一个方便查词的工具。一开始想借助OSX下面最火的Alfred,做一个插件。结果以为赚便宜淘宝上50块钱买了一个family license,结果被无良奸商骗了。license没几天就失效了,投诉无门。后来发现一直在用的Windows快捷方式神器Launchy,也支持插件开发。于是,锁定目标,做一个Launchy的有道插件。
首先看Launchy插件开发官方页。人家写清楚了环境的版本要求:

For this setup, we require Visual Studio (preferably 2005 as that is what I use) and QT 4.3.3

后来就因为版本问题走了很多弯路。

功能概述

  1. 快速进入插件 - yd<tab>
  2. 从剪贴板取单词,或自行输入

  1. 查单词 - <tab>

  1. 执行任意结果项均打开单词的有道词典页面

QT环境安装

QT4 vs.QT5

目前QT的最新版本是5.6,所以直接走官方用网络安装的都是QT5。所以一开始,傻乎乎的准备把原先的插件框架写成QT5兼容。QT4到QT5做了大规模的变化,很多特性不兼容。下面是一些参考链接

QT安装

QT有多种安装方式:

  1. 最简单的就是官网,通过网络方式安装,注意选community和open source。其他是要license fee的
  2. exe安装。以4.8.6为例,在QT archive的网站上可以下载官方用各种编译器编好的二进制安装包。

  1. 最灵活的安装方式就是编译安装了。去上面archive的网站下载源码。好处是可以编译出自己需要的编译器的版本。具体支持哪些编译平台看源码目录<Qt>\4.6.0\mkspecs\,下面列出了所有支持的开发平台。

有一点很有意思的是,在我折腾QT5的时候发现,QT5目前还不支持VS2015的编译平台,最高只支持到VS2013。
回到我们的需求上,可以看到,按照Launchy官方的指点,我们需要VS2005,以及对应的QT库,所以archive页上也没有现成的二进制安装包,只好自己编译。依然有官方指引。其实很容易,所谓会者不难。有几个地方要注意:

  1. 下载VS2005的时候一定要找靠谱的安装,否则像我一开始装的是个繁中版本,各种错误,让人很是郁闷。
  2. 一定要从VS的command prompt进去configue和compile。因为VS的command prompt会做很多环境配置。
  3. x86和x64是不同的command prompt

剩下来的按照官方的指引就可以了,简单看如下:

configure -platform win32-msvc2005
nmake

QT开发环境

官网安装的版本自带了QT Creator。所以一开始都是用他在折腾,感觉用起来还不错,没有VS那么臃肿。换到QT4.8.6以后,可能版本过低,开不起来,所以没办法要切到VS2005底下开发。然后又摸索了一阵,需要安装一个VS的QT插件。后来又是在版本上一番折腾,最终选定1.1.11,配合VS2005使用无压力。

Launchy插件开发

其实很简单,按照作者的推荐,版本一步不差,或者差的不远,都是可以跑起来的。最终版本VS2005+QT4.6.0+qt-vs-1.1.11
中间试过VS2013,如果整个Launchy用2013编译,插件也用2013编译的话,是可以用的。但是这样移植性太差了,网上下载的Launchy就没法用了。

Launchy插件

简单说一下Launchy的插件结构,以便未来如果要进一步开发又得重新学习:

插件基于消息工作

        case MSG_INIT:
init();
handled = true;
break;
case MSG_GET_LABELS: // 每个input可以打label,以后可以根据label来甄别属于哪个插件
getLabels((QList<InputData>*) wParam);
handled = true;
break;
case MSG_GET_ID:
getID((uint*) wParam);
handled = true;
break;
case MSG_GET_NAME:
getName((QString*) wParam);
handled = true;
break;
case MSG_GET_RESULTS:// 在这里为输入插入结果
getResults((QList<InputData>*) wParam, (QList<CatItem>*) lParam);
handled = true;
break;
case MSG_GET_CATALOG: // catalog是Launchy的数据库入口。对于插件数据量不大的话,可以忽略这个
getCatalog((QList<CatItem>*) wParam);
handled = true;
break;
case MSG_LAUNCH_ITEM: // 激发某个结果项,这里要注意InputData的top result
//qDebug()<<"Launch";
launchItem((QList<InputData>*) wParam, (CatItem*) lParam);
handled = true;
break;
case MSG_HAS_DIALOG:
// Set to true if you provide a gui
handled = false;
break;
case MSG_DO_DIALOG:
// This isn't called unless you return true to MSG_HAS_DIALOG
doDialog((QWidget*) wParam, (QWidget**) lParam);
break;
case MSG_END_DIALOG:
// This isn't called unless you return true to MSG_HAS_DIALOG
endDialog((bool) wParam);
break;

还有一些迷信活动

至今没理解是为什么,看下面的代码:

void mypluginPlugin::getLabels(QList<InputData>* id)
{
//此处省略一段代码...
if (id->first().hasLabel(HASH_myplugin))
{
id->first().setTopResult(CatItem("", id->last().getText(), HASH_myplugin, getIcon()));
}
}

加了这一段代码之后,就只出现跟插件有关的结果项,如果没有这一段代码,就会杂七杂八出现很多。所以我说InputData的top result很关键。

调试工具

因为我们是插件开发,没法在线调试,只能用qDebug()<<"proxy: "<<proxy;打印调试语句。又没有命令行界面,只能借助一个微软的工具叫DebugView,在下面的地址下载。DebugView官方下载地址
有了他就可以看调试信息输出了。

QT相关

QT调用python

其实就是C++调用python。网上搜到的一堆都大同小异。举个例子QT中 使用c++调用python。最后我失败了,编译成功,运行失败。原因,我总结了一下,其实和QT以及VS搭配使用时版本的问题类似。C++调用python的接口函数都是在python27.lib中定义的。这个lib使用的编译平台,要和你现在使用的编译平台一致。不过看起来蛮诱人的,不过不知道有多少可能能用得上。

QProcess

放弃python27.lib之后,就转到QProcess上来了。这个其实就是QT简单的调用命令行程序。但是这个变态的是一旦命令出错,什么信息也打不出来,别看他有readStandardError接口。在使用QProcess的时候,学习到以下几点:

  1. Windows底下在代码里要用中文必须在字符串前面加L,如L"有道翻译"。这样Windows才能识别到这个是WCHAR,Windows平台的双字节编码
  2. QT里面所有的QString都是unicode,如QString::fromWCharArray(L"有道翻译)

QJson

本来打算找一个库来解析有道API返回的json数据,不过后来本着小而美的精神,放弃了解析整个json数据的企图,只单纯的解析多行字符串。不过还是看了一些资料,所以记下来万一以后用得上。
QJson是一个QT的开源库,在git hub上,需要下载源码自己编译。编出来会有一个.lib和一个.dll。分别放到C:\Qt\4.6.0\lib和C:\Qt\4.6.0\bin\底下,并在.pro文件里引用就可以用了。记得哦,与你的主程序用同一个编译平台。另外QT5已经默认内置json解析库了。
使用QJson的方法看官方文档
另外一种解析json数据的思路是用QT4内置的QScriptEngine。没深究过,但知道这个库是让QT更好地和JavaScript融合使用诞生的,具体可以看这个链接-QScriptEngine Printout to String as JSON

一些有用的链接

%23Launchy%u6709%u9053%u7FFB%u8BD1%u63D2%u4EF6%u5F00%u53D1%0A@%28%u5DE5%u4F5C%u7B14%u8BB0%29%5BQT%5D%0A%u4E00%u76F4%u60F3%u505A%u4E00%u4E2A%u65B9%u4FBF%u67E5%u8BCD%u7684%u5DE5%u5177%u3002%u4E00%u5F00%u59CB%u60F3%u501F%u52A9OSX%u4E0B%u9762%u6700%u706B%u7684Alfred%uFF0C%u505A%u4E00%u4E2A%u63D2%u4EF6%u3002%u7ED3%u679C%u4EE5%u4E3A%u8D5A%u4FBF%u5B9C%u6DD8%u5B9D%u4E0A50%u5757%u94B1%u4E70%u4E86%u4E00%u4E2Afamily%20license%uFF0C%u7ED3%u679C%u88AB%u65E0%u826F%u5978%u5546%u9A97%u4E86%u3002license%u6CA1%u51E0%u5929%u5C31%u5931%u6548%u4E86%uFF0C%u6295%u8BC9%u65E0%u95E8%u3002%u540E%u6765%u53D1%u73B0%u4E00%u76F4%u5728%u7528%u7684Windows%u5FEB%u6377%u65B9%u5F0F%u795E%u5668Launchy%uFF0C%u4E5F%u652F%u6301%u63D2%u4EF6%u5F00%u53D1%u3002%u4E8E%u662F%uFF0C%u9501%u5B9A%u76EE%u6807%uFF0C%u505A%u4E00%u4E2ALaunchy%u7684%u6709%u9053%u63D2%u4EF6%u3002%0A%u9996%u5148%u770B%5BLaunchy%u63D2%u4EF6%u5F00%u53D1%u5B98%u65B9%u9875%5D%28http%3A//www.launchy.net/api2.0/%29%u3002%u4EBA%u5BB6%u5199%u6E05%u695A%u4E86%u73AF%u5883%u7684%u7248%u672C%u8981%u6C42%uFF1A%0A%3EFor%20this%20setup%2C%20we%20require%20**Visual%20Studio%20%28preferably%202005**%20as%20that%20is%20what%20I%20use%29%20and%20**QT%204.3.3**%0A%0A%u540E%u6765%u5C31%u56E0%u4E3A%u7248%u672C%u95EE%u9898%u8D70%u4E86%u5F88%u591A%u5F2F%u8DEF%u3002%0A%23%23%u529F%u80FD%u6982%u8FF0%0A1.%20%u5FEB%u901F%u8FDB%u5165%u63D2%u4EF6%20-%20yd%26lt%3Btab%26gt%3B%0A2.%20%u4ECE%u526A%u8D34%u677F%u53D6%u5355%u8BCD%uFF0C%u6216%u81EA%u884C%u8F93%u5165%0A%21%5BAlt%20text%5D%28./1469437387713.png%29%0A%21%5BAlt%20text%5D%28./1469437454898.png%29%0A3.%20%u67E5%u5355%u8BCD%20-%20%26lt%3Btab%26gt%3B%0A%20%21%5BAlt%20text%5D%28./1469437302454.png%29%0A4.%20%u6267%u884C%u4EFB%u610F%u7ED3%u679C%u9879%u5747%u6253%u5F00%u5355%u8BCD%u7684%u6709%u9053%u8BCD%u5178%u9875%u9762%0A%21%5BAlt%20text%5D%28./1469437529508.png%29%0A%0A%23%23QT%u73AF%u5883%u5B89%u88C5%0A%23%23%23QT4%20vs.QT5%0A%u76EE%u524DQT%u7684%u6700%u65B0%u7248%u672C%u662F5.6%uFF0C%u6240%u4EE5%u76F4%u63A5%u8D70%u5B98%u65B9%u7528%u7F51%u7EDC%u5B89%u88C5%u7684%u90FD%u662FQT5%u3002%u6240%u4EE5%u4E00%u5F00%u59CB%uFF0C%u50BB%u4E4E%u4E4E%u7684%u51C6%u5907%u628A%u539F%u5148%u7684%u63D2%u4EF6%u6846%u67B6%u5199%u6210QT5%u517C%u5BB9%u3002QT4%u5230QT5%u505A%u4E86%u5927%u89C4%u6A21%u7684%u53D8%u5316%uFF0C%u5F88%u591A%u7279%u6027%u4E0D%u517C%u5BB9%u3002%u4E0B%u9762%u662F%u4E00%u4E9B%u53C2%u8003%u94FE%u63A5%0A*%20%5B%u5B98%u65B9%u6307%u5F15%5D%28http%3A//wiki.qt.io/Transition_from_Qt_4.x_to_Qt5%29%0A*%20%5BQ_EXPORT_PLUGIN2%20to%20Q_PLUGIN_METADATA%5D%28http%3A//osdir.com/ml/kde-commits/2015-03/msg07583.html%29%0A%u603B%u4E4B%u6363%u9F13%u4E86%u5F88%u4E45%uFF0C%u6700%u7EC8%u653E%u5F03%u3002%0A%23%23%23QT%u5B89%u88C5%0AQT%u6709%u591A%u79CD%u5B89%u88C5%u65B9%u5F0F%uFF1A%0A1.%20%u6700%u7B80%u5355%u7684%u5C31%u662F%5B%u5B98%u7F51%5D%28https%3A//www.qt.io/download/%29%uFF0C%u901A%u8FC7%u7F51%u7EDC%u65B9%u5F0F%u5B89%u88C5%uFF0C%u6CE8%u610F%u9009community%u548Copen%20source%u3002%u5176%u4ED6%u662F%u8981license%20fee%u7684%0A2.%20exe%u5B89%u88C5%u3002%u4EE5%5B4.8.6%5D%28https%3A//download.qt.io/archive/qt/4.8/4.8.6/%29%u4E3A%u4F8B%uFF0C%u5728QT%20archive%u7684%u7F51%u7AD9%u4E0A%u53EF%u4EE5%u4E0B%u8F7D%u5B98%u65B9%u7528%u5404%u79CD%u7F16%u8BD1%u5668%u7F16%u597D%u7684%u4E8C%u8FDB%u5236%u5B89%u88C5%u5305%u3002%0A%21%5BAlt%20text%5D%28./1469352211795.png%29%0A3.%20%u6700%u7075%u6D3B%u7684%u5B89%u88C5%u65B9%u5F0F%u5C31%u662F%u7F16%u8BD1%u5B89%u88C5%u4E86%u3002%u53BB%u4E0A%u9762archive%u7684%u7F51%u7AD9%u4E0B%u8F7D%5B%u6E90%u7801%5D%28https%3A//download.qt.io/archive/qt/4.8/4.8.6/qt-everywhere-opensource-src-4.8.6.zip%29%u3002%u597D%u5904%u662F%u53EF%u4EE5%u7F16%u8BD1%u51FA%u81EA%u5DF1%u9700%u8981%u7684%u7F16%u8BD1%u5668%u7684%u7248%u672C%u3002%u5177%u4F53%u652F%u6301%u54EA%u4E9B%u7F16%u8BD1%u5E73%u53F0%u770B%u6E90%u7801%u76EE%u5F55%60%3CQt%3E%5C4.6.0%5Cmkspecs%5C%60%uFF0C%u4E0B%u9762%u5217%u51FA%u4E86%u6240%u6709%u652F%u6301%u7684%u5F00%u53D1%u5E73%u53F0%u3002%0A%0A%0A%u6709%u4E00%u70B9%u5F88%u6709%u610F%u601D%u7684%u662F%uFF0C%u5728%u6211%u6298%u817EQT5%u7684%u65F6%u5019%u53D1%u73B0%uFF0CQT5%u76EE%u524D%u8FD8%u4E0D%u652F%u6301VS2015%u7684%u7F16%u8BD1%u5E73%u53F0%uFF0C%u6700%u9AD8%u53EA%u652F%u6301%u5230VS2013%u3002%0A%u56DE%u5230%u6211%u4EEC%u7684%u9700%u6C42%u4E0A%uFF0C%u53EF%u4EE5%u770B%u5230%uFF0C%u6309%u7167Launchy%u5B98%u65B9%u7684%u6307%u70B9%uFF0C%u6211%u4EEC%u9700%u8981VS2005%uFF0C%u4EE5%u53CA%u5BF9%u5E94%u7684QT%u5E93%uFF0C%u6240%u4EE5archive%u9875%u4E0A%u4E5F%u6CA1%u6709%u73B0%u6210%u7684%u4E8C%u8FDB%u5236%u5B89%u88C5%u5305%uFF0C%u53EA%u597D%u81EA%u5DF1%u7F16%u8BD1%u3002%u4F9D%u7136%u6709%5B%u5B98%u65B9%u6307%u5F15%5D%28http%3A//doc.qt.io/qt-4.8/install-win.html%29%u3002%u5176%u5B9E%u5F88%u5BB9%u6613%uFF0C%u6240%u8C13%u4F1A%u8005%u4E0D%u96BE%u3002%u6709%u51E0%u4E2A%u5730%u65B9%u8981%u6CE8%u610F%uFF1A%0A1.%20%u4E0B%u8F7DVS2005%u7684%u65F6%u5019%u4E00%u5B9A%u8981%u627E%u9760%u8C31%u7684%u5B89%u88C5%uFF0C%u5426%u5219%u50CF%u6211%u4E00%u5F00%u59CB%u88C5%u7684%u662F%u4E2A%u7E41%u4E2D%u7248%u672C%uFF0C%u5404%u79CD%u9519%u8BEF%uFF0C%u8BA9%u4EBA%u5F88%u662F%u90C1%u95F7%u3002%0A2.%20%u4E00%u5B9A%u8981%u4ECEVS%u7684command%20prompt%u8FDB%u53BBconfigue%u548Ccompile%u3002%u56E0%u4E3AVS%u7684command%20prompt%u4F1A%u505A%u5F88%u591A%u73AF%u5883%u914D%u7F6E%u3002%0A3.%20x86%u548Cx64%u662F%u4E0D%u540C%u7684command%20prompt%0A%0A%u5269%u4E0B%u6765%u7684%u6309%u7167%u5B98%u65B9%u7684%u6307%u5F15%u5C31%u53EF%u4EE5%u4E86%uFF0C%u7B80%u5355%u770B%u5982%u4E0B%uFF1A%0A%60%60%60%0Aconfigure%20-platform%20win32-msvc2005%0Anmake%0A%60%60%60%0A%23%23%23QT%u5F00%u53D1%u73AF%u5883%0A%u5B98%u7F51%u5B89%u88C5%u7684%u7248%u672C%u81EA%u5E26%u4E86QT%20Creator%u3002%u6240%u4EE5%u4E00%u5F00%u59CB%u90FD%u662F%u7528%u4ED6%u5728%u6298%u817E%uFF0C%u611F%u89C9%u7528%u8D77%u6765%u8FD8%u4E0D%u9519%uFF0C%u6CA1%u6709VS%u90A3%u4E48%u81C3%u80BF%u3002%u6362%u5230QT4.8.6%u4EE5%u540E%uFF0C%u53EF%u80FD%u7248%u672C%u8FC7%u4F4E%uFF0C%u5F00%u4E0D%u8D77%u6765%uFF0C%u6240%u4EE5%u6CA1%u529E%u6CD5%u8981%u5207%u5230VS2005%u5E95%u4E0B%u5F00%u53D1%u3002%u7136%u540E%u53C8%u6478%u7D22%u4E86%u4E00%u9635%uFF0C%u9700%u8981%u5B89%u88C5%u4E00%u4E2AVS%u7684QT%u63D2%u4EF6%u3002%u540E%u6765%u53C8%u662F%u5728%u7248%u672C%u4E0A%u4E00%u756A%u6298%u817E%uFF0C%u6700%u7EC8%u9009%u5B9A%5B1.1.11%5D%28https%3A//download.qt.io/official_releases/vsaddin/%29%uFF0C%u914D%u5408VS2005%u4F7F%u7528%u65E0%u538B%u529B%u3002%0A%0A%23%23Launchy%u63D2%u4EF6%u5F00%u53D1%0A%u5176%u5B9E%u5F88%u7B80%u5355%uFF0C%u6309%u7167%u4F5C%u8005%u7684%u63A8%u8350%uFF0C%u7248%u672C%u4E00%u6B65%u4E0D%u5DEE%uFF0C%u6216%u8005%u5DEE%u7684%u4E0D%u8FDC%uFF0C%u90FD%u662F%u53EF%u4EE5%u8DD1%u8D77%u6765%u7684%u3002%u6700%u7EC8%u7248%u672C**VS2005+QT4.6.0+qt-vs-1.1.11**%u3002%0A%u4E2D%u95F4%u8BD5%u8FC7VS2013%uFF0C%u5982%u679C%u6574%u4E2ALaunchy%u75282013%u7F16%u8BD1%uFF0C%u63D2%u4EF6%u4E5F%u75282013%u7F16%u8BD1%u7684%u8BDD%uFF0C%u662F%u53EF%u4EE5%u7528%u7684%u3002%u4F46%u662F%u8FD9%u6837%u79FB%u690D%u6027%u592A%u5DEE%u4E86%uFF0C%u7F51%u4E0A%u4E0B%u8F7D%u7684Launchy%u5C31%u6CA1%u6CD5%u7528%u4E86%u3002%0A%23%23%23Launchy%u63D2%u4EF6%0A%u7B80%u5355%u8BF4%u4E00%u4E0BLaunchy%u7684%u63D2%u4EF6%u7ED3%u6784%uFF0C%u4EE5%u4FBF%u672A%u6765%u5982%u679C%u8981%u8FDB%u4E00%u6B65%u5F00%u53D1%u53C8%u5F97%u91CD%u65B0%u5B66%u4E60%uFF1A%0A%23%23%23%23%u63D2%u4EF6%u57FA%u4E8E%u6D88%u606F%u5DE5%u4F5C%0A%60%60%60%09%0A%09%09case%20MSG_INIT%3A%0A%09init%28%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_GET_LABELS%3A%20//%20%u6BCF%u4E2Ainput%u53EF%u4EE5%u6253label%uFF0C%u4EE5%u540E%u53EF%u4EE5%u6839%u636Elabel%u6765%u7504%u522B%u5C5E%u4E8E%u54EA%u4E2A%u63D2%u4EF6%0A%09getLabels%28%28QList%3CInputData%3E*%29%20wParam%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_GET_ID%3A%0A%09getID%28%28uint*%29%20wParam%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_GET_NAME%3A%0A%09getName%28%28QString*%29%20wParam%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_GET_RESULTS%3A//%20%u5728%u8FD9%u91CC%u4E3A%u8F93%u5165%u63D2%u5165%u7ED3%u679C%0A%09getResults%28%28QList%3CInputData%3E*%29%20wParam%2C%20%28QList%3CCatItem%3E*%29%20lParam%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_GET_CATALOG%3A%20//%20catalog%u662FLaunchy%u7684%u6570%u636E%u5E93%u5165%u53E3%u3002%u5BF9%u4E8E%u63D2%u4EF6%u6570%u636E%u91CF%u4E0D%u5927%u7684%u8BDD%uFF0C%u53EF%u4EE5%u5FFD%u7565%u8FD9%u4E2A%0A%09getCatalog%28%28QList%3CCatItem%3E*%29%20wParam%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_LAUNCH_ITEM%3A%20//%20%u6FC0%u53D1%u67D0%u4E2A%u7ED3%u679C%u9879%uFF0C%u8FD9%u91CC%u8981%u6CE8%u610FInputData%u7684top%20result%0A%09//qDebug%28%29%3C%3C%22Launch%22%3B%0A%09launchItem%28%28QList%3CInputData%3E*%29%20wParam%2C%20%28CatItem*%29%20lParam%29%3B%0A%09handled%20%3D%20true%3B%0A%09break%3B%0Acase%20MSG_HAS_DIALOG%3A%0A%09//%20Set%20to%20true%20if%20you%20provide%20a%20gui%0A%09handled%20%3D%20false%3B%0A%09break%3B%0Acase%20MSG_DO_DIALOG%3A%0A%09//%20This%20isn%27t%20called%20unless%20you%20return%20true%20to%20MSG_HAS_DIALOG%0A%09doDialog%28%28QWidget*%29%20wParam%2C%20%28QWidget**%29%20lParam%29%3B%0A%09break%3B%0Acase%20MSG_END_DIALOG%3A%0A%09//%20This%20isn%27t%20called%20unless%20you%20return%20true%20to%20MSG_HAS_DIALOG%0A%09endDialog%28%28bool%29%20wParam%29%3B%0A%09break%3B%0A%60%60%60%0A%0A%23%23%23%23%u8FD8%u6709%u4E00%u4E9B%u8FF7%u4FE1%u6D3B%u52A8%0A%u81F3%u4ECA%u6CA1%u7406%u89E3%u662F%u4E3A%u4EC0%u4E48%uFF0C%u770B%u4E0B%u9762%u7684%u4EE3%u7801%uFF1A%0A%60%60%60%0Avoid%20mypluginPlugin%3A%3AgetLabels%28QList%3CInputData%3E*%20id%29%0A%7B%0A%09//%u6B64%u5904%u7701%u7565%u4E00%u6BB5%u4EE3%u7801...%0A%09if%20%28id-%3Efirst%28%29.hasLabel%28HASH_myplugin%29%29%0A%09%7B%0A%09%09id-%3Efirst%28%29.setTopResult%28CatItem%28%22%22%2C%20id-%3Elast%28%29.getText%28%29%2C%20HASH_myplugin%2C%20getIcon%28%29%29%29%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%u52A0%u4E86%u8FD9%u4E00%u6BB5%u4EE3%u7801%u4E4B%u540E%uFF0C%u5C31%u53EA%u51FA%u73B0%u8DDF%u63D2%u4EF6%u6709%u5173%u7684%u7ED3%u679C%u9879%uFF0C%u5982%u679C%u6CA1%u6709%u8FD9%u4E00%u6BB5%u4EE3%u7801%uFF0C%u5C31%u4F1A%u6742%u4E03%u6742%u516B%u51FA%u73B0%u5F88%u591A%u3002%u6240%u4EE5%u6211%u8BF4InputData%u7684top%20result%u5F88%u5173%u952E%u3002%0A%21%5BAlt%20text%5D%28./1469435667177.png%29%0A%23%23%23%23%u8C03%u8BD5%u5DE5%u5177%0A%u56E0%u4E3A%u6211%u4EEC%u662F%u63D2%u4EF6%u5F00%u53D1%uFF0C%u6CA1%u6CD5%u5728%u7EBF%u8C03%u8BD5%uFF0C%u53EA%u80FD%u7528%60qDebug%28%29%3C%3C%22proxy%3A%20%22%3C%3Cproxy%3B%60%u6253%u5370%u8C03%u8BD5%u8BED%u53E5%u3002%u53C8%u6CA1%u6709%u547D%u4EE4%u884C%u754C%u9762%uFF0C%u53EA%u80FD%u501F%u52A9%u4E00%u4E2A%u5FAE%u8F6F%u7684%u5DE5%u5177%u53EBDebugView%uFF0C%u5728%u4E0B%u9762%u7684%u5730%u5740%u4E0B%u8F7D%u3002%5BDebugView%u5B98%u65B9%u4E0B%u8F7D%u5730%u5740%5D%28https%3A//technet.microsoft.com/en-us/sysinternals/debugview.aspx%29%u3002%0A%u6709%u4E86%u4ED6%u5C31%u53EF%u4EE5%u770B%u8C03%u8BD5%u4FE1%u606F%u8F93%u51FA%u4E86%u3002%0A%23%23%23QT%u76F8%u5173%0A%23%23%23%23QT%u8C03%u7528python%0A%u5176%u5B9E%u5C31%u662FC++%u8C03%u7528python%u3002%u7F51%u4E0A%u641C%u5230%u7684%u4E00%u5806%u90FD%u5927%u540C%u5C0F%u5F02%u3002%u4E3E%u4E2A%u4F8B%u5B50%5BQT%u4E2D%20%u4F7F%u7528c++%u8C03%u7528python%5D%28http%3A//www.cnblogs.com/shenghl/p/4442528.html%29%u3002%u6700%u540E%u6211%u5931%u8D25%u4E86%uFF0C%u7F16%u8BD1%u6210%u529F%uFF0C%u8FD0%u884C%u5931%u8D25%u3002%u539F%u56E0%uFF0C%u6211%u603B%u7ED3%u4E86%u4E00%u4E0B%uFF0C%u5176%u5B9E%u548CQT%u4EE5%u53CAVS%u642D%u914D%u4F7F%u7528%u65F6%u7248%u672C%u7684%u95EE%u9898%u7C7B%u4F3C%u3002C++%u8C03%u7528python%u7684%u63A5%u53E3%u51FD%u6570%u90FD%u662F%u5728python27.lib%u4E2D%u5B9A%u4E49%u7684%u3002%u8FD9%u4E2Alib%u4F7F%u7528%u7684%u7F16%u8BD1%u5E73%u53F0%uFF0C%u8981%u548C%u4F60%u73B0%u5728%u4F7F%u7528%u7684%u7F16%u8BD1%u5E73%u53F0%u4E00%u81F4%u3002%u4E0D%u8FC7%u770B%u8D77%u6765%u86EE%u8BF1%u4EBA%u7684%uFF0C%u4E0D%u8FC7%u4E0D%u77E5%u9053%u6709%u591A%u5C11%u53EF%u80FD%u80FD%u7528%u5F97%u4E0A%u3002%0A%23%23%23%23QProcess%0A%u653E%u5F03python27.lib%u4E4B%u540E%uFF0C%u5C31%u8F6C%u5230QProcess%u4E0A%u6765%u4E86%u3002%u8FD9%u4E2A%u5176%u5B9E%u5C31%u662FQT%u7B80%u5355%u7684%u8C03%u7528%u547D%u4EE4%u884C%u7A0B%u5E8F%u3002%u4F46%u662F%u8FD9%u4E2A%u53D8%u6001%u7684%u662F%u4E00%u65E6%u547D%u4EE4%u51FA%u9519%uFF0C%u4EC0%u4E48%u4FE1%u606F%u4E5F%u6253%u4E0D%u51FA%u6765%uFF0C%u522B%u770B%u4ED6%u6709readStandardError%u63A5%u53E3%u3002%u5728%u4F7F%u7528QProcess%u7684%u65F6%u5019%uFF0C%u5B66%u4E60%u5230%u4EE5%u4E0B%u51E0%u70B9%uFF1A%0A1.%20Windows%u5E95%u4E0B%u5728%u4EE3%u7801%u91CC%u8981%u7528%u4E2D%u6587%u5FC5%u987B%u5728%u5B57%u7B26%u4E32%u524D%u9762%u52A0L%uFF0C%u5982%60L%22%u6709%u9053%u7FFB%u8BD1%22%60%u3002%u8FD9%u6837Windows%u624D%u80FD%u8BC6%u522B%u5230%u8FD9%u4E2A%u662FWCHAR%uFF0CWindows%u5E73%u53F0%u7684%u53CC%u5B57%u8282%u7F16%u7801%0A2.%20QT%u91CC%u9762%u6240%u6709%u7684QString%u90FD%u662Funicode%uFF0C%u5982%60QString%3A%3AfromWCharArray%28L%22%u6709%u9053%u7FFB%u8BD1%29%60%0A%23%23%23%23QJson%0A%u672C%u6765%u6253%u7B97%u627E%u4E00%u4E2A%u5E93%u6765%u89E3%u6790%u6709%u9053API%u8FD4%u56DE%u7684json%u6570%u636E%uFF0C%u4E0D%u8FC7%u540E%u6765%u672C%u7740%u5C0F%u800C%u7F8E%u7684%u7CBE%u795E%uFF0C%u653E%u5F03%u4E86%u89E3%u6790%u6574%u4E2Ajson%u6570%u636E%u7684%u4F01%u56FE%uFF0C%u53EA%u5355%u7EAF%u7684%u89E3%u6790%u591A%u884C%u5B57%u7B26%u4E32%u3002%u4E0D%u8FC7%u8FD8%u662F%u770B%u4E86%u4E00%u4E9B%u8D44%u6599%uFF0C%u6240%u4EE5%u8BB0%u4E0B%u6765%u4E07%u4E00%u4EE5%u540E%u7528%u5F97%u4E0A%u3002%0A%5BQJson%5D%28https%3A//github.com/flavio/qjson%29%u662F%u4E00%u4E2AQT%u7684%u5F00%u6E90%u5E93%uFF0C%u5728git%20hub%u4E0A%uFF0C%u9700%u8981%u4E0B%u8F7D%u6E90%u7801%u81EA%u5DF1%u7F16%u8BD1%u3002%u7F16%u51FA%u6765%u4F1A%u6709%u4E00%u4E2A.lib%u548C%u4E00%u4E2A.dll%u3002%u5206%u522B%u653E%u5230C%3A%5CQt%5C4.6.0%5Clib%u548CC%3A%5CQt%5C4.6.0%5Cbin%5C%u5E95%u4E0B%uFF0C%u5E76%u5728.pro%u6587%u4EF6%u91CC%u5F15%u7528%u5C31%u53EF%u4EE5%u7528%u4E86%u3002%u8BB0%u5F97%u54E6%uFF0C%u4E0E%u4F60%u7684%u4E3B%u7A0B%u5E8F%u7528%u540C%u4E00%u4E2A%u7F16%u8BD1%u5E73%u53F0%u3002%u53E6%u5916QT5%u5DF2%u7ECF%u9ED8%u8BA4%u5185%u7F6Ejson%u89E3%u6790%u5E93%u4E86%u3002%0A%u4F7F%u7528QJson%u7684%u65B9%u6CD5%u770B%5B%u5B98%u65B9%u6587%u6863%5D%28http%3A//qjson.sourceforge.net/docs/%29%0A%u53E6%u5916%u4E00%u79CD%u89E3%u6790json%u6570%u636E%u7684%u601D%u8DEF%u662F%u7528QT4%u5185%u7F6E%u7684QScriptEngine%u3002%u6CA1%u6DF1%u7A76%u8FC7%uFF0C%u4F46%u77E5%u9053%u8FD9%u4E2A%u5E93%u662F%u8BA9QT%u66F4%u597D%u5730%u548CJavaScript%u878D%u5408%u4F7F%u7528%u8BDE%u751F%u7684%uFF0C%u5177%u4F53%u53EF%u4EE5%u770B%u8FD9%u4E2A%u94FE%u63A5-%5BQScriptEngine%20Printout%20to%20String%20as%20JSON%5D%28http%3A//www.qtcentre.org/threads/30874-QScriptEngine-Printout-to-String-as-JSON%29%0A%23%23%23%u4E00%u4E9B%u6709%u7528%u7684%u94FE%u63A5%0A-%20%5B%u5728%u7EBF%u7F16%u7801%u89E3%u7801%5D%28http%3A//bianma.911cha.com/%29%0A-%20%5BJS/HTML%u683C%u5F0F%u5316%5D%28http%3A//tool.chinaz.com/Tools/jsformat.aspx%3Fjdfwkey%3Dwslz01%29%0A%0A