{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# [X-Village] Lesson04-Overview and Encapsulation\n", "by 梁祐承" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 物件導向程式設計 OOP\n", "- Object-oriented programming\n", "- 以\"物件\"(Object)作為基本單位\n", "- \"物件\"(Object)具有函式(method)和資料(data)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 物件導向的精神\n", "- 封裝\n", "- 繼承\n", "- 多型" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 物件導向程式語言?\n", "- 支援Class (物件的模板)\n", "- Python / Java / C++ / ......" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 非物件導向程式語言?\n", "- 以C語言為例,C沒有直接支援Class\n", "- 但是你還是可以把C寫得很物件導向\n", "- 同理,Python也可以寫得很不OO" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 物件導向是種概念\n", "- 語言支援物件導向只是讓你可以方便使用Class\n", "- 重點是 \"物件導向設計\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 為何使用物件導向開發\n", "- 適合多人協作\n", "- 適合大型專案\n", "- 可維護性高\n", "- 減少不同程式碼互相干擾" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### 想像(一)\n", "- 現場有3個人拿著同一型號的手機\n", "- 但是容量/顏色不同\n", "- 剩餘電量也不同" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- \"手機\"是個\"物件\"\n", "- \"顏色/容量/電量\"是這個物件的\"資料\"\n", "- \"手機型號\"是Class\n", "- \"Class\" 可以生成多個 \"物件\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Practice 1 (15min)\n", "請設計一個Class `Car`,具有`Color`和`Speed`兩種data\n", "並用這個Class生成兩個`Car`物件,具有不同的`Color`且預設`Speed`為0" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### 想像(二)\n", "- 你走進一間空教室準備上課\n", "- 教室設備都沒有啟動\n", "- 你該做什麼" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "1. 把電燈打開\n", "2. 把冷氣打開\n", "3. 把投影機打開\n", "4. ......" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 回憶\n", "- 電腦Bootstrap\n", "- BIOS -> Bootloader -> OS -> ..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 但你是怎麼開電腦的?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "1. 按下開機鍵" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- \"電腦\"是個\"物件\"\n", "- \"開機\"是這個物件的\"函式\"\n", "- 函式可以對物件進行操作" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Practice 2 (15min)\n", "修改剛剛的Class `Car`,增加`boost()`和`step_break()`兩個函式,分別讓`speed`增加或減少" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 封裝 Encapsulation" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 存取權\n", "\n", "- 如果一台車不踩煞車直接讓速度變為0會發生什麼事\n", " - 人會飛出去\n", "- 所以我們需要保護`speed`不被任意修改" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "ename": "AttributeError", "evalue": "'Car' object has no attribute '__speed'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0mredCar\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Red'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mredCar\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mboost\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mredCar\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__speed\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Car' object has no attribute '__speed'" ] } ], "source": [ "class Car:\n", " color = None\n", " __speed = None\n", " \n", " def __init__(self, color, speed=0):\n", " self.color = color\n", " self.__speed = speed\n", " \n", " def boost(self):\n", " self.__speed += 1\n", " \n", " def step_break(self):\n", " self.__speed -= 1\n", " if self.__speed < 0:\n", " self.__speed = 0\n", " \n", "redCar = Car('Red')\n", "redCar.boost()\n", "print(redCar.__speed)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## OOPs" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Getter/Setter\n", "- 雖然保護了`speed`, 但還是要讓外界能拿到他的值\n", "- 也要保留可以讓外界修改的空間\n", "- 保留Getter/Setter可以在外部存取時做控制,不超出設計預期範圍" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Practice 3 (20min)\n", "修改剛剛的Class `Car`\n", "1. 增加`get_speed()`函式,回傳Car的`speed`\n", "2. 增加`set_speed(newspeed)`函式,若傳入的`newspeed`超過100或小於0就印出錯誤訊息並不要修改`speed`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 隱藏實做細節\n", "- 你的Class 可能有很多功能,但使用者不需要知道所有細節\n", "- 按下開機按鈕就可以開電腦,我不用知道Bootstrap的那一大堆東西!!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Practice 4 (10min)\n", "修改下一頁Code,新增`boot()`函式隱藏開機細節" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Power turned on\n", "BIOS loaded\n", "Bootloader loaded\n", "OS loaded\n", "Boot complete\n" ] } ], "source": [ "import time\n", "\n", "class Computer:\n", " def poweron(self):\n", " pass\n", " def load_BIOS(self):\n", " time.sleep(1)\n", " def load_bootloader(self):\n", " time.sleep(1)\n", " def load_OS(self):\n", " time.sleep(3)\n", " \n", "pc = Computer()\n", "pc.poweron()\n", "print('Power turned on')\n", "pc.load_BIOS()\n", "print('BIOS loaded')\n", "pc.load_bootloader()\n", "print('Bootloader loaded')\n", "pc.load_OS()\n", "print('OS loaded')\n", "print('Boot complete')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Class 設計" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "###### 決定所需的 Data\n", "- 各class管理自己所需的Data\n", "- 若不同的Class有許多相同的data,可以考慮之後提到的繼承\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "###### 決定 Data能見度\n", "- 哪些Data完全不該被外部存取\n", "- 哪些Data應該透過getter被讀取\n", "- 哪些Data可以透過setter被賦值\n", "- 哪些Data可以被自由存取" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "###### Data 能見度取捨\n", "- 有些人認為所有Data都不該被外部直接存取\n", " - 優點?\n", " - 缺點?\n", "- 有些人把所有Data開放給外部存取\n", " - 優點?\n", " - 缺點?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "###### 決定所需的 Method\n", "- 如何控制Data\n", "- 如何包裝各種操作\n", "- 減少Code重複性\n", "- 善用內部 Method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Practice 5\n", "考慮以下小遊戲:\n", "```\n", " ------\n", " |敵人|\n", " ==================== =====\n", "起 玩 終\n", "點 家 點\n", " =============================\n", " \n", " X軸座標 ---->\n", "```\n", "\n", "請設計玩家和敵人的class\n", "- 玩家要可以移動\n", "- 玩家具有HP\n", "- 玩家具有座標\n", "- 敵人有攻擊力\n", "- 敵人有攻擊狀態和休息狀態" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }