---
# System prepended metadata

title: 物件導向
tags: [OOP]

---

# 物件導向 

###### 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 
```

