Upgrade to Pro — share decks privately, control downloads, hide ads and more …

オレがオブジェクト指向をやめるために必要な3つのPHP RFC/PHP RFC for quit Object Oriented Programming

オレがオブジェクト指向をやめるために必要な3つのPHP RFC/PHP RFC for quit Object Oriented Programming

2023年6月22日のPHPカンファレンス福岡全然野菜での登壇資料です。
https://pepabo.connpass.com/event/280682/

Naoki Kishida

June 22, 2023
Tweet

More Decks by Naoki Kishida

Other Decks in Programming

Transcript

  1. 2023/06/22 2 自己紹介 • きしだ なおき • LINE Fukuoka •

    twitter: @kis • 「プロになるJava」という Java入門書を書いてます
  2. 抽象データ型 • データの操作だけ公開することで変更に強く柔軟な型を定義 • データ特化の「カプセル化」 • 操作としてデータ操作だけを含む class PersonName {

    function __construct( string $surname, string $givenName); function getFullName(); function getSurname(); function getGivenName(); } class PersonName { private string $surname; private string $givenName; function __construct ( string $surname, string $givenName) { $this->surname = $surname; $this->givenName = $givenName; } function getFullName() { return "%s %s".formatted(surname, givenName); } ... class PersonName { private string $fullName; function __construct ( string $surname, string $givenName) { $this→fullName = $surname.” “.$givenName; } function getFullName() { return $fullName; } String getSurname() { return explode(“ “, $fullName)[0]; } ... どちらでもOK
  3. データ型のルール • 純粋関数をデータ型に拡張する • 純粋データ型? • 参照等価 • 戻り値が引数だけで決まる •

    副作用なし • 状態の変更や外部への入出力なし • 参照等価 • 戻り値が引数とフィールドだけで決まる • 副作用なし • フィールド変更以外の状態の変更や 外部への入出力なし
  4. パターンマッチング • isによるパターンマッチング • https://wiki.php.net/rfc/pattern-matching class Point { public function

    __construct(public int $x, public int $y, public int $z) {} } $result = match ($p) is { // These will match only some Point objects, depending on their property values. Point{x: 3, y: 9, %$z} => "x is 3, y is 9, z is $z", Point{%$z, %$x, y: 4} => "x is $x, y is 4, z is $z", Point{x: 5, %$y} => "x is 5, y is $y, and z doesn't matter", // This will match any Point object. Point{%$x, %$y, %$z} => "x is $x, y is $y, z is $z", };
  5. データの処理を考える • こんな値を合計する record Product(String name, Type type) {} record

    Item(Product product, int amount) {} var cart = List.of( new Item(new Product("餃子", new Packed(300)), 3), new Item(new Product("牛肉", new Bulk(250, 100)), 230));
  6. 継承で実装してみる • 継承での実装 sealed interface Type { /** 量り売り */

    record Bulk(int price, int unit) implements Type { int calc(int amount) { return price * amount / unit; } } /** パッケージ */ record Packed(int price) implements Type { int calc(int amount) { return price * amount; } } int calc(int amount); } int total = cart.stream() .mapToInt(item -> item.product().type().calc(item.amount())) .sum();
  7. 継承で実現したときの欠点 • 追うときにいろいろなクラスを見る必要がある • 他のデータが関係あるときに対応できない • 1パック170円、3パック500円とか • 場合わけの型が2つあるときれいにかけない •

    どちらかの型に場合わけが必要 • 業務処理では一箇所にすべての型の処理をまとめるほうがいい • システム境界では他の型が関係することがすくないので継承が有効 • OracleConnectionがMySQLConnectionを気にしたりとかはない
  8. 継承で実現したときの欠点 • 追うときにいろいろなクラスを見る必要がある • 他のデータが関係あるときに対応できない • 1パック170円、3パック500円とか • 場合わけの型が2つあるときれいにかけない •

    どちらかの型に場合わけが必要 • 業務処理では一箇所にすべての型の処理をまとめるほうがいい • システム境界では他の型が関係することがすくないので継承が有効 • OracleConnectionがMySQLConnectionを気にしたりとかはない