最小知識の原則~PrincipleOfLeastKnowledge~

「最小知識の原則」についての説明は、
Facadeパターンの章で出てきました。

Facadeパターンは、
サブシステムの一連のインターフェースに対する
統合されたインターフェースを提供するものです。

したがって、Facadeパターンは
複数のオブジェクトのメソッドを呼び出すことが想定されます。
しかし、ある程度の決められた範囲内のメソッドのみを呼び出さないと、
依存性の高いコードになってしまいます。
それを防ぐための原則が
「最小知識の原則」となります。

 

最小知識の原則

「直接の友達とだけ話すこと」
オブジェクト間のやりとりを最小限にするべき。

→多数のクラスが互いに結合し、
システムのある部分に対する変更が他部分に
連鎖してしまうような設計を回避する。

※デメテルの法則 (Law of Demeter, LoD) ともいう。

 

 

以下に属するメソッドだけを呼び出すべき

1. そのオブジェクト自身のメソッド
2. メソッドの引数として渡されたオブジェクトのメソッド
3. メソッドが作成またはインスタンス化したオブジェクトのメソッド
4. そのオブジェクトのコンポーネント(インスタンス変数で参照されるオブジェクト)[HAS-A関係]のメソッド

 

<?php

class Car
{
    //4.このクラスのコンポーネント(HAS-A)の
    //メソッドである、$engine.start()はOK!
    public $engin;

    public function __construct(){}

    //2.メソッドの引数として渡されたオブジェクト$keyの
    //メソッドである$key.turns()はOK!
    public function start(Key $key): void
    {
             //3.メソッドが作成したオブジェクト$doorsの
        //メソッドである$door.lock()はOK
        $doors = new Doors();  
        
        $authorized = $key.turns();
        
        if($authorized){
            $engine.start();
             
               //1.オブジェクト自身のメソッド
                    //である、updateDashboardDisplay()はOK!
            this->updateDashboardDisplay(); 
       
            $door.lock();
        }

    }

    public function updateDashboardDisplay()
    {
        //
    }

}

デメリット

この原則を意識しすぎると、ラッパークラスの記述が多くなり、
複雑になってしまうこともある。

なので、適当に活用する!



PHPerKaigiいってきました!

PHPerKaigi@ココネリに参加してきました。
練馬初上陸でした。池袋から一駅でアクセス良きでした。

\公式サイトはこちら/
https://phperkaigi.jp/2018/

3/9,10と開催されてたのですが、3/10のみ参加しました。
お昼ご飯マグロどーん!他にもサンドイッチ、焼肉弁当もありました。
エンディングと懇親会のビールの豪華さが、、、もう最高!
昼食のマグロ丼コーヒー 懇親会のビール

スポンサー様にとっても感謝です。
写真のセンスがないのは、ほっといてくださいw

すべてのセッションが印象的だったんですが、
その中でも2つのセッション内容を自分なりに落とし込んでみました。(自己満ですみません。)
・SOLIDの原則って、どんなふうに使うの?
・BEAR.Sunday

#SOLIDの原則って、どんなふうに使うの?

SOLIDの原則の一つであるオープン・クローズドの原則にフォーカスを当てたお話でした。
この原則については、自身でも過去にかいてます、実は。
このあたり

しかし、これって実践できてる気はしていません。
新人くんの気持ちわかる〜って思ったり、こうやったほうがいいんだろなとか考えさせられたセッションでした。

close →修正を行わない
open →機能を拡張できる
この2つを同時に満たすこと=OCP準拠 !
interface使いこなさなきゃなと思いました。

フレームワークを参考にしてみると、いいとのことで、
もっとフレームワークみなきゃなと痛感しました。

「OCP違反ですよ。」て言いたくなりました。

#BEAR.Sunday

敏腕元上司(あまり人を褒めない)が尊敬していた郡山さんのセッション。
本物の郡山さんに感動しました。
フレームワークBEAR.Sundayで使われてるDI・AOP・RESTのお話でした。

 

