1. Implement the enumeration SwitchState, which describes the states which a switch can take (besides on and off, unknown and error states are also allowed).
2. Write the interfaces DeviceInfo and switch which will be used to describe smart devices.
3. Implement the class SmartDevice which describes a basic, general smart device.
4. Write the generic interface Listener which is used to listen for signals from a smart device.
5. Implement the class SmartSwitch, which implements our smart switch.
6. Implement the class Controller, which manages a number of smart devices.
7. Students in the honors section will have an additional smart device to implement for full credit.
8. Download and use the tester module to ensure that your program is correct.
9. Prepare the assignment for submission and submit it.
The concept of smart devices is decades old, but it hadn't caught on much until recently. Now, however, Internet and cell phone technology has matured to the point that smart devices are common and practical. It's not at all uncommon see homes with smart lights or cameras or thermometers. Yes, there are issues which we will need to tackle in the near future (security comes to mind), but controlling a smart home is a task for the here and now. Interestingly, much of smart home control is done by way of cell phone apps, and many cell phone apps (think Android) are written in Java.
For this project, we will simulate a smart home system which uses smart switches. Like in previous projects, we will build from the ground up by making the smart device classes, and build up to a controller which manages the devices. The smart devices will be capable of signaling: when their state changes, they will send out signals to notify others of state changes. Our controller will be a listener which listens for those state changes and reports them.
We will incorporate two more language features into this project: generics and enumerations. We will use enumerations to describe switch state. If we just wanted on and off, we could use a boolean, but by using an enumeration we can permit additional states such as unknown or error states. We will use generics for signal listeners for signals sent by smart devices, because by using generics, we can define different types of listeners for different classes of devices.
public enum SwitchState
This enumeration will contain the possible values which a switch can take, which will include the obvious on and OFF values, but also UNKNOWN and ERROR. Additionally, the enumeration will provide the following public methods:
public interface DeviceInfo
This interface will be a part of smart devices to get identifying information about the device. It has two methods, which allow us to get the device name and the device ID. The device ID is a number which will be used by the controller to identify a particular device, especially if more than one device has the same name.
The interface will have the following public methods:
public interface Switch, which is a DeviceInfo
This interface will be part of switch devices (light switches, etc). It contains methods related to setting, flipping, or querying the state of a switch. This interface will have the following public methods:
public class SmartDevice, which is a DeviceInfo
This class will be the basis for any smart device we write. It will not have much functionality for now, only enough to identify the device. We will add onto the functionality later in subclasses of this class. At the minimum, every smart device will have a name and an integer) ID value to identify it.
Our SmartDevice will implement the following public methods:
> SmartDevice d = new SmartDevice("device");
> d.setID(5);
> System.out.println(d.toString());
device 5
public interface Listener, which is a generic interface with two type parameters
Our smart devices will send out signals if something happens (i.e. their state changes, etc). In order to react to those signals, our controllers will be listeners which listen for signals. The smart devices do not need to know the details of our controllers to know that they are listeners which can accept signals. Thus, we will use a listener interface which can react to a signal sent out by our smart devices.
This interface is going to be a generic interface. By using generics, we can write re-usable code which is essentially the same except for the data type. We can send signals from different types of smart devices, and we can use it to send different types of signals. Instead of rewriting the interface for every type of device and every class of signals, we use a generic interface which allows us to treat these types as placeholders until we're ready to use them. Our listener will have two type parameters: the first one will represent the smart device category which is generating the signal, and the second will represent the type of signal which is being sent.
The interface will define one method:
public class SmartSwitch, which is a SmartDevice and a switch
First and foremost, the SmartSwitch device is a Switch. That means that it has a SwitchState state, meaning that it can be on or OFF (or even be in an UNKNOWN ON ERROR State). The state can be changed or flipped (from on to OFF and back again), or queried. We can ask for the current state and change the state.
On top of the switching functionality, we will also include signalling functionality, which will send out a signal whenever the state changes. To do this, we will keep a list of Listener
Our smart switch should implement the following:
> SmartSwitch ss = new SmartSwitch("light");
> ss.setID(1);
> ss.change (SwitchState.OFF);
> System.out.println(ss.toString();
light 1: off
> ss.flip();
> System.out.println(ss.toString());
light 1: on
Tip: it may be useful to have a private sendSignals method to call the signal method of all registered listeners. This method could be called whenever the smart switch's state changes.
public class Controller, which is a Listener< Switch, SwitchState>
Our controller keeps a list of smart devices, and will print reports about the existing smart devices, or allow us to add, remove, or retreive a particular smart device. Also, it serves as a listener, so we can use it to report changes whenever the state of a smart device has changed. The controller assigns each smart device a unique ID (the ID number grows every time a new device is added, so that the first device is device 0, the next is device 1, etc). We do not need to go back and "plug holes" in the ID numbers if devices are removed and others are added later. Here is an example of how the controller might work:
> Controller c = new Controller();
> SmartSwitch ss0 = new SmartSwitch("front door light");
> SmartSwitch ssl = new SmartSwitch("kitchen light");
> SmartSwitch ss2 = new SmartSwitch("pool light");
> c.addDevice(80);
> c.addDevice(sl);
> c.addDevice(ss2);
front door light 0: unknown
kitchen light 1: unknown
pool light 2: unknown
> ss0.change (SwitchState.ON); // a state change will trigger the signal listener, which prints a message front door light o changed state to on
> ss0.change (SwitchState.ON); // if there is no state change, then no signal
> ssl.flip(); // if there is no state change, then there is no signal
> ssl.change (SwitchState.ON);
kitchen light 1 changed state to on
> ssl.flip();
kitchen light I changed state to off
> ss2.change (SwitchState.OFF);
pool light 2 changed state to off
front door light 0: on
kitchen light 1: off
pool light 2: off
This class will have the following public methods: