2018年3月22日星期四

Object Oriented Programming ( java )?先放下,現在砌模型,玩遊戲

cover

事先聲明,不是教大家組裝精美模型,只是想透過組裝模型,說明 object oriented 這種程式設計概念。一半加餸,一半炒冷飯,換個例子,加點新意,編寫新文章。

文章很長,有很多概念上的東西學,一定要一邊動手試,一邊思考為甚麼,有沒有其他用法之類。總言之,別急,看一次是學不會,看多幾次也是學不好,object oriented programming 要靠實踐及知識基礎才可以學好,兩者缺一不可。

多去 GitHub 看看別人怎用 object oriented,有時候會看到你意想不到的用法,看到像魔術一樣的用法後,可能會知道自己還有所欠缺的知識,因為無知才覺得像魔術,知道原理後,這只是個掩眼法。

例子程式碼 ( V1_gunpla_example )
https://github.com/IntegrityKnight/java_object_oriented/releases/tag/V1_gunpla_example

===============================

事前準備︰


雖然廢話,但你需要準備兩盒或三盒模型或曾經砌過模型,不是甚麼模型都可以,這裡選擇 EW-5 及 EW-1 模型。對 Bandai 沒興趣,可以選 Good Smile Company 黏土人系列。

沒有互換性的模型,很難解釋 object oriented 概念。

===============================

互換性︰


解釋甚麼是【互換性】之前,先了解 parts 及 interface 關係。

模型視點的 parts︰



頭、手、腳、身、背包都叫做 parts ( PSV 遊戲《GUNDAM BREKAER 3》)。

模型視點的 interface︰


model_1.png

遊戲中,可以把 1/100 比例的手,安裝在 1/144 比例身體 ……
現實中的模型是不可能,因為 interface 不同,用遊戲作比喻,只為了大家比較好想像。

model_2

回到現實模型制作,interface 是指 parts 與 parts 之間的連接,可以用 1/100 EW-5 手,接上 1/100 EW-1 身體。

model_3

為什麼可以接上?因為 parts 用了【標準及統一】的接位。

 model_4.png

理論上,只要接位 ( interface ) 匹配,甚麼 parts 都能接上去,這是互換性。

炒冷飯


標準 ( standard )、模組化 ( modularize )、重用( Reusable )


想一想以前冷飯,發現甚麼?

  • parts = modularize

  • standard interface

  • Reusable parts

model_5
http://www.1999.co.jp/eng/image/10024155/70/5

砌模型跟砌 program 很相似。

====================== ( 補充 start ) ======================

複雜度 ( complexity ) 與 重用 ( Reusable )


  • Good Smile Company 黏土人

  • 素組 Bandai GUNPLA

  • Lego 積木

做複雜度排名看看吧

Lego > GUNPLA > 黏土人

Lego 雖然能砌到很多東西,但要一小件一小件砌,變化多,相對複雜。
GUNPLA 沒 Lego 靈活,不過還是可以在 GUNPLA 之間互換,平衡了複雜度與重用。
黏土人能換臉換配件,不過互換性不及 GUNPLA 高,又不至於完全無法跟其他黏土人互換,只是 parts 不夠通用。

不明白,沒關係,寫程式經驗累積下來,自然會懂。

====================== ( 補充 end ) ====================

砌模型到砌 program ( object oriented programming )︰


四個 object oriented programming 特性︰


  • Abstraction
  • Encapsulation
  • Inheritance
  • Polymorphism

沒有明確界線,四個特性混合使用。

The Java™ Tutorials
https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html

==========================================

封裝一 ( Encapsulation )︰


Java 代表, POPJ ( Plain Ordinary Java Object )。
Encapsulation,不需要知道如何制作及處理,只需要知道輸入甚麼,輸出甚麼即可。
這樣做有甚麼好處?需要知道的東西變少,專注學習使用。

model_6.png

以砌模型為例,制作【手】這個 module ( 或叫做 parts )。

看,左圖的制作步驟多複雜,但你只需要知道右圖,把各 module 組裝起來就好 ( 頭、手、腳、身、背包 patrs )。

事先或前人,把左圖的【手】造好,現在只需要「使用」它 ( 寫程式一定有聽過 framework 及 library 之類,有各式各樣叫法,概念大同小異,重點是 reuse )。

=================== ( 補充 start ) ========================

module 化後,還有多個好處︰容易測試、容易發佈。#

【divide and conquer】這個名詞不知有沒有聽過,意思是把問題拆細,逐一解決後,再結合成一個。
這個方法也適用於 programming,把【system】拆細為【function】,逐一解決後再做成【module】,把各個【module】結合成【system】。日後再說 Unit test 等等問題,現在專注 object oriented。

==================== ( 補充 end ) =======================

虛化一 ( Abstraction )


之前 Encapsulation 裡說過「使用」它,怎用法?在「使用」之前,首先要知道如何「制作」。
出現矛盾,之前也說過「不需要知道如何制作及處理,只需要知道輸入甚麼,輸出甚麼即可」……

「先有雞還是先有蛋?」…… 在「使用」之前,首先「有」parts 可用。在沒有合適 parts 的程況下,「造」parts 是唯一選擇,所以了解如何「制作」,是一個必經階段。

定義 ( Define ) 


Define Interface


create_interface.PNG

「interface 是指 parts 與 parts 之間的連接」。定義一個叫 「PC_C」的 Interface Class,這是個 Object。

Define Object 


create_class.PNG

Object 是甚麼?Object 甚麼都可以,可以是實體,可以是概念,也可以是服務,所以先把這個 Object 想像成一個 java 檔尾的電腦檔案,建立 Object,把這個定義成【Ew5_Left_Arm】的 Class。

impl_class_1

修改程式碼,【Ew5_Left_Arm】用【PC_C】Interface 接合。

===========================================

封裝二 ( Encapsulation )︰ 


Game_2.png

javabean_1

定義好【Ew5_Left_Arm】及【PC_C】外殼後,要定義內涵。

【Ew5_Left_Arm】應該存放以下資料 ( Define Fields )

  • code_name
  • gundam_name

【PC_C】會作為以下部件的接合處

  • BODY
  • ARMS

javabean_2.png

【Ew5_Left_Arm】能做甚麼?可以做甚麼? ( Define Methods )

設定及取得機體名稱︰

  • getGundam_name ()
  • setGundam_name ( String gundam_name )

設定及取得機體代號︰

  • getCode_name()
  • setCode_name ( String code_name )

請參考 JavaBeans︰
https://en.wikipedia.org/wiki/JavaBeans

Getting and Setting Field Values
https://docs.oracle.com/javase/tutorial/reflect/member/fieldValues.html

==========================

虛化二 ( Abstraction )


Game3.png

【Ew5_Left_Arm】雛型做好,造【Ew1_Left_Arm】看看。
【Ew5_Left_Arm】及【Ew1_Left_Arm】,除造型外,有甚麼共通之處?

Game2.png

長遠想法,Gunpla 不只這兩隻,未來還有更多。Gunpla 大部份都有【手】,但肯定設定不會一模一樣,甚麼是【通用】,甚麼是【特化】呢?reuse【通用】部份,補上不足或需要修改的【特化】。

==========================

承繼一 ( inheritance )


Game_4

紅框部份之前造好,【特化】部份為水藍框。

inheritance_1.png

把【通用】部份拆出來。

inheritance_2.png

【Ew5_Left_Arm】 承繼 【GunplaArm】並填上【特化】部份。

Game_5

reuse【通用】部份,去造【Ew1_Left_Arm】。
【Ew1_Left_Arm】承繼 【GunplaArm】及補上【特化】。

==========================

多型 ( Polymorphism )


Polymorphism_1.png

Ew1 及 Ew5 手都造好,是時候做身體看看。
跟之前方法一樣,先定義有甚麼 ( Define Fields ),然後定義可以做甚麼 ( Define methods )。
其實 fields 包括 code_name 及 gundam_name,現在簡化了 GunplaBody,只定義兩個 methods。

====================( 補充 start)====================

談 Polymorphism 前,要清楚 java 語言特性及名詞,這裡就不詳述了,自己看︰

Object type
https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html

instanceof
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

method signatures 及 overloading
https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html

===================( 補充 end )===================

