違った視点から
①Personクラスの_nameと_addressにfinalをつける必要がありますか?
_nameと_addressは定数ではないと思い、疑問に感じています。
staticではないフィールドにprivateを設定するとコンストラクタでしか代入できなくなります。全てがfinalなフィールドのオブジェクトは**不変(immutable)**オブジェクトともいわれ、関数型プログラミングなどでは重要な概念です。(ただし、完全に不変オブジェクトであるにはフィールドの参照値が指す先のオブジェクトも不変オブジェクトでなくてはなりません)
不変オブジェクトは後から変更できないために一見不便に見えますが、マルチスレッドやテストでその利便性がわかります。不変であるため、そのオブジェクトを扱うメソッドは(引数のオブジェクトその内部で使うグローバルオブジェクトについて副作用が無ければ)何もしなくてもスレッドセーフになり、面倒な同期やロックを考える必要が無くなります。また、状態の変化が無いため、状態の変化に対するテストが不要になります。状態が変わることによって振る舞いが変わるようなオブジェクトのテストはかなり面倒ですが、それをまるまる省けると言うことです。
では、名前を変更したいとなったらどうするかというと、新たなオブジェクトを作ることになります。
Java
1public Person changeName(Label name) {
2 return new Person(name, this.address);
3}
前のオブジェクトはそのままですので、メモリ消費量が多くなりますが、逆に言うと前のオブジェクトをそのまま使い続けられと言う利点が生まれます。Javaでも新たに追加されたクラス(java.nio.file.Pathやjava.time.LocalDateTime等)は不変オブジェクトとして作られる場合が多いようです。
ただし、今回のコードのPersonは必ずしも不変オブジェクトであるとは限らず、例え不変オブジェクトであっても、スレッドセーフと限りません。
まず、Labelが不変オブジェクトと限らないと言うことです。Labelの_labelにfinalが無いからではありません。現在の実装では_labelを生成後に変更することはできないため、その意味では不変です。また、String自体は不変オブジェクトです。しかし、Labelのサブクラスも同様に不変である問い保証はありません。PersonはLablelおよびそのサブクラスを受け付けるため、Personの不変性が崩れる可能性があります。これを完全に防ぐにはLabel自身にfinalをつけるか、Labelそのもの以外は例外で弾くかしないと無理でしょう。
次にスレッドセーフかですが、副作用を伴うSystem.out.println()を使っているため、その条件を満たしていません。自動的にスレッドセーフと言えるのは不変オブジェクト以外を扱わず、一切の副作用がない場合です。これを自動的に検知するような仕組みはJava自体にはありません。
最後に、上を修正してPersonを不変オブジェクトにしても、そのサブクラスは同じく不変オブジェクトであるは限りません。Person型とされる物は全て不変と扱ってはいけないと言うことです。これを防ぐには同じくPersonクラス自体をfinalにする必要があるでしょう。その意味では、少し片手落ちのような気もします。
このように、全てがfinalなフィールドであることは不変オブジェクトの十分条件でも必要条件でもありません。ただ、もし、不変オブジェクトであれば、全てのフィールドをfinalにしてもコンパイルエラーが起きないはずです。間違って不変オブジェクトでは無くなってしまっていることを検知するためにfinalに設定することは無駄ではありません。
②PersonクラスでLabel型の_nameと_addressを宣言していますが、継承等を行っていないのに宣言して、コンパイルエラーが出ない仕組みがよくわかっていません。PersonクラスでLabel型は使えるものでしょうか?
また、継承等を行わなくてもいいのでしょうか?
継承するのか、それとも持つだけなのかは重要なテーマです。それぞれis_aとhas_aと呼ばれています。継承すればStringとしても扱えるというのは利点ですが、Stringとしても扱えてしまうと言うのは欠点でもあります。あまり、それ自身として扱って欲しくない場合は、has_aな関係を持った方が良い場合があります。
しかし、Javaの場合は継承禁止というのがあります。Stringはfinalなクラスであるため継承できません。なので、has_aの関係、つまりフィールドに持つだけという関係にするしかありません。それでも、なるべくStringのように振る舞いたい場合は、必要なメソッドを一つ一つ委譲することになります(Lombokの@Delegateを使うという手もありますが)。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2016/12/20 23:48
退会済みユーザー
2016/12/20 23:51 編集
2016/12/21 00:18
2016/12/22 00:30 編集
退会済みユーザー
2016/12/21 18:06
2016/12/21 18:29
2016/12/21 21:12
2016/12/22 01:39
2016/12/22 11:57 編集