ちょっとtwitterで話題になったこと。 - 都元ダイスケ IT-PRESS を読んで、思ったことをまとめてみる。
自分が設計するならば、修飾子じゃなくて
- マーカインタフェース java.lang.Freezable
- メソッド java.lang.Object#freeze()
- Freezable インタフェースを implement していないクラスのインスタンスで freeze() を呼び出した場合に投げられる実行時例外クラス java.lang.FreezeNotSupportException
- freeze() されたインスタンスのフィールドを変更しようとした場合に投げられる実行時例外クラス java.lang.FrozenObjectException
を用意すると思う。
package java.lang; public interface Freezable {}
package java.lang; public class FreezeNotSupportedException extends Exception { public FreezeNotSupportedException() { super(); } public FreezeNotSupportedException(String s) { super(s); } }
package java.lang; public class FrozenObjectException extends UnsupportedOperationException { public FrozenObjectException() { super(); } public FrozenObjectException(String s) { super(s); } }
package java.lang; public class Object { : private boolean frozen = false; protected void freeze() throws FreezeNotSupportedException { ... } : }
freeze() の処理を clone() と同じような挙動にすると、わかりやすいと思う。ただし、実装するとなると、ちょっとややこしい気がする。
freeze() を呼び出した後はそのインスタンスのフィールドの変更がされそうになった場合に例外をスローする仕組みが必要はなずだけど、それをどうやって検出するのか?
基本的にはバイトコード内で this に対する putfield 命令を持つようなメソッドで、その前に frozen? のチェックを入れればいいとは思うけど、それだと継承しているすべてのメソッドを調べて、必要なメソッド (setHoge() の類) をオーバーライドしなければいけないはず。
だけど、中には private メソッドや final メソッドがあるはずだから、コンパイラが特別扱いして処理しないと解決できないと思う。
それはさすがによろしくないだろうから、やっぱり freeze の実装は難しそうな気がする。
.NET Framework には Freezable クラス があるみたいなのだが、どのように実装しているのだろうか?