Trait とは?
    その使い道を考えてみる
              藤村 拓也 @tlync




12年8月9日木曜日
自己紹介




12年8月9日木曜日
自己紹介
             • 藤村 拓也@tlync
             • アプリケーション開発第二
             • 最近の関心事
              • Scala, Agile(Project Mgt.)
             • PHP は生きる為にやっています

12年8月9日木曜日
※ ちなみに残念ながら?
             PHP の Trait のお話しです




12年8月9日木曜日
Trait を知ってる人?




12年8月9日木曜日
Trait を説明できる人?




12年8月9日木曜日
trait   /tréit ¦ tréi/


     名 詞 形式的
     1 (性格習慣の)特徴, 特色, 特質
     admirable traits like honesty and courage|誠実さや勇気と
     いったすばらしい特質
     American traits|米国国民性.
     2 希用語 (ペン鉛筆などの)一筆, 筆使い;(性質など
     の)気味, 気配 of ...
     a trait of sadness|一まつの悲哀.



12年8月9日木曜日
特徴,
             特色,
             特質
12年8月9日木曜日
Trait とは?
      • メソッドとプロパティの集合
      • 単一継承の制約を軽減する
             • 継承関係とは関係なく、共通の特性、
               振舞いを再利用(水平展開)できる
      • それ自体ではインスタンス化できない


12年8月9日木曜日
継承関係と関係なく
      実装 を 再利用 できる仕組み



12年8月9日木曜日
PHP 5.4 <=




12年8月9日木曜日
他言語での類似の機構
    • Scala … trait
    • Perl 6 … role
    • Ruby … Mix-in
        ※同様の概念だが仕様は微妙に異なる。
        型情報を持つか(is_aをパスするか)とか。


12年8月9日木曜日
簡単なサンプル




12年8月9日木曜日
trait Engine
             {
                 public function startEngine()
                 {
                     echo 'BRRRM!';
                 }
             }

             class Car
             {
                 use Engine;
             }

             (new Car)->startEngine(); // BRRRM!


12年8月9日木曜日
これは継承でも
             できなくはない



12年8月9日木曜日
では、これは?




12年8月9日木曜日
class Vehicle
             {
                 protected function startEngine()
                 {
                     echo '⚡';
                 }
             }

             class Plane extends Vehicle
             {
                 public function fly()
                 {
                     echo '✈';
                 }
             }

             class Boat extends Vehicle
             {
                 public function sail()
                 {
                     echo '⚓';
                 }
             }

12年8月9日木曜日
class SeaPlane extends ???
   {
       // ボートして走らせたいし、飛行機
   として飛ばしたい。どうすれば…
   }




12年8月9日木曜日
Vehicle
                             startEngine()




                      Boat                          Plane
             sail()                          fly()


                                      ???
                                 SeaPlane
                             sail()
                             fly()




12年8月9日木曜日
多重継承はできない




12年8月9日木曜日
委譲(Composition) ?




12年8月9日木曜日
interface Plane
             {
                 public function fly();
             }

             interface Boat
             {
                 public function sail();
             }




12年8月9日木曜日
class SimplePlane extends Vehicle implements Plane
    {
        public function fly()
        {
            echo '✈';
        }
    }

    class SimpleBoat extends Vehicle implements Boat
    {
        public function sail()
        {
            echo '⚓';
        }
    }



12年8月9日木曜日
class SeaPlane extends Vehicle implements Plane, Boat
             {
                 private $boat;
                 private $plane;

                 public function __constract()
                 {
                     $this->boat = new SimpleBoat();
                     $this->plane = new SimplePlane();
                 }

                 public function sail()
                 {
                     return $this->boat->sail();
                 }

                 public function fly()
                 {
                     return $this->plane->fly();
                 }
             }

             $seaPlane = new SeaPlane();
             $seaPlane->sail(); // !
             $seaPlane->fly(); // ✈

12年8月9日木曜日
形式的な記述が多い
               やや面倒



12年8月9日木曜日
Trait で
             実装の共有をしてみる



12年8月9日木曜日
// 命名はちょっと微妙
             trait FlyEngine
             {
                 public function fly()
                 {
                     echo '✈';
                 }
             }

             trait FloatEngine
             {
                 public function sail()
                 {
                     echo '⚓';
                 }
             }

             class SeaPlane implements Plane, Boat // 型の継承
             {
                 use FloatEngine, FlyEngine; // 実装の継承
             }

             $seaPlane = new SeaPlane();
             $seaPlane->sail(); // !
             $seaPlane->fly(); // ✈
12年8月9日木曜日
記述はすっきり
             実装の共有ができた



12年8月9日木曜日
Vehicle
                                      startEngine()




                      Boat                                     Plane
             sail()          BoatEngine                 fly()            FlyEngine
                             sail()                                    fly()



                                          SeaPlane
                                      sail()   BoatEngine       FlyEngine
                                      fly()
                                               sail()          fly()




12年8月9日木曜日
型の保証 … Interface
             実装の再利用 … trait


        ※ 注: Scala, Ruby などではまたちょっと違うよ!

12年8月9日木曜日
Trait は
             継承ツリーに関係なく
             実装の再利用を行うだけ


12年8月9日木曜日
で、実際どう使うと便利なのか?




12年8月9日木曜日
1. 抽象クラスを作る前に
                Trait の検討



12年8月9日木曜日
抽象クラスの主な理由は
             コードの再利用(多分)



12年8月9日木曜日
Trait が利用できないか検討する




12年8月9日木曜日
※Trait 中2病には注意しましょう




12年8月9日木曜日
2. Entity の振舞いの共有




12年8月9日木曜日
Entity の振舞い
      • タイムスタンプ管理
      • 変更のトレース
      • ソフトデリート可能か
      • など…



12年8月9日木曜日
trait Timestampable
             {

                 private $createdAt;
                 private $updatedAt;

                 ... getter, setter

                 /**
                   * Updates createdAt and updatedAt timestamps.
                   */
                 public function updateTimestamps()
                 {
                      if (null === $this->createdAt) {
                          $this->createdAt = new DateTime('now');
                      }

                     $this->updatedAt = new DateTime('now');
                 }
             }




12年8月9日木曜日
/**
         * 商品エンティティ
          */
        class Product
        {
             use Timestampable, // タイムスタンプを自動で
                 SoftDeletable, // ソフトデリート可能に
                 Activatable; // 活性、非活性を可能に

             private $name;

             // 本質的なロジック
        }



12年8月9日木曜日
3




12年8月9日木曜日
時間なかった
             \(^o^)/



12年8月9日木曜日
いいアイディアあったら
               教えてください




12年8月9日木曜日
まとめ




12年8月9日木曜日
Trait を知り、PHP 5.4 時代の
             新たな設計を探ろう



12年8月9日木曜日
それか




12年8月9日木曜日
この会社から PHP を撲滅しよう




12年8月9日木曜日
おわり




12年8月9日木曜日

Trait とは? その使い道を考えてみる