Added info in which package is the code snippet defined.
←Older revision | Revision as of 09:20, 14 July 2015 | ||
Line 12: | Line 12: | ||
<source lang="java" snippet="design.less.friend.Item"/> | <source lang="java" snippet="design.less.friend.Item"/> | ||
+ | (package org.apidesign.friendpackage.api) | ||
This is regular [[Java]] code relying on the standard '''public''' and ''package private'' modifiers. This is exactly the code that you would write, if the friend code would reside in the same package as the API. As we want to use distinct packages, let us take another step and [[wikipedia::Teleport|teleport]] the API to another ''friend'' package with implementation classes. This can be done by defining an ''accessor'' class in such package: | This is regular [[Java]] code relying on the standard '''public''' and ''package private'' modifiers. This is exactly the code that you would write, if the friend code would reside in the same package as the API. As we want to use distinct packages, let us take another step and [[wikipedia::Teleport|teleport]] the API to another ''friend'' package with implementation classes. This can be done by defining an ''accessor'' class in such package: | ||
<source lang="java" snippet="design.less.friend.Accessor"/> | <source lang="java" snippet="design.less.friend.Accessor"/> | ||
+ | (package org.apidesign.friendpackage.impl) | ||
This class defines an internal, friend API specifying what is the functionality that our implementation classes want to get from our API interfaces (in addition to regular access to all '''public''' elements). In this particular case it is the access to constructor via the ''newItem'' method and listener manipulation via ''addChangeListener'' method. Please note that these methods are abstract, without implementation and that this internal API is waiting for someone to register the implementation by calling the ''setDefault'' static method. | This class defines an internal, friend API specifying what is the functionality that our implementation classes want to get from our API interfaces (in addition to regular access to all '''public''' elements). In this particular case it is the access to constructor via the ''newItem'' method and listener manipulation via ''addChangeListener'' method. Please note that these methods are abstract, without implementation and that this internal API is waiting for someone to register the implementation by calling the ''setDefault'' static method. | ||
Line 22: | Line 24: | ||
<source lang="java" snippet="design.less.friend.AccessorImpl"/> | <source lang="java" snippet="design.less.friend.AccessorImpl"/> | ||
+ | (package org.apidesign.friendpackage.api) | ||
Place this non-public ''AccessorImpl'' next to the ''Item'' class, so they are friends in the classical [[Java]] sense. Now all our intrinsic classes are ready. We have the public API class ''Item'' with hooks for friends, we have the API for friends in the ''Accessor'' class and we also have a provider of this friend API. Now we need to bind this all together. As soon as the ''Item'' class is loaded, we need to register the implementation. In [[Java]] this can be done with the use of '''static''' initializer block in the API class: | Place this non-public ''AccessorImpl'' next to the ''Item'' class, so they are friends in the classical [[Java]] sense. Now all our intrinsic classes are ready. We have the public API class ''Item'' with hooks for friends, we have the API for friends in the ''Accessor'' class and we also have a provider of this friend API. Now we need to bind this all together. As soon as the ''Item'' class is loaded, we need to register the implementation. In [[Java]] this can be done with the use of '''static''' initializer block in the API class: | ||
<source lang="java" snippet="design.less.friend.Item.static"/> | <source lang="java" snippet="design.less.friend.Item.static"/> | ||
+ | (package org.apidesign.friendpackage.api) | ||
And this is all (especially if we want as [[Cluelessness|clueless]] understanding as possible). We have connected two [[Java]] packages together and provided an API that allows them to perform a ''privileged'' communication. As such any code in the same package as the ''Accessor'' class can call: | And this is all (especially if we want as [[Cluelessness|clueless]] understanding as possible). We have connected two [[Java]] packages together and provided an API that allows them to perform a ''privileged'' communication. As such any code in the same package as the ''Accessor'' class can call: | ||
<source lang="java" snippet="design.less.friend.use"/> | <source lang="java" snippet="design.less.friend.use"/> | ||
+ | (package org.apidesign.friendpackage.impl) | ||
Moreover, because all the methods in the ''Accessor'' class are '''protected''' and there is just one reasonable subclass, only code in this one package can make the calls, no code in other packages has any chance to access these methods. As such the solution is safe and creates a secure [[wikipedia::Teleport|teleport]] between the API package and the implementation one, allowing us to separate interfaces and implementation as advised by | Moreover, because all the methods in the ''Accessor'' class are '''protected''' and there is just one reasonable subclass, only code in this one package can make the calls, no code in other packages has any chance to access these methods. As such the solution is safe and creates a secure [[wikipedia::Teleport|teleport]] between the API package and the implementation one, allowing us to separate interfaces and implementation as advised by |