どんな時にクラスを final と宣言するのか

<font color="Gray">
[Ocramius](https://twitter.com/Ocramius) さんの記事、[When to declare classes final](https://ocramius.github.io/blog/when-to-declare-classes-final/) を、ご本人の許可を得て翻訳してみました。
Ocramius さんありがとー。
誤訳等にお気付きの際は、コメントや編集リクエストをもらえると助かります。
</font>

# どんな時にクラスを final と宣言するのか

**まとめ：インタフェースを実装していて他のパブリックメソッドが定義されていない場合、いつもクラスを `final` にしてください。**

この 1 ヶ月で、私は PHP クラスへの `final`の使い方について何度か議論をしました。

そして以下のような流れが繰り返されました。

1. 私が新しく作られたクラスへ `final` を宣言するよう頼む
2. コードを書いた人は嫌がり　`final` は柔軟性を損なうと主張
3. 柔軟性は良い抽象化から生まれるのであって、継承から生まれるのではないという説明が必要となる

この流れから明らかなのは、コードを書く人達に**どんな時に** `final` を使うのか、そしてまたどんな時に避けるべきなのかについて、より良い説明が必要ということです。

この話題については[他にも](http://verraes.net/2014/05/final-classes-in-php/)[幾つもの](https://www.javaworld.com/article/2073649/core-java/why-extends-is-evil.html)[記事がある](https://stackoverflow.com/questions/137868/using-the-final-modifier-whenever-applicable-in-java)のですが、この記事の主旨は、将来同じ質問をしてくる人への「クイックリファレンス」となることです。

## いつ "final" を使うのか
`final` は**可能な限りいつでも**使うべきです。

## なぜ final を使わなければならないのか
あるクラスを `final` とする理由は幾つもあります。個人的に特に大事だと思うものをリストアップして、それぞれ説明してみましょう。

### 1. 大規模な継承連鎖を防ぐ
開発者には悪い習慣があり、それは問題を解決するために既存の（不適切な）対応の具体的なサブクラスを作ろうとすることです。
多分以下のような例から見てとれるはずです。

```php
<?php

class Db { /* ... */ }
class Core extends Db { /* ... */ }
class User extends Core { /* ... */ }
class Admin extends User { /* ... */ }
class Bot extends Admin { /* ... */ }
class BotThatDoesSpecialThings extends Bot { /* ... */ }
class PatchedBot extends BotThatDoesSpecialThings { /* ... */ }
```

これは、疑いようもなく、コードをデザインする際にとるべき**ではない**やり方です。
上述のアプローチを通常採用するのは、開発者の中でも [OOP(Object Oriented Programming)](http://wiki.c2.com/?AlanKaysDefinitionOfObjectOriented) を「問題を継承によって解決する方法」と取り違えている人達です（「継承志向プログラミング」とでもいったところでしょうか？）。

### 2. 集約(composition)の奨励
一般に継承を（デフォルトとして）強制的なやり方で防ぐことには利点があり、開発者にもっと集約について考えさせることができます。

既存のコードが継承によって機能の詰め込みを少なくできる、というのは私の考えでは、[feature creep](https://en.wikipedia.org/wiki/Feature_creep)[^1] と結び付いた軽率さのあらわれです。

以下の単純な例について考えてみましょう。

```php
<?php

class RegistrationService implements RegistrationServiceInterface
{
    public function registerUser(/* ... */) { /* ... */ }
}

class EmailingRegistrationService extends RegistrationService
{
    public function registerUser(/* ... */) 
    {
        $user = parent::registerUser(/* ... */);

        $this->sendTheRegistrationMail($user);

        return $user;
    }

    // ...
}
```

`RegistrationService` を `final` とすることで、`EmailingRegistrationService` をその子クラスとするというアイディアは分かりやすく禁止され、先に示されたような愚かな間違いは簡単に避けることができます。

```php
<?php

final class EmailingRegistrationService implements RegistrationServiceInterface
{
    public function __construct(RegistrationServiceInterface $mainRegistrationService) 
    {
        $this->mainRegistrationService = $mainRegistrationService;
    }

    public function registerUser(/* ... */) 
    {
        $user = $this->mainRegistrationService->registerUser(/* ... */);

        $this->sendTheRegistrationMail($user);

        return $user;
    }

    // ...
}
```

### 3. 公開 API について考える事を開発者に強制できる

開発者達は継承を使ってアクセサーを加え、既存クラスへ API を追加しようとする傾向があります。

```php
<?php

class RegistrationService implements RegistrationServiceInterface
{
    protected $db;

    public function __construct(DbConnectionInterface $db) 
    {
        $this->db = $db;
    }

    public function registerUser(/* ... */) 
    {
        // ...

        $this->db->insert($userData);

        // ...
    }
}

class SwitchableDbRegistrationService extends RegistrationService
{
    public function setDb(DbConnectionInterface $db)
    {
        $this->db = $db;
    }
}
```

この例は思考プロセスにおける幾つかの欠陥を示しており、`SwitchableDbRegistrationService` のようなものが作られてしまいます。

- `setDb` メソッドは `DbConnectionInterface` を実行時に変更するために使われ、解決すべき別の問題を隠しているように見えます。多分本当に必要なのは `MasterSlaveConnection` でしょうか？
- `setDb` メソッドは `RegistrationServiceInterface` によってカバーされておらず、したがってこれが使えるのはコードを完全に `SwitchableDbRegistrationService` へ依存させて使う場合のみであり、幾つかの文脈においてその誓約の意図を台無しにします
- `setDb` メソッドは実行時に依存対象を変えますが、これは `RegistrationService` のロジックによってサポートされていないかもしれず、バグを招きさえするかもしれません。
- `setDb` メソッドは元々の実装のバグのために導入されたのかもしれません。なぜ修正がこのような形で行われたのでしょうか？ これは本当の修正といえるでしょうか？ 対症療法に過ぎないのではないでしょうか？

この `setDb` の例にはもっと多くの問題がありますが、上述の点は `final` がこういった状況を未然に防ぐということを説明するのに、最もふさわしいものです。

### 4. 開発者がオブジェクトの公開 API を削減するよう強制できる

クラスが多くのパブリックメソッドを持つのは、おそらく SRP(Single Responsiblity Principle: 単一責任の原則) を破っていることが多く、よくあることとして、開発者はそのようなクラスの特定の API をオーバーライドしたくなります。

新規実装は毎回 `final` とするようにすれば、新しい API を可能な限り小さく保つことについて、あらかじめ考えさせるよう開発者に強制することができます。

### 5. `final` クラスはいつでも継承可能に変えられる
新規のクラスを `final` としてコードしても、任意のタイミングで（本当に必要なら）継承可能に変えることができます。

それで失うものは何もなく、ただしそのような変更をする際は自分自身やチームメンバーに対する説明が必要となり、そしてその議論は変更がマージされる前に、よりよい解決策をもたらすことにつながるかもしれません。

### 6. `extends` はカプセル化を破壊する
書く人が特に拡張可能なものとして設計するのでない限り、実際どうなのかに関わらず、クラスを `final` とすることを考えるべきです。

クラスの継承はカプセル化を破壊し、予期しない結果や後方互換性の破壊につながります。`extends` キーワードを使う前によくよく考えることです。もっと良いのは、クラスを `final` とし、他の人にも継承を使うことを考えないようにすることです。

### 7. その柔軟性は必要ない
いつも言われることですが、`final` はコードベースの使われ方の柔軟性を減らすという意見があります。

これに対する反論は非常にシンプルです。そのような柔軟性は必要ありません。

そもそも何故必要なのでしょうか？ なぜあるコントラクトに対する実装を、別途で書くことができないのでしょうか？ 何故集約を使わないのでしょうか？ 問題に対し注意深く考えてみたでしょうか？

もしまだ `final` キーワードの削除が必要だというのであれば、そこには別の種類のコードの臭いがありそうです。

### 8. 自由にコードを変えられる
一度クラスを `final` とすれば、そのコードは納得いくまで変えることができます。

カプセル化の維持は保証されているので、注意しなければならないのは公開 API のみです。

つまり何でも書き換えたいだけ、自由に書き換えることができます。

##  `final` が不要な時
final クラスは**以下の前提でのみ有効**です。

1. その final クラスが実装する抽象（interface）がある
2. その final クラスの全ての公開 API がその interface の一部である

もしこれら 2 つの事前条件の内の 1 つが欠けているなら、いずれそのクラスを継承可能としたくなる日がくることでしょう。あなたのコードが真に抽象へ依存してはいないということなのですから。

例外となるのは、ある特定のクラスが表しているのが、ある種の誓約や概念で、それらが完全に不変のものであり、柔軟性がなくシステム全体にグローバルである場合です。その 1 つの好例は数学的な操作です。`$calculator->sum($a, $b)` は時を経ても変わることがなさそうなものです。このような場合には、あらかじめ依拠する抽象がなくとも、 `final` キーワードを使うことは安全だと考えられます。

他に `final` キーワードを使いたくない状況は、既存のクラスです。影響するコードベースがあるので、可能となるのは [semver](https://semver.org/) に従いメジャーバージョンを上げる場合のみです。

## 試してみよう！
この記事を読み終えたなら、自分のコードへ戻り、そしてもしまだやったことがないのなら、あなたの最初の `final` を実装するクラスに加える事を検討してみましょう。

続くコードが、期待通りの適切な形となっていくことが分かる筈です。

[^1]: 訳注: フィーチャー・クリープ、機能をどんどん足して当初意図を超えて複雑化すること