2012年7月12日 星期四

[轉錄]Re: [問題] 物件導向的好處是....

 作者  ie945167 (龍蝦)                                      站內  Lobster
 標題  [轉錄]Re: [問題] 物件導向的好處是....
 時間  2012/07/12 Thu 23:21:47
───────────────────────────────────────

※ 本文轉錄自 [Big-Bear] 看板

發信人: johnhao1206.bbs@ptt.cc (johnhao1206.bbs@ptt.cc) 看板: Big-Bear
標  題: Re: [問題] 物件導向的好處是....
發信站: 2012/07/12 Thu 17:19:50

作者: givemepass () 看板: java
標題: Re: [問題] 物件導向的好處是....
時間: Tue Dec 14 16:57:35 2010

※ 引述《kidd0730 (大阪掛川大不同)》之銘言:
: 我目前對物件的認知是可以延伸出很多類似的類別
: 比如人的物件  可以延伸出男人女人等類別
: 且可以擁有各自的屬性或行為
: 這樣就是物件導向  可以減少相同的code出現
: 如果我的認知沒錯的話
: 那問題來了
: 以前非物件導向的語言 透過method或是function的呼叫
: 不是也可以做到"類似"的功能嗎??
: 還是物件導向有其他更強大的地方呢?
強大的地方就是在多型!!

寫了一個例子 有點長 如果觀念有錯 請大家鞭策一下^^
假設你已經創造一個遊戲

裡面有一個角色是一個劍士

class SwordsMan{
    public String name;
    public SwordsMan(String userName){
        name = userName;
    }
    public void run(){
        System.out.println("跑");
    }
    public void fight(){
        System.out.println("揮舞劍");
    }
}

裡面又有一個角色是魔法師

class Magician {
    public String name;
    public Magician(String userName){
        name = userName;
    }
    public void run(){
        System.out.println("跑");
    }
    public void fight(){
        System.out.println("魔法攻擊");
    }
}

這時候你就會想到 每一個角色當中 都有重複的跑方法
這樣好了 我就寫一個方法 然後讓所有的角色來繼承(inheritance)
於是就寫出了這樣的程式

class Character{
    public String name;
    public Character(String userName){
        name = userName;
    }
    public void run(){
        System.out.println("跑");
    }
    public void fight(){}
}

因為每個角色的攻擊方式都不一樣
然後所有的角色都去推翻fight()這個方法(覆寫)

class SwordsMan extends Character{
    public SwordsMan(String username){
        super(username);
    }
    public void fight(){
        System.out.println("揮舞劍");
    }
}
class Magician extends Character{
    public Magician(String username){
        super(username);
    }
    public void fight(){
        System.out.println("魔法攻擊");
    }
}
..其他角色同樣繼承覆寫...

這時候 只要將魔法師 、劍士或其他角色實體化(instance)
就可以使用各自的方法了

可是這樣會出現一個問題,就是程式靈活度不夠,
想看看今天我有50個角色,裡面有20個角色攻擊都是揮舞劍,
這樣我每個角色都要去覆寫fight()不就累死了,

再說,如果我要修改每一個揮舞劍的角色改成揮舞刀,
那這樣也是會浪費很多時間,
所以我們就必須要把常常會變動的部分取出來,

所以我們將fight()拿出來寫成介面(interface)

interface class FightMethod{
    public void fight();
}

然後我們用SwordsMan這個類別去繼承它嗎?
不!

我們已經繼承Character, Java不允許多重繼承
所以我們實作(implement)它嗎?
不!這樣跟剛剛覆寫fight()方法不就一樣的問題?
複合才是我們要的答案!

我們定義一個使用劍的類別去實做它

class UseSword implements FightMethod{
    public void fight(){
        System.out.println("揮舞劍");
    }
}

然後在劍士的類別改成這樣

class SwordsMan extends Character{
    private UseSword charUseSword;
    public SwordsMan(String username){
        super(username);
        charUseSword = new UseSword();
        charUseSword.fight();
    }
}

