2014年9月9日 星期二

Design Patterns Explained: A New Perspective Object-Oriented Design (一)

這本書跟一般講design pattern 的書不同
他帶領讀者思考pattern背後的基本原則和動機
不只學習design pattern,對OOP也會有更上一層的理解

繼承、封裝、多型

對這三個物件導向基礎提供了不同於常的見解
下面介紹這本書中一直強調的重心(個人見解)



1.single responsibility principle

簡單的來說就是一個物件只做一件事
這概念很簡單,但是要實行起來卻有一定的難度
像是clean code中,說了盡量不要使用switch
"因為這樣你就做了超過一件事"

??????????????????????????????

這是我看這一句當下的反應....
超過一件事??我看不出來阿??我覺得只做了一件事
但是仔細想想,通常我是怎麼用switch的
裡面塞東塞西(new 新物件、調整UI、改一下flag、加個if else)
甚至在別的地方又遇到同樣問題
然後就把要switch的變數設成global
繼續switch.....

之後沒完沒了,萬一有新需求
這裡加加,那裏減減
漏東漏西,要測試很多次才能確定還有沒有BUG
所以!!!!!!
這就是design pattern強大的地方了


2.encapsulation

這本書中一再強調封裝不只是public, protect, private
這只是以直觀的角度去思考封裝
封裝的概念可以更加抽象
我可以不知道你是甚麼東西(對物件封裝),也可以不知道你怎麼做(對行為封裝)
總之自己去做自己的事就對了
其他不需要知道的東西
全  部  都  藏  起  來



3.program to interface not implementation

這句話我一開始也是看不懂
只寫界面程式就可以跑了嗎???

現在舉個例子
設計出一個暗棋遊戲

在program to implementation中我會:
建立一個物件 chess
其中有屬性 name 表示他是帥還是象、車
                     image 表示他的圖像

好了設計完成!!
在main中建立全部棋子,通通用array存起來當成棋盤
再全部打亂,就可以開始玩拉
怎麼判斷誰可以吃誰?
就全部用if就好啦,每個棋子標上數字,誰大就誰贏
簡單又方便
每吃完一個就檢查一下是不是都吃完了
遊戲結束!!



這樣設計有沒有問題??
不會阿   怎麼可能會有問題

但是今天我想玩一個新玩法:
兵跟卒兩隻以上就可以合體成超級士兵(但是只能存在一回合):

兵 相                     相              相                     相
兵 士       =>    超 士     =>     超          =>    

完了,要改一堆if`,不然就乾脆另外寫一個新的遊戲規則比較快



你沒辦法要求不會有新需求
所以只能盡早的因應即將到來的需求



那如果是program to interface我會怎麼做?

首先想好這遊戲會有哪些功能、責任
1.棋子
2.棋子攻擊的規則
3.棋子行走的規則
4.棋盤
5.遊戲初始設定
6.遊戲勝利條件

這時候我又發現棋盤其實根本不用知道誰可以吃誰、誰可以怎麼走
而且要吃一個棋子之前一定要移動
所以也不用理攻擊規則

所以我就定義一個chessboard 物件
他所要做的事就只有提供空間給棋子=>getChessAt(x,y)、setAllChess()
以及哪個棋子要移動到哪 =>move(A,x,y)
至於這移動對不對,我就交給其他人去做

而這個人叫做 MoveRule,另外一個物件
負責管理這動作合不合乎規則
視情況會呼叫另一個物件AttackRule 
負責管理攻擊的規則

其它的就交給各人發揮



問題來了
這樣設計真的有比較好嗎??
講這麼多
到了MoveRule還不是要靠if判斷

但是!!情況不同了
現在來了上面新需求(超級士兵)
我只要把全部心力花在MoveRule跟AttackRule上面
棋盤、勝利條件我可以通通不要理他(因為責任已經分好)
而我的第一個做法(implementation)就要在main中做修改
改了這邊   另外一邊也要改(因為重複性)

又或者新需求來了
我不要只有4*8棋盤
我要多一個新的十字棋盤
第一個做法(implementation)就已經寫死了
移動、棋子本身全部都放在array裡面
要怎麼改??
把main從頭到尾看一次嗎?

如果是第二個做法
我就可以抽出一個抽象類別 abstractChessBorad
一樣有原本的方法
RectangleBoard,CrossBorad 就可以分別繼承他
MoveRule只知道棋子在abstractChessBorad上行走
根本不用知道棋盤長得怎樣

以上是我對這句話的理解

to be continue......


沒有留言:

張貼留言