有兩個 method,method signatures 如下︰

  • public void concatenate(PC_C leftArm)
  • public void concatenate(GunplaArm leftArm)

這是 overloading,可用不同的 Object type 接收 Object reference。
寫個測試看看。

 Polymorphism_2.png

從結果看,object instance 可用不同 object type 接著,如果有看過之前的參考網址,可以改造成 instanceof 做測試。

用不同的 object type 接著 object instance 有甚麼用呢?這才是混亂的開始……

=======================================

承繼二 ( inheritance )


inheritance Class 或 implement interface 後,java 還可以做 overriding︰

====================( 補充 start )====================

要了解 Java 特性 ( 限制? ) 才能繼續下去,例如只能 inheritance 一個 Class,一定要補足所有 methods 內涵才可 new instance 等等。

Multiple Inheritance of State, Implementation, and Type
https://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html

Abstract Methods and Classes
https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

Interfaces
https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html

Object as a Superclass
https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html

overriding
https://docs.oracle.com/javase/tutorial/java/IandI/override.html

===================( 補充 end )===================

Polymorphism_1.png

toString() 這個 method 是怎來的?如果有看補充資訊,這個 method 來自 Object Class,是一個必定會承繼的祖宗。再看一下之前測試結果︰
  • hk.blogspot.javatoybox.simgunpla.Ew5_Left_Arm@70dea4e
這句就是來自 toString(),是不是很礙眼?可以用 override 改寫它。

Polymorphism_3.png

在【GunplaArm】空白的地方右鍵跟圖做。

Polymorphism_4.png

要 Overrid Object Class 的 toString(),加在 setGundam_name() 後。

Polymorphism_5.png

改造成這樣。annotation 是 jdk 1.5 後,新加的功能,很強大,有時間該研究這個配合 reflection 怎用。

Annotations Basics
https://docs.oracle.com/javase/tutorial/java/annotations/basics.html

===========================================

Object Oriented 技術綜合運用


會 git,去 clone repo,不會 git,直接下載程式碼。

Repository
https://github.com/IntegrityKnight/java_object_oriented

修改後的例子程式碼 ( V2_gunpla_example )
https://github.com/IntegrityKnight/java_object_oriented/releases/tag/V2_gunpla_example

===================( 補充 start)===================

比較程式碼


compare.png

用 git 有甚麼好處?比較上一版本程式碼,看看改了甚麼。現在只有四個 java 檔,當然沒有問題,但有過百個 java 檔項目,怎用人力去找【不同之處】,【找錯處遊戲】我不玩了,只想知道改了甚麼。

===================( 補充 end )===================

result.png

話不用多說,動手試,看程式碼,思考以下四點︰
  1. new instance 甚麼 Class

  2. 用甚麼 object type 接 instance

  3. Call Super Class method OR Sub Class method

  4. 結果
==========================

總結︰


先要學 Software engineering 理論,Object-Oriented Analysis and Design ( OOAD ) 方法,最後才到 object oriented programming ( OOP ) 實現,要學思考方式、研究方法,懂得把問題拆件及組合 ( divide and conquer )。

這裡已經跳過 Software engineering 解說、歷史、問題的由來、技術負債、UML 等等,全都沒有說,直接跳進 OOAD 及 OOP。這樣會根基不穩,問題只要稍微轉個灣就應付不了,有時間的話,回去補習 Software engineering 這方面智識,這裡不會解說太多。

用 java 介紹如何實現 object oriented 是關符語言特性,文章的連結過於碎片化,不能有效了解 java,所以學 java 最好由頭學起,不是教寫程式那種,而是考 ocpjp 認證那種學習。比起網上零碎的教學,統整後的書籍,確實又全面又有效率。

如果 object oriented 及 java 有足夠經驗,可以跳步,直接定義 Object、fields、methods 及 interface,一步到位,不用一直  refactor,我用 refactor 目的是為了給大家希望,程式碼寫爛了,也能修正過來,即使是我,也有寫爛程式碼的時候,畢竟我曾經新手過,共勉之。

沒有留言:

發佈留言

設有留言驗證及審查,檢閱後,才會顯示留言。
本人惰性很高,留言或許會石沉大海。