# 物件導向
###### 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
```