Practice Problems for Single Responsibility
Single Responsibility Principle (SRP)
Practice Problems
To master the Single Responsibility Principle, it's essential to engage in practical exercises and projects. Here are some complete coding exercises, sample projects, and quizzes to help reinforce your understanding.
Coding Exercises
Exercise 1: Refactor a Monolithic Class:
Given:
- Java
- JavaScript
- Python
public class UserService {
public boolean authenticateUser(String username, String password) {
// Authentication logic
}
public UserData getUserData(String userId) {
// Data retrieval logic
}
public void logActivity(String userId, String activity) {
// Logging logic
}
}
class UserService {
authenticateUser(username, password) {
// Authentication logic
}
getUserData(userId) {
// Data retrieval logic
}
logActivity(userId, activity) {
// Logging logic
}
}
class UserService:
def authenticate_user(self, username, password):
# Authentication logic
def get_user_data(self, user_id):
# Data retrieval logic
def log_activity(self, user_id, activity):
# Logging logic
Refactored:
- Java
- JavaScript
- Python
public class AuthenticationService {
public boolean authenticateUser(String username, String password) {
// Authentication logic
}
}
public class UserDataService {
public UserData getUserData(String userId) {
// Data retrieval logic
}
}
public class ActivityLogService {
public void logActivity(String userId, String activity) {
// Logging logic
}
}
class AuthenticationService {
authenticateUser(username, password) {
// Authentication logic
}
}
class UserDataService {
getUserData(userId) {
// Data retrieval logic
}
}
class ActivityLogService {
logActivity(userId, activity) {
// Logging logic
}
}
class AuthenticationService:
def authenticate_user(self, username, password):
# Authentication logic
class UserDataService:
def get_user_data(self, user_id):
# Data retrieval logic
class ActivityLogService:
def log_activity(self, user_id, activity):
# Logging logic
Exercise 2: Implement a Facade Pattern:
Given:
- Java
- JavaScript
- Python
public class OrderProcessing {
public void processOrder(Order order) {
// Order processing logic
}
}
public class PaymentProcessing {
public void processPayment(Payment payment) {
// Payment processing logic
}
}
public class ShippingProcessing {
public void processShipping(Order order) {
// Shipping processing logic
}
}
class OrderProcessing {
processOrder(order) {
// Order processing logic
}
}
class PaymentProcessing {
processPayment(payment) {
// Payment processing logic
}
}
class ShippingProcessing {
processShipping(order) {
// Shipping processing logic
}
}
class OrderProcessing:
def process_order(self, order):
# Order processing logic
class PaymentProcessing:
def process_payment(self, payment):
# Payment processing logic
class ShippingProcessing:
def process_shipping(self, order):
# Shipping processing logic
Facade:
- Java
- JavaScript
- Python
public class OrderFacade {
private OrderProcessing orderProcessing = new OrderProcessing();
private PaymentProcessing paymentProcessing = new PaymentProcessing();
private ShippingProcessing shippingProcessing = new ShippingProcessing();
public void placeOrder(Order order, Payment payment) {
orderProcessing.processOrder(order);
paymentProcessing.processPayment(payment);
shippingProcessing.processShipping(order);
}
}
class OrderFacade {
constructor() {
this.orderProcessing = new OrderProcessing()
this.paymentProcessing = new PaymentProcessing()
this.shippingProcessing = new ShippingProcessing()
}
placeOrder(order, payment) {
this.orderProcessing.processOrder(order)
this.paymentProcessing.processPayment(payment)
this.shippingProcessing.processShipping(order)
}
}
class OrderFacade:
def __init__(self):
self.order_processing = OrderProcessing()
self.payment_processing = PaymentProcessing()
self.shipping_processing = ShippingProcessing()
def place_order(self, order, payment):
self.order_processing.process_order(order)
self.payment_processing.process_payment(payment)
self.shipping_processing.process_shipping(order)
Exercise 3: Decorator Pattern:
Given:
- Java
- JavaScript
- Python
public interface Car {
void assemble();
}
public class BasicCar implements Car {
@Override
public void assemble() {
System.out.print("Basic Car.");
}
}
class Car {
assemble() {
console.log('Basic Car.')
}
}
class Car:
def assemble(self):
print("Basic Car.")
Decorator:
- Java
- JavaScript
- Python
public class CarDecorator implements Car {
protected Car car;
public CarDecorator(Car car) {
this.car = car;
}
@Override
public void assemble() {
this.car.assemble();
}
}
public class SportsCar extends CarDecorator {
public SportsCar(Car car) {
super(car);
}
@Override
public void assemble() {
super.assemble();
System.out.print(" Adding features of Sports Car.");
}
}
public class LuxuryCar extends CarDecorator {
public LuxuryCar(Car car) {
super(car);
}
@Override
public void assemble() {
super.assemble();
System.out.print(" Adding features of Luxury Car.");
}
}
class CarDecorator {
constructor(car) {
this.car = car
}
assemble() {
this.car.assemble()
}
}
class SportsCar extends CarDecorator {
assemble() {
super.assemble()
console.log(' Adding features of Sports Car.')
}
}
class LuxuryCar extends CarDecorator {
assemble() {
super.assemble()
console.log(' Adding features of Luxury Car.')
}
}
class CarDecorator:
def __init__(self, car):
self.car = car
def assemble(self):
self.car.assemble()
class SportsCar(CarDecorator):
def assemble(self):
super().assemble()
print(" Adding features of Sports Car.")
class LuxuryCar(CarDecorator):
def assemble(self):
super().assemble()
print(" Adding features of Luxury Car.")
Sample Projects
- Project 1: E-commerce System:
- Description: Design an e-commerce system with separate classes for order processing, payment handling, inventory management, and user authentication. Each class should have a single responsibility.
- Example:
- Java
- JavaScript
- Python
public class OrderService {
public void processOrder(Order order) {
// Order processing logic
}
}
public class PaymentService {
public void handlePayment(Payment payment) {
// Payment handling logic
}
}
public class InventoryService {
public void updateInventory(Order order) {
// Inventory management logic
}
}
public class UserService {
public void authenticateUser(String username, String password) {
// User authentication logic
}
}
class OrderService {
processOrder(order) {
// Order processing logic
}
}
class PaymentService {
handlePayment(payment) {
// Payment handling logic
}
}
class InventoryService {
updateInventory(order) {
// Inventory management logic
}
}
class UserService {
authenticateUser(username, password) {
// User authentication logic
}
}
class OrderService:
def process_order(self, order):
# Order processing logic
class PaymentService:
def handle_payment(self, payment):
# Payment handling logic
class InventoryService:
def update_inventory(self, order):
# Inventory management logic
class UserService:
def authenticate_user(self, username, password):
# User authentication logic
- Project 2: Blogging Platform:
- Description: Build a blogging platform with distinct classes for post management, comment handling, user profiles, and notification services. Adhere to SRP for each class.
- Example:
- Java
- JavaScript
- Python
public class PostService {
public void createPost(Post post) {
// Post creation logic
}
}
public class CommentService {
public void addComment(Comment comment) {
// Comment handling logic
}
}
public class UserProfileService {
public void updateUserProfile(User user) {
// User profile management logic
}
}
public class NotificationService {
public void sendNotification(Notification notification) {
// Notification logic
}
}
class PostService {
createPost(post) {
// Post creation logic
}
}
class CommentService {
addComment(comment) {
// Comment handling logic
}
}
class UserProfileService {
updateUserProfile(user) {
// User profile management logic
}
}
class NotificationService {
sendNotification(notification) {
// Notification logic
}
}
class PostService:
def create_post(self, post):
# Post creation logic
class CommentService:
def add_comment(self, comment):
# Comment handling logic
class UserProfileService:
def update_user_profile(self, user):
# User profile management logic
class NotificationService:
def send_notification(self, notification):
# Notification logic
- Project 3: Task Management App:
- Description: Develop a task management application where classes are responsible for task creation, task tracking, user management, and reporting. Ensure each class has one responsibility.
- Example:
- Java
- JavaScript
- Python
public class TaskService {
public void createTask(Task task) {
// Task creation logic
}
}
public class TaskTrackingService {
public void trackTask(Task task) {
// Task tracking logic
}
}
public class UserService {
public void manageUser(User user) {
// User management logic
}
}
public class ReportingService {
public void generateReport() {
// Reporting logic
}
}
class TaskService {
createTask(task) {
// Task creation logic
}
}
class TaskTrackingService {
trackTask(task) {
// Task tracking logic
}
}
class UserService {
manageUser(user) {
// User management logic
}
}
class ReportingService {
generateReport() {
// Reporting logic
}
}
class TaskService:
def create_task(self, task):
# Task creation logic
class TaskTrackingService:
def track_task(self, task):
# Task tracking logic
class UserService:
def manage_user(self, user):
# User management logic
class ReportingService:
def generate_report(self):
# Reporting logic
Quizzes
- Quiz 1: Identifying Responsibilities:
- Question: Given the following class, identify its responsibilities and suggest how to refactor it according to SRP.
- Java
- JavaScript
- Python
public class LibraryService {
public void addBook(Book book) {
// Add book logic
}
public void issueBook(Book book, User user) {
// Issue book logic
}
public void returnBook(Book book, User user) {
// Return book logic
}
public void sendNotification(User user, String message) {
// Send notification logic
}
}
class LibraryService {
addBook(book) {
// Add book logic
}
issueBook(book, user) {
// Issue book logic
}
returnBook(book, user) {
// Return book logic
}
sendNotification(user, message) {
// Send notification logic
}
}
class LibraryService:
def add_book(self, book):
# Add book logic
def issue_book(self, book, user):
# Issue book logic
def return_book(self, book, user):
# Return book logic
def send_notification(self, user, message):
# Send notification logic
- Answer:
- Java
- JavaScript
- Python
public class BookService {
public void addBook(Book book) {
// Add book logic
}
public void issueBook(Book book, User user) {
// Issue book logic
}
public void returnBook(Book book, User user) {
// Return book logic
}
}
public class NotificationService {
public void sendNotification(User user, String message) {
// Send notification logic
}
}
class BookService {
addBook(book) {
// Add book logic
}
issueBook(book, user) {
// Issue book logic
}
returnBook(book, user) {
// Return book logic
}
}
class NotificationService {
sendNotification(user, message) {
// Send notification logic
}
}
class BookService:
def add_book(self, book):
# Add book logic
def issue_book(self, book, user):
# Issue book logic
def return_book(self, book, user):
# Return book logic
class NotificationService:
def send_notification(self, user, message):
# Send notification logic
Quiz 2: Design Patterns and SRP:
- Question: How do the Facade, Adapter, and Decorator patterns relate to SRP? Provide examples.
- Answer:
- Facade Pattern: Simplifies a complex subsystem by providing a unified interface. Each class within the subsystem adheres to SRP.
- Adapter Pattern: Allows incompatible interfaces to work together. Adapters convert one interface into another without altering the original classes, each of which has a single responsibility.
- Decorator Pattern: Adds behavior to objects dynamically. Each decorator class and the original class follow SRP, making it easy to extend functionality in a modular way.
Quiz 3: Integration with SOLID Principles:
- Question: How does SRP integrate with other SOLID principles like OCP, DIP, and ISP? Provide examples.
- Answer:
- OCP: By adhering to SRP, classes can be extended with new functionality without modifying existing code, supporting the Open/Closed Principle.
- DIP: SRP facilitates Dependency Inversion by ensuring that high-level modules do not depend on low-level modules but rather on abstractions. Clear, single-responsibility classes make it easier to define these abstractions.
- ISP: SRP promotes the use of specific, client-focused interfaces rather than a single general-purpose interface, aligning with the Interface Segregation Principle.
Multiple-Choice Questions (MCQs)
MCQ 1: What is the primary goal of the Single Responsibility Principle (SRP)?
- A) To ensure a class has multiple responsibilities
- B) To ensure a class has only one reason to change
- C) To allow a class to handle both data and logic
- D) To create large, monolithic classes
Answer: B) To ensure a class has only one reason to change
MCQ 2: Which design pattern is most aligned with SRP?
- A) Singleton Pattern
- B) Observer Pattern
- C) Facade Pattern
- D) Strategy Pattern
Answer: C) Facade Pattern
MCQ 3: What is a common pitfall when applying SRP?
- A) Creating classes with multiple responsibilities
- B) Overly fragmenting the codebase with too many small classes
- C) Ignoring the need for class cohesion
- D) All of the above
Answer: D) All of the above