I am currently writing a Java interface to a C library. It mostly just delegates calls and adds a object oriented layer on top of it to make integration into a regular Java program more natural.
The C library talks to a (local) server which in turn communicates with a real device.
My current design uses dependency injection and a central Connection
class which provides access to the lower level C API binding (I use JNA). It looks like this:
public class Connection {
public void connect(int port);
public APIBinding getBinding();
}
public interface DataReceiver {
public Data getData();
}
public class DeviceDataReceiver implements DataReceiver {
public DeviceDataReceiver(Connection conn);
public Data getData(); // Use conn.getBinding() to retrieve Data package
}
public class FileDataReceiver implements DataReceiver {
public FileDataReceiver(File file);
public Data getData(); // Load data from file, for device simulation
}
I think this is quite solid, as it provides the user with the opportunity to run a program with the FileDataReceiver
instead of the DeviceDataReceiver
, so that they can use pre-recorded data.
But there is one thing bugging me - There can actually only be one instance of every Device
dependant class. Creating multiple instances would only result in confusing behavior, since there is only one state, which is held inside the C library. The imperative nature of the C library doesn't translate to the object oriented nature of my Java API.
I want to solve this by making my device dependant classes singletons. Personally I dislike singletons, but the usage of the API would get a lot more intuitive.
My main problem is how to name my singleton classes and how to access them in a way that doesn't feel awkward for the user. My first approach was this:
public class Device {
// Handles the single instance problem
// The old classes stay the same
public static ConnectionManager getConnectionManager();
public static DataReceiver getDataReceiver();
...
}
// Using it like this:
Device.getConnectionManager().connect(1234);
DataReceiver dr = Device.getDataReceiver();
for (int i = 0; i < 10; i++) {
System.out.println(dr.getData());
}
There are two things that I am not sure about with this solution:
- Is
Manager
a good name? It feels very generic. - The single instance management is done by my
Device
class. Normally you have something likeConnection.INSTANCE
and a private constructor. While being more restrictive, this approach also would make my classes pretty much untestable, as I have to inject a mock of the JNA binding. Is usingDevice
as a instance-manager a good approach to circumvent that problem?