オブジェクト指向をプログラミング初心者が勉強してみた

#オブジェクト指向とは?

##オブジェクト指向

オブジェクト（モノ）を中心とした指向。モノづくりの考え方にのっとり、無駄を省き、使いやすいシステムを構築するための考え方。

##オブジェクト指向のメリット
**予め変更が予想される個所をクラスとしてまとめておくことで、柔軟に変更に対応できる。**
では、そのために何が必要か

1. カプセル化...外部から見て、抽象的でわかりやすいものを作る。アクセスを制限することで、修正を最低限に抑えること。外部に不必要なメソッドを隠すことで、混乱を防ぐ。
2. ポリモーフィズム（多態性）...同じメソッドの呼び出しでも、オブジェクトによって変化するような汎用性
3. 継承...親機能の引継ぎ、またはインターフェイス（メソッドの強制実装）によって再利用性を高める。

##オブジェクト指向とクラス・インスタンス

###クラス

オブジェクト指向には、クラスの存在が必要不可欠。
クラスは主に設計図。属性と関数を用いて、インスタンスを作るのに必要なモノを設定していく。オブジェクト指向では、上記で述べたように柔軟性が必要になってくる。抽象的で、汎用性の高いクラスほど使い勝手が良くなる。
オブジェクト指向における、クラスの役割は

1. 関連性の高いサブルーチンと変数をまとめる役割
2. クラス内部だけで扱う変数やサブルーチンを隠す。
3. 1つのクラスから、インスタンスをたくさん作る。

###インスタンス

インスタンスは実体。クラスの設計図に従って、より具体的なモノに落とし込んでいったもの。

|抽象的　←→　具体的|
|:---------------:|
|乗り物　←→　車　←→　スポーツカー|

##カプセル化とは

カプセル化とは、一言でいうと**抽象的なやり取りで、目的が達成できるように、内部の構造を外部から隠す**ということ。
内部構造がいくら複雑でも、実際のやり取りが非常に単純化されていて非常に抽象的に見えるようにする。

phpで言うなら、アクセス修飾子を用いて、これらを行う。

カプセル化無し

```php
<?php

class Product
{
    public $name;
}

$prd = new Product();
$prd->name = 'かまぼこ';

echo $prd->name . 'と命名した。';
echo $prd->name . 'のラベルに「' . $prd->name . '」と書いた';

?>
```

```php
<?php

class Product
{
    public $name;
}

$prd = new Product();
$prd->name = 'かまぼこ';


$name = '名無し';
if ($prd->name != '') {
    $name = $prd->name;
}

echo $name . 'と命名した。';
echo $name . 'は、「僕は' . $name . 'です。」と言った';

?>
```

カプセルあり

```php
<?php

class Product
{
    private $name;

    public function setName($name)
    {
        $this->name $name;
    }
    public function getName()
    {
        return $this->name;
    }
}

$prd = new Product();
$prd->setName('かまぼこ');

echo $prd->getName() . 'と命名した。';
echo $prd->getName() . 'のラベルに「' . $prd->getName() . '」と書いた';

?>
```

```php
<?php

class Product
{
    private $name;

    public function setName($name)
    {
        $this->name $name;
    }
    public function getName()
    {
         if ($this->name == '') {
            return '名無し';
        } else {
            return $this->name;
        }
    }
}

$prd = new Product();
$prd->setName('かまぼこ');

echo $prd->getName() . 'と命名した。';
echo $prd->getName() . 'のラベルに「' . $prd->getName() . '」と書いた';

?>
```

##ポリモーフィズムとは
異なる動作を同じ操作、命令で実現することを示す。
乗り物クラスで、「走れ!」という命令を出せば、自転車クラスでは「シャー」、自動車では「ブーン」という表示になるようにするイメージ。
抽象クラスの中に、抽象メソッドを実装しておいて継承先の好きなようにメソッドをいじくれるようにしておくといった感じ。

```php
<?php
interface IProduct
{
    public function applyPriceDown();

    public function getPrice();    

    public function setPrice($price);
}

// 野菜クラス
class Begetable implements IProduct
{
    private $price = 1000;

    public function applyPriceDown()
    {
        // 常に3割引
        $this->price = $this->price * 0.7;
    }

    public function getPrice()
    {
        return $this->price;
    }
}

// 肉クラス
class Meet implements IProduct
{
    private $price = 2000;

    public function applyPriceDown()
    {
        if ('29' == date('d')) {
            // 29日なら半額
            $this->price = $this->price / 2;
        }
    }

    public function getPrice()
    {
        return $this->price;
    }
}

// 冷凍食品クラス
class FreezedFood implements IProduct
{
    private $price = 500;

    public function applyPriceDown()
    {
        // 値引きなし
    }

    public function getPrice()
    {
        return $this->price;
    }
}

class Cart
{
    // 商品インスタンス保持用配列
    private $products = array();

    // 商品追加
    public function addProduct($product)
    {        
        $product->applyPriceDown();    
        $this->products[] = $product;
    }

    // 商品の合計価格取得
    public function getTotalPrice()
    {
        $total = 0;
        foreach ($this->products as $product) {
            $total += $product->getPrice();
        }
        return $total;
    }        
}

// カート@
$cart = new Cart();

// 商品@
$meet = new Meet();
$begetable = new Begetable();
$freezed = new FreezedFood();

// カートに商品追加@
$cart->addProduct($meet);
$cart->addProduct($begetable);
$cart->addProduct($freezed);

// 現在の合計価格を取得@
$total = $cart->getTotalPrice();

var_dump($total);
?>

```


##継承

クラス定義の共通部分を別クラスにまとめる仕組み。メリットはコードの再利用性や拡張性を高めるため。そうすることで、コードの重複を防ぎ、バグやトラブルを減少させることができる。
`interface`を良く用いる。


```php
<?php

// Productクラス
class Product
{
    protected $name; // 商品名
    protected $price;// 価格

    // コンストラクタ
    public function __construct($name)
    {
        $this->name = $name;
    }

    // 価格を取得
    public function getPrice()
    {
        return $this->price;
    }

    // 価格を設定
    public function setPrice($price,$name)
    {
        $this->name = $name;
        $this->price = $price;
        echo $price;
        echo $name;
    }
}

// Productクラスを継承したFoodProductクラス

class FoodProduct extends Product
{
    private $expire; // 賞味期限日数

    public function setExpire($expire)
    {
        $this->expire = $expire;
        echo $expire;
    }

    public function getExpire()
    {
        return $this->expire;
    }
}

$customer = new FoodProduct();
$customer -> setExpire(200);
$customer -> setPrice(200,"パン");
?>

```