2,3个星期前,看了设计模式中的Memento(备忘录)模式。GOF的那本书表示Memento的变量只有Originator(原发器)能够访问,这在c++中很容易实现,因为c++有友元的概念。只要将Memento的成员变量设置成私有访问权限,再把Originator设置成Memento的友元即可。可是Java怎么办?Java可没有友元的概念。那究竟怎么能用Java实现Memento模式呢?
问题的核心在于怎么用Java实现友元。事实上,我在刚开始自然而然想到的一个方法就是人为的造就一个一个类中的成员变量只能被一个类访问的情况。这可以通过构造一个包,在这个包中只有Originator和Memento这两个类,Mementor的所有成员变量的访问级别设置成包级别,而Orginator原来应该是什么级别就是什么级别。
这在理论上是能解决问题,但是碰到友元的问题的话,难道都要这样建立一个特别的包?如果友元的情况有许多,那岂不是就会发生包爆炸的情形,而且包的设定本来就是一个架构的问题,而不是一个为了实现某种技巧的手段。更重要的是,如果这个Originator还要作为另一个类的友元的话,就毫无办法了!
几天前,重新在翻越Thinking in java中关于内部类和回调(Callback)以及闭包(Closure)的那一段(之前一直没有能好好理解)。事实上内部类就是一种面向对象的闭包,因为内部类有他的宿主类的一个reference(所谓闭包是指一个对象,它记录了来自于创建它的作用域的所有信息),内部类本身可以利用这个引用访问宿主类的一切变量,包括Private级别。我突然想到,这不就是一个语法上的,一个类的所有成员变量能被另一个类完全访问吗?内部类不正是能当做宿主类的友元吗?
于是我们可以这样用Java实现Memento模式,将Originator类作为Memento的内部类使用!而Memento只有一个public的方法getCallbackRefenence,用这个方法得到Originator的refenence。
但是问题又来了!这样做导致了一个严重的后果就是原始类和友元之间变成了一种组合(composition)关系,而不是c++里面的一种相识(acquaintance)关系,即友元的生命周期完全被原始类给负责了!而这也几乎就破坏了Memento模式的原类图关系!另外事实上,Memento应该是由Originator负责创建的,如果将Originator作为Memento的内部类的话,那么主次关系就颠倒了而且Memento中的Originator类型和数目就成了编译时静态决定的了!甚至不能在运行时做任何的改变,灵活性降到了最低!
关于这个话题希望大家能够多讨论一下,给我一些意见,看看大家对于用Java实现友元有什么想法。至少从目前看来,用内部类实现也不是一个很好的办法!