這樣寫很有問題! 什麼問題?

回想剛剛的問題,又在這裡發生了,這樣每一個角色都必須宣告一個攻擊的物件,
並且配置實體給它,那100個角色仍然要配置100個實體,
你會累死...

怎麼辦呢?

多型就是用在這個地方
我們這樣宣告

FightMethod fm = new UseSword();
fm.fight();
FightMethod fm是形式型態的宣告,而
new UseSword()才是你實際型態的宣告。


關於多型(Polymorphism),「當某變數的實際型態(actual type)和形式型態
(formal type)不一致時,呼叫此變數的 method,一定會呼叫到「正確」的版本,
也就是實際型態的版本。

所以我們這樣就可以在Character類別直接這樣宣告

class Character{
    public String name;
    protected FightMethod fm;
    public Character(String userName){
       name =  userName;
    }
    public void run(){
        System.out.println("跑");
    }
    protected void useWeapon(){
        fm.fight();
    }
}

而在SwordsMan內直接這樣宣告

class SwordsMan extends Character{
    public SwordsMan(String username){
        super(username);
        fm = new UseSword();
    }
}

這樣劍士要改變攻擊方式就可以直接換成useKnife();
或者要增加一百個角色,也可以直接在介面上增加攻擊方式。
你看出多型的好處了嗎?

參考:
深入淺出JAVA(book)
深入淺出設計模式
歐萊禮網頁http://www.oreilly.com.tw/column_sleepless.php?id=j022
良葛格http://caterpillar.onlyfun.net/Gossip/JavaEssence/InheritanceWhat.html


--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.221.115.4
推 lancelotte:寫個簡單又清楚:)                                     12/14 16:59
推 chrisQQ:好文推!                                                12/14 17:24
→ LoveCheer:有些引數傳遞的地方寫反了 還有一些名詞前後不太一致@@   12/14 19:27
                                        感謝提醒!已經修改 不過名詞是指?^^"
→ LoveCheer:^^" 謝謝你花時間修改 ex:  charUseSword 前面沒有宣告   12/14 20:00
→ LoveCheer:我最近也在思考復合跟轉發的問題 還掌握不到精髓所在     12/14 20:02
→ LoveCheer:我在想是不是可以將各職業寫成interface呢?             12/14 20:04
→ LoveCheer:class player extends Character implements 魔法, 劍士  12/14 20:07
→ LoveCheer:這樣就可以有復合職業了(像DQ一樣A_A) (抱怨:推文等好久  12/14 20:09
已經修改好了 感謝 你要考慮is-a 跟 has-a的關係喔!
※ 編輯: givemepass      來自: 61.62.45.162         (12/14 20:28)
推 tomap41017:推強大說明                                           12/14 22:55
推 solomn:推                                                       12/15 09:04
推 lovelycateye:好文推                                             12/15 10:52
→ LoveCheer:我是有在JAVA版看你文章的人@@                          12/15 22:21
→ LoveCheer:回水球變推文@@                                        12/15 22:22
推 LoveCheer:推大大! 太開心了 經由跟大大學習我終於明白了!        12/16 09:49
→ LoveCheer:複合+多型是為了改良 文章前半部使用多型的方式          12/16 09:52
→ LoveCheer:請問是說未來遇到要使用多型時 都盡量改以複合+多型 嗎?  12/16 10:10
推 dream1124:策略模式                                              12/16 12:23
→ givemepass:是策略模式沒錯                                       12/16 14:30
推 computer5566:推                                                 12/16 16:54
推 tkhunter:好文,該m起來                                          12/18 19:31
推 papayamilk:推                                                   04/20 21:17
▋ ie945167 推:借轉 感謝~~~                                        12/07/12
▋ ie965225 推:其實我還是看不太懂 XD                               12/07/14
◤ ie945167 推:哈哈 我也是 不過最近剛好在看有相關的東西 XD         12/07/15

沒有留言:

張貼留言