Skip to content

Instantly share code, notes, and snippets.

@skuzzle
Last active November 10, 2016 18:31
Show Gist options
  • Save skuzzle/baab94875adbd806d64f2c4186093444 to your computer and use it in GitHub Desktop.
Save skuzzle/baab94875adbd806d64f2c4186093444 to your computer and use it in GitHub Desktop.
An approach to 'friend' classes in java

API designers might know the struggle: you have a package defining the public API as interfaces and then you have another package containing the implementation. How do you make the implementation accessible to the outside but also restrict unwanted instantiations?

Forbidding unwanted usage of your API actually makes it easier to use because it is harder to be used the wrong way.

Let's look at this simple example and start with a public service interface:

package com.yourdomain.api;

public interface PublicService {
    // .. Service methods
}

Then, within the internal package, the service's implementation:

package com.yourdomain.internal;

import com.yourdomain.api.PublicService;

public class PublicServiceImpl implements PublicService {
    // ... Service method implementations
}

You do not want client code to directly instantiate the PublicServiceImpl class, because it should not depend on the actual implementation. One way to do so is putting a factory class with static methods into the api package like:

package com.yourdomain.api;

import com.yourdomain.internal.PublicServiceImpl;

public class PublicServiceFactory {

    public static PublicService create() {
        return new PublicServiceImpl();
    }
}

Now, using the factory, client code does not need to know about the existence of the PublicServiceImpl. The problem is, this approach does not enforce the usage of the factory. Clients could still go and call the implementation's constructor because it needs to be public in order for the factory to see it.

My proposal for solving this issue, is to use an instance of the factory class as guard for instantiating the PublicServiceImpl. To do so, we introduce a constructor argument within our implementation:

package com.yourdomain.internal;

import com.yourdomain.api.PublicService;
import com.yourdomain.api.PublicServiceFactory;

public class PublicServiceImpl implements PublicService {

    // an instance of the Factory must be passed in order to construct an instance of the 
    // service 
    public PublicServiceImpl(PublicServiceFactory guard) {
        if (guard == null) {
            throw new IllegalArgumentException("no guard supplied");
        }
    }

    // ... Service method implementations
}

Now, to instantiate the service, you first need an instance of its factory. The next step is to prevent the factory class from being instantiated from the outside and to pass an instance of itself when constructing the service instance.

package com.yourdomain.api;

import com.yourdomain.internal.PublicServiceImpl;

// make class final to prevent inheritance
public final class PublicServiceFactory {

    private PublicServiceFactory() {
        // hide constructor from others
    }

    public static PublicService create() {
        // b/c of the private constructor we are the only one who can create the guard 
        // instance
        final PublicServiceFactory guard = new PublicServiceFactory();
        return new PublicServiceImpl(guard);
    }
}

This way we enforce that the factory is the only one place where our service can get instantiated and clients must commit themself to a special malicious intent in order to create an instance of the implementation themself.

Note that this approach might not be suitable in every case. One disadvantage is that you introduce a package cycle between the internal and the api package. This prevents you from separating them into different artifacts.

In guice-async-extension I'm using this technique to pass a guice Module from the internal- to the api package. This also allows to make all the service implementations package private because they will be instantiated by guice and thus the only public class within the internal package is the module for configuring the guice bindings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment