Question

I am defining a class (RemoteBluetoothDevice), within which there is a nested inner class for bluetooth low energy associated parameters. Basically, if the discovered remote bluetooth device is of type DEVICE_TYPE_CLASSIC, the first four private member variables are set accordingly, using available APIs, such as getUuids(), getType(), etc. When the device type is determined as DEVICE_TYPE_LE or DEVICE_TYPE_DUAL, I would like to instantiate the inner class (i.e., leCharacteristics) to hold all related BLE related parameters (those listed herein and the one I might add in future). There is a private member variable (i.e., leCharacteristicsReference) which will hold the reference to the inner class instance in case we instantiate it when the discovered device supports BLE.

public class RemoteBluetoothDevice {

    private BluetoothDevice                 device;
    private Parcelable[]                    bluetoothRemoteDeviceUuids;
    private RelationWithRemoteDeviceState   bluetoothRemoteDeviceBondingRequestAndConnectionStatus;
    private RemoteBluetoothDeviceType       remoteBluetoothDeviceType;
    private leCharacteristics leCharacteristicsReference = null; // Ref to inner class instance

    private class leCharacteristics {

        private int                         bluetoothRemoteLeDeviceRssi;
        private byte[]                      bluetoothRemoteLeDeviceScanRecord;

        private leCharacteristics(int rssi, byte[] scanRecord) {

            this.bluetoothRemoteLeDeviceRssi = rssi;
            this.bluetoothRemoteLeDeviceScanRecord = scanRecord;

        }
}

My main question here relates to design patterns and the best possible practice in defining such nested classes. Since a device may or may not support BLE, the outer class may or may not have to have its inner class instantiated when being constructed (using any of its constructors). In fact, depending on what the device type is, we may choose to instantiate the inner class or not. I am aware of few (but not all TBH) design patterns in Java but none would be applicable to this. So, any help is highly appreciated.

Thanks!

[EDIT] After some research, I came across with "Local Inner Classes". Since I had never used them before, I had no idea if they could possibly be applicable to the aforementioned case (I admit that I am still not sure if this is good practice at all!). What I understood, I could add an if clause where I check it the discovered device supports BLE. IF yes, then I place the inner class inside the if clause and declare it therein. I could define getter and setter methods for it so that the outer class (in my case, RemoteBluetoothDevice) is able to set or get the inner class variables.

Here is what I came up with so far:

public RemoteBluetoothDevice(BluetoothDevice newDevice) throws IllegalArgumentException {

            if (newDevice.getType() == BluetoothDevice.DEVICE_TYPE_CLASSIC) {
                this.device = newDevice;
                if (device.getUuids() != null)
                    this.bluetoothRemoteDeviceUuids = newDevice.getUuids();
                else
                    this.bluetoothRemoteDeviceUuids = null;

                this.remoteBluetoothDeviceType = RemoteBluetoothDeviceType.DEVICE_TYPE_CLASSIC;

            } else {    
                throw new IllegalArgumentException();   
            }
}

// General constructor which also sets BLE-related parameters
// when this class is instantiated with relevant arguments 

public RemoteBluetoothDevice(BluetoothDevice newDevice, int rssi, byte[] scanRecord)
             throws IllegalArgumentException {

        if (newDevice.getType() == BluetoothDevice.DEVICE_TYPE_LE ||
                newDevice.getType() == BluetoothDevice.DEVICE_TYPE_DUAL) {

            // Nested local inner class to represent bluetooth low energy
            // related capabilties of the remote bluetooth device 

            class leCharacteristics {

                private int                         bluetoothRemoteLeDeviceRssi;
                private byte[]                      bluetoothRemoteLeDeviceScanRecord;

                public leCharacteristics(int rssi, byte[] scanRecord) {

                    this.bluetoothRemoteLeDeviceRssi = rssi;
                    this.bluetoothRemoteLeDeviceScanRecord = scanRecord;

                }

                public void bluetoothRemoteLeDeviceRssiSetter(int newBluetoothRemoteLeDeviceRssi) {
                    this.bluetoothRemoteLeDeviceRssi = newBluetoothRemoteLeDeviceRssi;
                }

                public int bluetoothRemoteLeDeviceRssiGetter() {
                    return this.bluetoothRemoteLeDeviceRssi;
                }

                public void bluetoothRemoteLeDeviceScanRecordSetter(byte[] newBluetoothRemoteLeDeviceScanRecord) {
                    this.bluetoothRemoteLeDeviceScanRecord = newBluetoothRemoteLeDeviceScanRecord;
                }

                public byte[] bluetoothRemoteLeDeviceScanRecordGetter() {
                    return this.bluetoothRemoteLeDeviceScanRecord;
                }

            }

            this.device = newDevice;

            // Instantiate the nested inner class by invoking its constructor
            // and relevant arguments corresponding to the BLE remote device

            leCharacteristics leCharacteristicsReference = new leCharacteristics(rssi, scanRecord);

            if (device.getUuids() != null)
                this.bluetoothRemoteDeviceUuids = newDevice.getUuids();
            else
                this.bluetoothRemoteDeviceUuids = null;

            if (this.device.getType() == BluetoothDevice.DEVICE_TYPE_LE) {  
                this.remoteBluetoothDeviceType = RemoteBluetoothDeviceType.DEVICE_TYPE_LE;
            } else if (this.device.getType() == BluetoothDevice.DEVICE_TYPE_DUAL) {
                this.remoteBluetoothDeviceType = RemoteBluetoothDeviceType.DEVICE_TYPE_DUAL;
            } else {
                this.remoteBluetoothDeviceType = RemoteBluetoothDeviceType.DEVICE_TYPE_LE;
            }

        } else {
            throw new IllegalArgumentException();
        }
}

Here, I decided to define two different constructors for the outer class. When a remote device, which does support BLE, is discovered, the second constructor is called, which also comes with two more arguments, namely, RSSI and scanRecord. In this case, the inner local class is defined, for which a constructor is further defined (I think I could simply place a block {..} where the inner class' internal members could be initialized). On the other hand, when a classic device is discovered, the first and simpler constructor of the outer class is called, where we do not have any declaration and instantiation for any inner class.

Was it helpful?

Solution

I eventually implemented this using both "Local Inner Classes" as well as stand-alone class which can be instantiated by the main RemoteBluetoothDevice class. It turned out that the latter was a cleaner solution as it did not require sequential instantiations, which could be overlooked throughout the code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top