Design of a remoteControl class for connecting to electronic devices In a course that I'm taking on learning object oriented programming in java, I have completed an assignment for modeling a home entertainment system and the ability for a user to be able to use a single remote control to control multiple digital devices such as a TV or sound system etc.

I don't feel too confident about this design so I wanted to run it past the experts.
Below is my code. Any feedback you can provide on improving this design and why would be super helpful!

package user;

import remotes.RemoteControl;
import devices.Projector;
import devices.TV;

public class Person {

    public static void main (String args[]){

        //Devices in the home
        Projector niceProjector = new Projector();
        TV niceLargeScreenTV = new TV();

        // The user's control
        RemoteControl control;

        control = RemoteControl.connectWithdevice(niceProjector);
            control.clickOnButon();

        control = RemoteControl.connectWithdevice(niceLargeScreenTV);
            control.clickOffButon();

    }

}


RemoteControl class:

package remotes;

import devices.Device;

public class RemoteControl {

    private Device theDevice= null;

    private RemoteControl(){

    }

    public static RemoteControl connectWithdevice(Device aDevice){
        RemoteControl remote = new RemoteControl();
        remote.theDevice = aDevice;
        return remote;
    }

    public void clickOffButon(){
        theDevice.turnOnDevice();
    }

    public void clickOnButon(){
        theDevice.turnOnDevice();
    }

}


One of the device classes:

package devices;


public class TV implements Device{

    @Override
    public void turnOnDevice() {
        SwitchToFavoriteChannel();
        System.out.println("TV has been turned on");
    }

    @Override
    public void turnOffDevice() {
        turnOnTVAlarm();
        System.out.println("TV has been turned off");
    }


    // below are additional steps that may be required for you to operate your device
    private void SwitchToFavoriteChannel(){
        System.out.println("Switched to your favorite Channel");
    }

    private void turnOnTVAlarm(){
        System.out.println("TV Alarm set for you to wake up in the morning");
    }


}
@Override
public void turnOffDevice() {
    turnOnTVAlarm();
    System.out.println("TV has been turned off");
}


Welcome to the hell that never ends.

Just kidding. But please don't make TVs that automatically turn on an alarm to wake you up in the morning. I have alarm clocks for that, which are beating resistant.

Method naming

    control = RemoteControl.connectWithdevice(niceProjector);
        control.clickOnButon();

    control = RemoteControl.connectWithdevice(niceLargeScreenTV);
        control.clickOffButon();


Did you mean clickOnButton and clickOffButton?

Actually, your method naming could use some work. Let's go over some of them. But first, Java convention. It's Java convention that your function names are camelCase.

So, let's look at your method names:

connectWithdevice


This should be connectWithDevice, as each word after the first starts with a capital.

SwitchToFavoriteChannel


This should be switchToFavoriteChannel, as the first word does not have a capital. (That's how we easily distinguish classes and methods from each other).

turnOnTVAlarm


This one is tricky. For now, I'd let it stay... TV is only two characters. But when you have an acronym, treat it as one word. That is, turnOnTvAlarm. This because you end up with class names like HTTPConnection later, and getHttpConnection reads a lot better than getHTTPConnection. Especially if you're not familiar with the acronym.

Instantiating RemoteControl

private Device theDevice= null;

private RemoteControl(){

}

public static RemoteControl connectWithdevice(Device aDevice){
    RemoteControl remote = new RemoteControl();
    remote.theDevice = aDevice;
    return remote;
}


Have you considered passing the device in as constructor argument instead?

Then you can do something like this:

private final Device device;

public RemoteControl(Device aDevice){
    device = aDevice;
}


And people will always be forced to set a device.

With Objects.requireNotNull you can even make them not pass in a null value (you can also write the check yourself, but it's easier with Objects.requireNotNull.

private final Device device;

public RemoteControl(Device aDevice){
    device = Objects.requireNotNull(aDevice, "A remote control requires a device to work with.");
}


Design

Good designs feel natural.

Let's see how natural your design feels.

I have a Projector. And I have a TV. And I may have a RemoteControl... wait, I need to ask RemoteControl to connect to a device so it can send messages to the device? Why can't I just grab the remote control for the TV?

There's two options that I'm aware of in real life:


You take a programmable remote and set it to control a specific device. This would be like passing a different Device into an existing RemoteControl.
You pick up the remote that belongs to the TV. We'll assume we're clean, orderly people who store the remote with the device (far more likely for projectors than for TV's...). This would be like asking the Device to give a RemoteControl.


Both are more natural than wishing for a RemoteControl for a device.