咋看上去友元使得类的私有成员暴露以致影响了类的安全性(封装),但是实际上它反而保证了类的安全。让一个朋友访问你比让所以的人访问你安全的多。比如你有一份私有文件,想让你的朋友查看,如果通过友元,你可以很方便的让你的朋友访问到那份私有文件。如果没有友元,那你怎么办?只能将这份文件变成public,那样不仅你的朋友可以访问它,任何人都可以访问它了,类的安全性受到了破坏。
也就是说友元提供了一种约束,失去友元就少了这么一种约束规则。
那么我们看看在模式中那些地方可以使用到它。State模式中的Context的state就应该只能被ConcreateState所修改,而不能被外界所修改,这也是State区别与Stratage的一个重要方面,如何表现出这种约束?通过友元就很简单了,将Context的state设为私有,ConcreateState设为Context的友元就可以了,这样就实现了前面提到的约束。详见我另一篇随笔。
而在java和c#中似乎并没有提供这么一种方法。那么怎么办?
一种办法就是在Context中加入SetState的public方法,这样做约束就没了。
还有一种方法,利用反射,利用反射你可以获得一个类的私有成员,不过效率太低,语义也显得复杂。
更深入的应用,在O/R mapping中DomainObjectMapper需要构造出DomainObject,这样势必会设置DomainObject的私有变量。如果没有友元,那你必须提供DomainObject所以私有变量的设值函数,而你又显然不愿意这样(严重破坏DomainObject的封装性)。如果有友元就简单的多了。
友元是不是就完美了呢?
不是的,就拿第一个例子来说,你的朋友确实是可以访问你的私有文件了,但是你想让他看你的日记吗?友元使得他有了这个权利!所以如果低粒度的考虑,友元还要再进行细分,细分成每个私有成员的友元,不过这样好像太麻烦了。
可是为什么java ,C#连友元都不支持呢?