Practice Problems for Interface Segregation Principle
Interface Segregation Principle (ISP)
Practice Problems
To master the Interface Segregation Principle (ISP), it's essential to engage in practical exercises and projects. Here are some complete coding exercises, sample projects, quizzes, and multiple-choice questions (MCQs) to help reinforce your understanding.
Code Refactoring Exercise
Given:
A code snippet that violates ISP by having a single interface overloaded with methods:
- Java
- JavaScript
- Python
interface Worker {
void work();
void eat();
void sleep();
}
class Employee implements Worker {
@Override
public void work() {
System.out.println("Working");
}
@Override
public void eat() {
System.out.println("Eating");
}
@Override
public void sleep() {
System.out.println("Sleeping");
}
}
class Robot implements Worker {
@Override
public void work() {
System.out.println("Working");
}
@Override
public void eat() {
// Robots don't eat
throw new UnsupportedOperationException("Robots don't eat");
}
@Override
public void sleep() {
// Robots don't sleep
throw new UnsupportedOperationException("Robots don't sleep");
}
}
class Worker {
work() {
throw new Error('This method should be overridden')
}
eat() {
throw new Error('This method should be overridden')
}
sleep() {
throw new Error('This method should be overridden')
}
}
class Employee extends Worker {
work() {
console.log('Working')
}
eat() {
console.log('Eating')
}
sleep() {
console.log('Sleeping')
}
}
class Robot extends Worker {
work() {
console.log('Working')
}
eat() {
// Robots don't eat
throw new Error("Robots don't eat")
}
sleep() {
// Robots don't sleep
throw new Error("Robots don't sleep")
}
}
class Worker:
def work(self):
raise NotImplementedError("This method should be overridden")
def eat(self):
raise NotImplementedError("This method should be overridden")
def sleep(self):
raise NotImplementedError("This method should be overridden")
class Employee(Worker):
def work(self):
print("Working")
def eat(self):
print("Eating")
def sleep(self):
print("Sleeping")
class Robot(Worker):
def work(self):
print("Working")
def eat(self):
# Robots don't eat
raise NotImplementedError("Robots don't eat")
def sleep(self):
# Robots don't sleep
raise NotImplementedError("Robots don't sleep")
Challenge: Refactor the code to adhere to ISP.
Refactored:
- Java
- JavaScript
- Python
interface Worker {
void work();
}
interface Eater {
void eat();
}
interface Sleeper {
void sleep();
}
class Employee implements Worker, Eater, Sleeper {
@Override
public void work() {
System.out.println("Working");
}
@Override
public void eat() {
System.out.println("Eating");
}
@Override
public void sleep() {
System.out.println("Sleeping");
}
}
class Robot implements Worker {
@Override
public void work() {
System.out.println("Working");
}
}
class Worker {
work() {
console.log("Working");
}
}
class Eater {
eat() {
console.log("Eating");
}
}
class Sleeper {
sleep() {
console.log("Sleeping");
}
}
class Employee extends Worker, Eater, Sleeper {
work() {
console.log("Working");
}
eat() {
console.log("Eating");
}
sleep() {
console.log("Sleeping");
}
}
class Robot extends Worker {
work() {
console.log("Working");
}
}
class Worker:
def work(self):
print("Working")
class Eater:
def eat(self):
print("Eating")
class Sleeper:
def sleep(self):
print("Sleeping")
class Employee(Worker, Eater, Sleeper):
def work(self):
print("Working")
def eat(self):
print("Eating")
def sleep(self):
print("Sleeping")
class Robot(Worker):
def work(self):
print("Working")
Design Challenge
Challenge: Design a class hierarchy for a home automation system that
adheres to ISP. The system should have base interfaces for LightControl
,
ThermostatControl
, and SecurityControl
. Each interface should provide
methods relevant to controlling lights, thermostats, and security systems,
respectively.
Coding Exercises
- Exercise 1: Implement a Device Control System:
- Description: Create a base interface
DeviceControl
with methodsturnOn
andturnOff
. Extend this interface for specific devices likeLightControl
andFanControl
, adding device-specific methods. Implement these interfaces in classes representing different types of devices. - Example:
- Description: Create a base interface
- Java
- JavaScript
- Python
interface DeviceControl {
void turnOn();
void turnOff();
}
interface LightControl extends DeviceControl {
void dim();
}
interface FanControl extends DeviceControl {
void setSpeed(int speed);
}
class SmartLight implements LightControl {
@Override
public void turnOn() {
System.out.println("Light is on");
}
@Override
public void turnOff() {
System.out.println("Light is off");
}
@Override
public void dim() {
System.out.println("Dimming light");
}
}
class SmartFan implements FanControl {
@Override
public void turnOn() {
System.out.println("Fan is on");
}
@Override
public void turnOff() {
System.out.println("Fan is off");
}
@Override
public void setSpeed(int speed) {
System.out.println("Setting fan speed to " + speed);
}
}
class DeviceControl {
turnOn() {
console.log('Device is on')
}
turnOff() {
console.log('Device is off')
}
}
class LightControl extends DeviceControl {
dim() {
console.log('Dimming light')
}
}
class FanControl extends DeviceControl {
setSpeed(speed) {
console.log(`Setting fan speed to ${speed}`)
}
}
class SmartLight extends LightControl {
turnOn() {
console.log('Light is on')
}
turnOff() {
console.log('Light is off')
}
dim() {
console.log('Dimming light')
}
}
class SmartFan extends FanControl {
turnOn() {
console.log('Fan is on')
}
turnOff() {
console.log('Fan is off')
}
setSpeed(speed) {
console.log(`Setting fan speed to ${speed}`)
}
}
class DeviceControl:
def turn_on(self):
print("Device is on")
def turn_off(self):
print("Device is off")
class LightControl(DeviceControl):
def dim(self):
print("Dimming light")
class FanControl(DeviceControl):
def set_speed(self, speed):
print(f"Setting fan speed to {speed}")
class SmartLight(LightControl):
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")
def dim(self):
print("Dimming light")
class SmartFan(FanControl):
def turn_on(self):
print("Fan is on")
def turn_off(self):
print("Fan is off")
def set_speed(self, speed):
print(f"Setting fan speed to {speed}")
Sample Projects
- Project 1: Home Automation System:
- Description: Design a home automation system with interfaces for controlling lights, thermostats, and security systems. Implement these interfaces in classes representing smart home devices. Ensure that each interface provides only the methods relevant to the specific device.
- Example:
- Java
- JavaScript
- Python
interface LightControl {
void turnOn();
void turnOff();
void dim();
}
interface ThermostatControl {
void setTemperature(int temperature);
}
interface SecurityControl {
void arm();
void disarm();
}
class SmartLight implements LightControl {
@Override
public void turnOn() {
System.out.println("Light is on");
}
@Override
public void turnOff() {
System.out.println("Light is off");
}
@Override
public void dim() {
System.out.println("Dimming light");
}
}
class SmartThermostat implements ThermostatControl {
@Override
public void setTemperature(int temperature) {
System.out.println("Setting temperature to " + temperature);
}
}
class SmartSecuritySystem implements SecurityControl {
@Override
public void arm() {
System.out.println("Arming security system");
}
@Override
public void disarm() {
System.out.println("Disarming security system");
}
}
class LightControl {
turnOn() {
console.log('Light is on')
}
turnOff() {
console.log('Light is off')
}
dim() {
console.log('Dimming light')
}
}
class ThermostatControl {
setTemperature(temperature) {
console.log(`Setting temperature to ${temperature}`)
}
}
class SecurityControl {
arm() {
console.log('Arming security system')
}
disarm() {
console.log('Disarming security system')
}
}
class SmartLight extends LightControl {
turnOn() {
console.log('Light is on')
}
turnOff() {
console.log('Light is off')
}
dim() {
console.log('Dimming light')
}
}
class SmartThermostat extends ThermostatControl {
setTemperature(temperature) {
console.log(`Setting temperature to ${temperature}`)
}
}
class SmartSecuritySystem extends SecurityControl {
arm() {
console.log('Arming security system')
}
disarm() {
console.log('Disarming security system')
}
}
class LightControl:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")
def dim(self):
print("Dimming light")
class ThermostatControl:
def set_temperature(self, temperature):
print(f"Setting temperature to {temperature}")
class SecurityControl:
def arm(self):
print("Arming security system")
def disarm(self):
print("Disarming security system")
class SmartLight(LightControl):
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")
def dim(self):
print("Dimming light")
class SmartThermostat(ThermostatControl):
def set_temperature(self, temperature):
print(f"Setting temperature to {temperature}")
class SmartSecuritySystem(SecurityControl):
def arm(self):
print("Arming security system")
def disarm(self):
print("Disarming security system")
Quizzes
- Quiz 1: Identifying ISP Violations:
- Question: Given the following interface, identify the ISP violation and suggest a way to fix it.
- Java
- JavaScript
- Python
interface Appliance {
void turnOn();
void turnOff();
void setTemperature(int temperature);
}
class Heater implements Appliance {
@Override
public void turnOn() {
System.out.println("Heater is on");
}
@Override
public void turnOff() {
System.out.println("Heater is off");
}
@Override
public void setTemperature(int temperature) {
System.out.println("Setting temperature to " + temperature);
}
}
class Fan implements Appliance {
@Override
public void turnOn() {
System.out.println("Fan is on");
}
@Override
public void turnOff() {
System.out.println("Fan is off");
}
@Override
public void setTemperature(int temperature) {
// Fans don't set temperature
throw new UnsupportedOperationException("Fans don't set temperature");
}
}
class Appliance {
turnOn() {
throw new Error('This method should be overridden')
}
turnOff() {
throw new Error('This method should be overridden')
}
setTemperature(temperature) {
throw new Error('This method should be overridden')
}
}
class Heater extends Appliance {
turnOn() {
console.log('Heater is on')
}
turnOff() {
console.log('Heater is off')
}
setTemperature(temperature) {
console.log(`Setting temperature to ${temperature}`)
}
}
class Fan extends Appliance {
turnOn() {
console.log('Fan is on')
}
turnOff() {
console.log('Fan is off')
}
setTemperature(temperature) {
// Fans don't set temperature
throw new Error("Fans don't set temperature")
}
}
class Appliance:
def turn_on(self):
raise NotImplementedError("This method should be overridden")
def turn_off(self):
raise NotImplementedError("This method should be overridden")
def set_temperature(self, temperature):
raise NotImplementedError("This method should be overridden")
class Heater(Appliance):
def turn_on(self):
print("Heater is on")
def turn_off(self):
print("Heater is off")
def set_temperature(self, temperature):
print(f"Setting temperature to {temperature}")
class Fan(Appliance):
def turn_on(self):
print("Fan is on")
def turn_off(self):
print("Fan is off")
def set_temperature(self, temperature):
# Fans don't set temperature
raise NotImplementedError("Fans don't set temperature")
- Answer:
- Java
- JavaScript
- Python
interface Appliance {
void turnOn();
void turnOff();
}
interface TemperatureControl {
void setTemperature(int temperature);
}
class Heater implements Appliance, TemperatureControl {
@Override
public void turnOn() {
System.out.println("Heater is on");
}
@Override
public void turnOff() {
System.out.println("Heater is off");
}
@Override
public void setTemperature(int temperature) {
System.out.println("Setting temperature to " + temperature);
}
}
class Fan implements Appliance {
@Override
public void turnOn() {
System.out.println("Fan is on");
}
@Override
public void turnOff() {
System.out.println("Fan is off");
}
}
class Appliance {
turnOn() {
console.log("Appliance is on");
}
turnOff() {
console.log("Appliance is off");
}
}
class TemperatureControl {
setTemperature(temperature) {
console.log(`Setting temperature to ${temperature}`);
}
}
class Heater extends Appliance, TemperatureControl {
turnOn() {
console.log("Heater is on");
}
turnOff() {
console.log("Heater is off");
}
setTemperature(temperature) {
console.log(`Setting temperature to ${temperature}`);
}
}
class Fan extends Appliance {
turnOn() {
console.log("Fan is on");
}
turnOff() {
console.log("Fan is off");
}
}
class Appliance:
def turn_on(self):
print("Appliance is on")
def turn_off(self):
print("Appliance is off")
class TemperatureControl:
def set_temperature(self, temperature):
print(f"Setting temperature to {temperature}")
class Heater(Appliance, TemperatureControl):
def turn_on(self):
print("Heater is on")
def turn_off(self):
print("Heater is off")
def set_temperature(self, temperature):
print(f"Setting temperature to {temperature}")
class Fan(Appliance):
def turn_on(self):
print("Fan is on")
def turn_off(self):
print("Fan is off")
- Quiz 2: ISP and SRP:
- Question: How does adhering to ISP support the Single Responsibility Principle (SRP)? Provide examples.
- Answer:
- Explanation: Adhering to ISP supports SRP by ensuring that interfaces
are focused and specific, reducing the likelihood of classes being
burdened with multiple responsibilities. For example, instead of a
Vehicle
interface with methods for driving and flying, separate interfaces likeDriveable
andFlyable
ensure that each class has a single responsibility.
- Explanation: Adhering to ISP supports SRP by ensuring that interfaces
are focused and specific, reducing the likelihood of classes being
burdened with multiple responsibilities. For example, instead of a
Multiple-Choice Questions (MCQs)
MCQ 1: What does the Interface Segregation Principle state?
- A) Classes should inherit from a single base class
- B) No client should be forced to depend on interfaces it does not use
- C) Classes should be open for extension but closed for modification
- D) Methods should only be implemented once
Answer: B) No client should be forced to depend on interfaces it does not use
MCQ 2: Which of the following is a violation of ISP?
- A) An interface with methods for different functionalities
- B) A class that implements multiple small interfaces
- C) An interface that provides methods for a single functionality
- D) A class that depends on an interface with methods it doesn't use
Answer: D) A class that depends on an interface with methods it doesn't use
MCQ 3: How can you implement ISP in a large system?
- A) By creating a single interface with all methods
- B) By dividing functionality into smaller, focused interfaces
- C) By using inheritance to extend a large interface
- D) By avoiding the use of interfaces
Answer: B) By dividing functionality into smaller, focused interfaces
By working through these extensive practice problems, quizzes, and MCQs, you'll gain hands-on experience with the Interface Segregation Principle, helping you to apply it effectively in your projects. These exercises will deepen your understanding and improve your ability to create maintainable, scalable, and flexible code.