ともわれ、使ってみなきゃということで、
クイックスタートしてみました。次回はチュートリアルします!
(リンク:https://bearsunday.github.io/manuals/1.0/ja/quick-start.html)

まずは、composerでbear/skeletonをいれる。

composer create-project -n bear/skeleton MyVendor.MyProject

composer create-project [option] vendor/project target-directory
※ -n (–no-interaction) :対話的な質問の問い合わせはしないよ

 

作成されたMyVendor.MyProjectに入って、

cd MyVendor.MyProject

 

src/Resource/Page/Kin29.phpをつくって、

<?php 
namespace MyVendor\Myproject\Resource\Page; 

use BEAR\Resource\ResourceObject; 

class Kin29 extends ResourceObject { 
    public function onGet( string $word = 'morimori!!!' ) : ResourceObject              
    { 
        $this->body = [
             'getting' => 'kin29 ' . $word
        ];

        return $this;
    }
}

 

GETパラメータなしでリクエスト

$ php bootstrap/web.php get /kin29
200 OK
content-type: application/hal+json

{
    "getting": "kin29 morimori!!!",
    "_links": {
        "self": {
            "href": "/kin29"
        }
    }
}

 

GETパラメータ「word=man」でリクエスト

$ php bootstrap/web.php get /kin29?word=man
200 OK
content-type: application/hal+json

{
    "getting": "kin29 man",
    "_links": {
        "self": {
            "href": "/kin29?word=man"
        }
    }
}

ちょっとアレンジしてます。
GETパラメータ名「word」は、onGet関数の引数名と合わせればなんでもいいようですね。

まだまだ全然わかってません…チュートリアルささっとします。
アノテーションで機能を導かれ、機能となる
print_oすごかった!地下鉄の線路図みたいでした。

 

ほかのセッションで、Hackもやってみたいなと思いました。
型に厳しいということで不慣れなことが多そうですが。
チュートリアル:http://hacklang.org/tutorial.html

 

モチベーション上がるいい機会でした。

スタッフ&スピーカー&スポンサーの皆様ありがとうございました。

DRYの原則

参考:ここ

DRY

=Don’t Repeat Yourself

直訳すると「繰り返すな。」という意味です。

 

同じような内容のコードが重複していると、

変更際、重複の数だけ変更しなければなりません。

また、いざそのコードを使う時に、どれを使えば良いのかわからなくなります。

 

同じようなコードは一箇所にまとめとけ!同じようなコードは何度も書くな!

→再利用性の高いコードを書く必要がある。

 

この原則を守ると、シンプルで保守しやすいコードが書きやすくなるとのことです。

「シンプルなコードを書きたい!!」

 

関連している原則:

・Once and Only Once(OAOO)一度、ただ一度

OCP 開放閉鎖の原則

SRP 単一責務の原則

 

 

 

ISP(The Interface Segregation Principle) – SOLID

ISP(The Interface Segregation Principle)
– クライアントに対して利用しないインタフェースへの依存を強制してはならない。

参考:ここここ

 

・インターフェイスはクライアント(使う側)の都合により変更される

→インターフェイスはそれを使うクライアントごとに分離されるべき

 

 

・インターフェイスが分離されていないと、

クライアントにサーバが依存すべきところが、

サーバにクライアントが依存してしまい、

変更のたびに全体へ影響を与えてしまう。

→依存関係の逆転が成り立たず、脆弱となる。

 

 

・太った(いろんな役割を持つ=便利な)インターフェイスにしない。

→SRP(単一責務の原則)にする

 

・依存をできる限り減らす。

→クラス間の結合度(Coupling)を減らす

 

オブジェクト指向って難しい・・・。

 

 

 

LSP(The Liskov Substitution Principle)- SOLID

LSP(The Liskov Substitution Principle)リスコフの置換原則
– 派生クラスは、その基底クラスと置換可能でなくてはならない。

 

参考:ここ

 

リスコフさんが提唱した、置換原則です。

置換するもの:親クラスと子クラス

この2つが置き換えることができなければならない。

 

よく、子クラスに親クラスをオーバーライドするのですが、

その時、親クラスの意図する動きをしなければならないということ。

 

LSP ありきの ODP

子クラスと親クラスが置き換え可能でないと、

そのクラスに依存するクラスの変更時、

子クラスor親クラスからの来たのかの条件文が必要となり、

変更が大変、浪費がかかる。

=拡張にしにくく、修正が多い

ODP(オープン・クローズドの原則)に反している。

 

 

 

DIP(The Dependency Inversion Principle)依存性反転の原則- SOLID

DIP(The Dependency Inversion Principle)依存性反転の原則

– 抽象に依存すべき。具象クラスに依存してはいけない。

 

HeadFirstデザインパターンの説明が分かりやすかったです。

↑では様々な種類のPizza(NYCheesePizza,NYClamPizza…)を作るPizzaStoreを例に出しています🍕🍕🍕

 

[Before]なにも考えず実装する🙄

PizzaStoreは具象クラスであるNYCheesePizzaやNYClamPizzaに依存しています。

高水準なクラス PizzaStoreから低水準なクラスNYCheesePizzaに依存する形となり、依存の方向は上から下(矢印)になっています。

 

デメリット🙅‍♂️

PizzaStoreは4つの具象クラス依存しており、Pizzaの種類が増えるとさらに依存する具象クラスが増え、コードの修正も必要となってしまいます。

 

 

[After]DIPに沿った実装をする🤔

抽象クラスPizzaを追加しました。

PizzaStoreは抽象クラスPizzaを作成し、抽象クラスPizzaに依存するようになります。

また、具象クラスだったNYCheesePizzaやNYClamPizzaは抽象クラスPizzaを実装するようになり、抽象クラスPizzaに依存するようになりました。

これにより、原則通りにPizzaStoreもNYCheesePizzaやNYClamPizzaもすべて抽象に依存するようになりました!!!

さらに、依存の方向を示す矢印も上から下だったものが「反転」して、下から上への依存となりました💡

 

メリット🙆‍♂️

PizzaStoreは具体的なPizzaの種類を知らなくていい(抽象Pizzaクラスしか知らない)ので、新しい具象Pizzaクラスが作成されても修正は少なくなります。

 

 

まとめ

この原則に従った設計を考える時には、高水準コンポーネントではなく低水準コンポーネントから抽象化できないかを考えていくといい気がしました。

 

また、この原則に従うための指針として

  • 具象クラスへの参照を保持する変数を持たない
  • 具象クラスからクラスを継承しない
  • ベースクラスの実装済みメソッドをオーバーライドしない

というのも大事だなと改めて感じました。

 

\ 改めて、この本おすすめです🍺/

 

OCP(The Open-Closed Principle)- SOLID

OCP(The Open-Closed Principle)オープン・クローズドの原則
– オブジェクトは拡張に対して開いており、修正に対して閉じていなければならない。

参考:こちら

 

この法則ですが、よく聞くし、言いたいこともなんとなくわかるのですが、

どうすれば、この法則に沿ったソースが書けるか、なってるのかがまだわかんないですね。わかったらまた書こう。

 

ー オブジェクト指向の核心をついている

というますが、オブジェクト指向がまだまだなので、「確かにそうだ!」とかまだ言えるレベルではないです、はい。

 

オブジェクト指向の話って、よく「抽象」て言葉が出てくるんですけど、

日本語が苦手なので、ここで覚えます。

「抽象」《名・ス他》

多くの物や事柄や具体的な概念から、それらの範囲の全部に共通な属性を抜き出し、これを一般的な概念としてとらえること。
(ほうほう、なるほど、共通部分を簡潔に捉える的な感じですかね?)

まとめ
・追加/継承する時が楽にできる(開放)
・その時、既存のコードを変更しなくていい、
そのコードが使われる時、使う主体に影響を与えない(閉鎖)

 

⇒使う側にも、使われる側にも影響が少ないもの

SRP(The Single Responsibility Principle)- SOLID

SOLIDとは…
オブジェクト指向設計の五つの原則の頭文字をとったものだそうです。

SRP(The Single Responsibility Principle)
– クラスの責務は単一でなければならない。

OCP(The Open-Closed Principle)
– オブジェクトは拡張に対して開いており、修正に対して閉じていなければならない。

LSP(The Liskov Substitution Principle)
– 派生クラスは、その基底クラスと置換可能でなくてはならない。

ISP(The Interface Segregation Principle)
– クライアントに対して利用しないインタフェースへの依存を強制してはならない。

DIP(The Dependency Inversion Principle)
– 具象化されたものではなく、抽象化されたものに依存するべきである。

 

今回は、
SRP(The Single Responsibility Principle)単一責務の原則
-クラスの責務は単一でなければならない。

について、書きます。

1つのクラスには、1つの責任・役割を持たせる。

その理由としては、
クラスの責任・役割を小さくすることで、読みやすくて、保守性も上がるからだそうです。

コードの変更の必要が発生した時、1つのクラスに複数の役割の関数をもたせていた場合、
依存が大量に発生し、変更箇所が増える。
こんな感じかなっと掴んでいます。この読みが当たっているかはわかりませんが・・・。

設計って大事だなっと、しみじみと思いました。 おわり

参考:
オブジェクト指向の法則集
プログラマが知るべき97のこと