之前寫過一篇隨筆《剪刀剪紙》是給一些新同事講面向對象時用的,當時就感覺有些不順暢,不過用來給新同事入門足夠了就沒多想,最近看書時偶爾走神把這件事想起來了,順便群里討論時談到聚合之間的方法調用,于是決定寫一篇博客糾正一下那篇隨筆里的問題。
開頭先聲明一下,以下只是個例子,只是用來說明對象間交互的解耦,怎么樣交互我覺得更好,但是如果是真的要寫一個剪刀剪紙的程序,之前隨筆的做法并不一定就是不好的,有些耦合只是在需要解的時候才應該去解。另外,以下做法只是理想的做法,但是現實的項目總會有各種各樣的妥協,所以主要還是隨機應變,沒有最好的做法,只有最合適的做法,聲明暫時結束。
在剪刀剪紙的隨筆里寫了:剪刀只需要關心自己發出了剪的動作,不需要關心紙,于是給紙抽象了一個東西的基類。但是回頭細看其實這并沒有解決問題,剪刀雖然沒有和紙發生耦合,但是和東西發生了耦合,剪刀本身并不一定要剪東西,說不定就是個工藝品呢,剪刀剪紙隨筆中剪子的Cut(Thing thing)方法參數選擇了Thing等于將剪刀內部的邏輯對Thing公開了一部分,這種做法已經破壞了剪子的封裝,同時也表達了一種業務邏輯,既剪刀剪東西,而且Thing也已經不是單純的東西的概念,而是被剪子剪的東西。如果是一個初學者做項目,這么做問題或許不大,但是深究這種做法從某種角度來說是錯的。
上面一段說出的問題概括一下:
1.剪刀和Thing(以下所說的Thing都代表”被剪的東西“這個概念)的耦合是多余的,如何讓剪刀和Thing各自獨立;
2.在需要的時候,剪子和Thing可以交互完成剪東西這一業務。
上面說了Cut的參數使用Thing破壞了封裝,如果做好封裝的話就可以解決上面的第一個問題。做好封裝也就是說剪刀只包含自己的職責,也就是抽象好自己的職責,封裝和抽象是相輔相成的存在。仔細思考下,剪子的職責應該是什么的,可以用來剪東西只是說明了它可以做什么,諾基亞還可以用來砸核桃(其實還有用來開核桃的模特模型,你懂得。。。),但你能說砸核桃是諾基亞的職責么,那剪刀的職責是什么,很明顯沒Thing那就一定是剪了,怎么表達這個剪呢,那就是發出一個剪的作用力,所以,我們可以增加一個作用力的對象,當然如果非要較真,作用力和剪刀還是有耦合,不過剪刀本就是接受并傳遞作用力的,作用力只是參數,而且作用力在這個業務場景中也是在一個工作單元里傳遞業務狀態變化的根本,整個業務其實就是由作用力驅動的,其實這個作用力用命令模式的命令來表達或許更貼切,不過這里就不細說了。
?
//關于命名,我是故意的,原因不想說,你們千萬別學,作用力的意思public class KineticEnergy{public int Size { get; set; }public struct Point{public int X { get; set; }public int Y { get; set; }}}
? 然后是剪刀的:
public class Scissors{private KineticEnergy _kineticEnergyBeUsed { get; set; }public void Stress(KineticEnergy kineticEnergy){_kineticEnergyBeUsed = kineticEnergy;}public KineticEnergy SendCutEnergy(){return SwitchKineticEnergy();}private KineticEnergy SwitchKineticEnergy(){KineticEnergy kineticEnergyBeCut = _kineticEnergyBeUsed;//作用點和力的大小等變化return kineticEnergyBeCut;}}
至于Thing還是看剪紙那篇隨筆的,基本就是那意思,代碼就不改個名重貼一遍這么費事了。
下面就是第二個問題了,想必大家也看出來了,第二個問題基本上也不是問題了,剪刀剪一次紙的過程我們可以用一個工作單元來表示(我偷懶,傳遞的力一直在改變,但是反正重點不在這,就不要在意這些細節了):
//工作單元UOW三個單詞不是這么寫的,看到的注意,別學!!!public class CutThingsWorkUnit{private KineticEnergy _kineticEnergy;private Scissors _scissors;private Thing _thing;//剪刀和Thing應該由業務場景的Context來提供public CutThingsWorkUnit(Scissors scissors, Thing thing){_scissors = scissors;_thing = thing;}public void Execute(){//這里的人,那篇隨筆我已經給抽象掉了,放這里就是個意思,隨便實例化一下,這種細節就不要在意了Person person = new Person();_kineticEnergy = person.UseScissorsKineticEnergy();_scissors.Stress(_kineticEnergy);_kineticEnergy = _scissors.SendCutEnergy();_thing.Stress(_kineticEnergy);}}
最后,至于這東西被剪的結果,剪紙那篇隨筆說過,就不再說了。
?
?
?
?
?