作者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
1F:推 lancelotte:写个简单又清楚:) 12/14 16:59
2F:推 chrisQQ:好文推! 12/14 17:24
3F:→ LoveCheer:有些引数传递的地方写反了 还有一些名词前後不太一致@@ 12/14 19:27
感谢提醒!已经修改 不过名词是指?^^"
4F:→ LoveCheer:^^" 谢谢你花时间修改 ex: charUseSword 前面没有宣告 12/14 20:00
5F:→ LoveCheer:我最近也在思考复合跟转发的问题 还掌握不到精髓所在 12/14 20:02
6F:→ LoveCheer:我在想是不是可以将各职业写成interface呢? 12/14 20:04
7F:→ LoveCheer:class player extends Character implements 魔法, 剑士 12/14 20:07
8F:→ LoveCheer:这样就可以有复合职业了(像DQ一样A_A) (抱怨:推文等好久 12/14 20:09
已经修改好了 感谢 你要考虑is-a 跟 has-a的关系喔!
※ 编辑: givemepass 来自: 61.62.45.162 (12/14 20:28)
9F:推 tomap41017:推强大说明 12/14 22:55
10F:推 solomn:推 12/15 09:04
11F:推 lovelycateye:好文推 12/15 10:52
12F:→ LoveCheer:我是有在JAVA版看你文章的人@@ 12/15 22:21
13F:→ LoveCheer:回水球变推文@@ 12/15 22:22
14F:推 LoveCheer:推大大! 太开心了 经由跟大大学习我终於明白了! 12/16 09:49
15F:→ LoveCheer:复合+多型是为了改良 文章前半部使用多型的方式 12/16 09:52
16F:→ LoveCheer:请问是说未来遇到要使用多型时 都尽量改以复合+多型 吗? 12/16 10:10
17F:推 dream1124:策略模式 12/16 12:23
18F:→ givemepass:是策略模式没错 12/16 14:30
19F:推 computer5566:推 12/16 16:54
20F:推 tkhunter:好文,该m起来 12/18 19:31
21F:推 papayamilk:推 04/20 21:17
22F:推 dick51207:推 写的好棒!! 08/19 12:42