# 物件導向 ###### tags: `OOP` Object-Oriented programming (oop) ## 為什麼要有OOP? 因為程式碼很分散, code散落各地,而且語意更好懂. 透過把function在集中一次的方式,並用object來集合這些function比較貼近我們生活的樣貌. ### 重要的兩個概念: Class和Instance. #### 工作上的時候,要去想別人該怎麼call這個function比較方便去著手設計Class ## Class 類別 類別比較算是一個設計圖,裡面定義好該有的屬性和方法 ```php class Dog { //在類別裡面的function稱之為方法,此例就是說hello是dog的一個方法 function hello(){ echo 'i am dog' } } ``` ## instance 實體 有了設計圖,那我要實際打造一隻狗出來,有了設計圖不能改變構造,只能把想要的方法加進去. 就像有室內設計圖,但是傢俱擺設可以自由更換 ```php //a 是這個Dog的實體 $a = new Dog(); $a -> hello(); ``` ## public 有了public,可以從外部呼叫這個方法 ```php //預設是用public class Dog { public function hello(){ echo 'i am dog' } } ``` ## private 不可以從外部呼叫這個方法 ```php //預設是用public class Dog { private function hello(){ echo 'i am dog' } } ``` ### 為什麼需要一個無法呼叫的private? 因為封裝(Encapsulation),,你需要用的時候呼叫就好,不需要知道底層怎麼做的. 細節都隱藏好了,只需要call你要的東西就好了. ```php //預設是用public class Dog { public function hello(){ $this-> getHelloSentence(); } private function getHelloSentence(){ return 'i am a dog ' } } ``` ```php $a = new Dog(); //初始化 $a -> hello(); // i am a dog. ``` > 簡單來說就是抽象(Abstract)的概念。對一件事情只需要理解他的外在就好,不需要了解裡面內部的構造。 就像我們只要知道看電視的時候該怎麼轉台、調音量,並不需要知道裡面有多少電線和構造。 > 在類別裡面,透過 private 與 public 的宣告方式,替方法加上限制與規範,程式撰寫人員只要遵循規範,就能使用類別的方法,而不需要知道這些方法是如何去實作的。這樣的行為,是 OOP 的特色之一:封裝。 #### 一個class可以new出很多instance, 而每一個instance可以new出很多自己的資料. ```php class Dog { public $name = 'default'; public function hello(){ $this-> getHelloSentence(); } private function getHelloSentence(){ return 'i am ' . $this -> name } } ``` ```php $a = new Dog(); $a-> name = 'leo'; $a -> hello(); // i am leo ``` ```php $a = new Dog(); $a-> name = 'leo'; $b-> name = 'hello'; $b-> hello(); $a -> hello(); // i am hello i am leo ``` 以上範例就是在說,同一個設計圖可以產生多個東西,就像是一個模板在那邊一樣. #### 一般來說,都用成public不常見,所以最後都會包成一個方法 ```php class Dog { private $name = 'default'; public function hello(){ $this-> getHelloSentence(); } private function getHelloSentence(){ return 'i am ' . $this -> name } //setter public function setName($name){ $this-> name = $name; } //getter public function getName($name){ return $this-> name; } } ``` ```php $a = new Dog(); $a-> setName('leo'); $b-> setName ('hello'); $b-> hello(); $a -> hello(); // i am hello i am leo ``` ### 為什麼要包成function? 直接讓外面call就好啊? 1. 設定條件(if/else) 2. 檢查機制(不能寫髒話) 3. 保護裡面的東西不被外面用到 例如: ```php public function setName($name){ if($name === 'fuck') return; $this-> name = $name; } ``` ## __construct 建構子(每一個程式語言的語法都不太一樣) - 建構子就像是我在初始化的時候,已經對這個instance給定了一個屬性 ```php class Dog { public $name = 'default'; public function __construct ($name){//建構子 $this-> name = $name; $this-> hello(); } public function hello(){ $this-> getHelloSentence(); } private function getHelloSentence(){ return 'i am ' . $this -> name } } ``` ```php $a = new Dog('leo'); //直接new出來的時候,就已經初始化這隻狗叫做leo了 $a -> hello(); // i am leo ``` ### 其實在javaScript中, 沒有class這個語法,也沒有private, public. 用constructor前不需要加上function. ==在Javascript語言中,new命令後面跟的不是類,而是構造函數。== 以底下計算機為例: ```javascript= class Calculator(){ constructor(name){ this.name = name; } hello(){ console.log(this.name) } } ``` ```javascript= const calculator = new Calculator('my calculator') calculator.hello() // my calculator // instance 就是object // 執行hello, console出this.name, this.name= my calculator ``` ## 計算機範例超經典的 ```javascript= class Calculator(){ constructor(){ this.text = ''; } input(str){ input.text+=str } getResult(){ return eval(this.text) } } ``` ```javascript= const calculator = new Calculator(); calculator.input(1) calculator.input('+') calculator.input(3) const result = calculator.getResult() console.log(result)// 4 ``` ## inheritance 繼承 > 繼承(Inheritance),要設計一張和原有設計很像的設計圖,可以拿原本的設計圖當底開始畫 狗也是動物,所以可以繼承這個class所有的東西 當想要改變一些東西,可以用繼承的方式,保持原有的東西,但可以做細節上的修改 ```php class Animal{ public $name = 'default'; //初始化 public function __construct ($name){ $this-> name = $name; } public function sayHello(){ echo 'i am ' . $this -> name } } ``` ```php class Dog extends Animal{ public function run{ echo 'i am running'; } } ``` ```php $a = new Dog('leo'); $a -> sayHello(); $a -> run(); // i am leo i am running ``` ### override 複寫 ```php class Animal{ public $name = 'default'; //初始化 public function __construct ($name){ $this-> name = $name; } public function sayHello(){ echo 'i am ' . $this -> name } } ``` ```php class Dog extends Animal{ public function run{ echo 'i am running' . $this -> name;//上面設定好下面的就可以用 } public function sayHello(){ echo 'i am a dog' } } ``` ```php $a = new Dog('leo'); $a -> sayHello(); $a -> run(); // i am a dog i am running leo ``` ### protected 從外面看是private, 但從父母和小孩來看是public ```php class Animal{ protected $name = 'default'; //初始化 public function __construct ($name){ $this-> name = $name; } public function sayHello(){ echo 'i am ' . $this -> name } } ``` ```php class Dog extends Animal{ public function run{ echo 'i am running' . $this -> name;//上面設定好下面的就可以用 } public function sayHello(){ echo 'i am a dog' } } ``` ```php $a = new Dog('leo'); //$a -> name(); 但還是沒辦法在外面呼叫 $a -> sayHello(); $a -> run(); // i am a dog i am running leo ``` ```php class Animal{ protected $name = 'default'; //初始化 public function __construct ($name){ $this-> name = $name; } public function sayHello(){ echo 'i am ' . $this -> name } } ``` ```php class Dog extends Animal{ public function run{ echo 'i am running' . $this -> name;//上面設定好下面的就可以用 } public function sayYoAndHello(){ echo 'yo'; } } ``` ```php $a = new Dog('leo'); $a -> sayYoAndHello(); // yo ``` ### parent用法 但是我還是想要呼叫Animal裡面的sayHello ```php class Dog extends Animal{ public function run{ echo 'i am running' . $this -> name;//上面設定好下面的就可以用 } public function sayYoAndHello(){ parent::sayHell0(); echo 'yo'; } } ``` ### 在javaScript中也想要繼承一下 ```javascript= class Calculator(){ constructor(){ this.text = ''; } input(str){ input.text+=str } getResult(){ return eval(this.text) } } ``` 中文計算機用繼承的方法 ```javascript= class ChineseCalculator extends Calculator(){ input(str){ if(str === "三"){ super.input(3) }else{ super.input(str) } } } ``` ```javascript= const calculator = new Calculator(); calculator.input(1) calculator.input('+') calculator.input('三') const result = calculator.getResult() console.log(result)// 4 ``` ## static 靜態方法 不是屬於這個instance而是屬於繼承底下的class. static 不需建立物件,可直接使用 ```php class Animal{ protected $name = 'default'; //初始化 public function __construct ($name){ $this-> name = $name; } public function sayHello(){ echo 'i am ' . $this -> name } } ``` ```php class Dog extends Animal{ public function run{ echo 'i am running' . $this -> name;//上面設定好下面的就可以用 } public function sayYoAndHello(){ echo 'yo'; } public static function test(){ echo 'test'; } } ``` ```php $a = new Dog('leo'); $a -> sayYoAndHello(); //給instance用的 Dog::test();// test ``` ### javaScript中的class,背後實作原理 原本是這樣(這是一般大眾的寫法) ```javascript= class Calculator(){ constructor(){ this.text = ''; } input(str){ input.text+=str } getResult(){ return eval(this.text) } } ``` ```javascript= const calculator = new Calculator(); calculator.input(1) calculator.input('+') calculator.input(3) const result = calculator.getResult() console.log(result)// 4 ``` 可以改成 ```javascript= //建構子 function Calculator(){ this.name = name this.text ='' } Calculator.prototype.input = function(str){ this.text+=str } Calculator.prototype.getResult = function(){ return eval(this.text) } ``` ```javascript= const calculator = new Calculator('name'); calculator.input(1) calculator.input('+') calculator.input(3) const result = calculator.getResult() console.log(result)// 4 ```