Department of Software Engineering
SE-211: Software Design and Architecture
Class: BESE 14AB
Lab 8 : Object Oriented Design Principles (Class Level)
Date : March 17th, 2025
Instructor: Mehvish Rashid
Name M. Ahmad Raza
Class BESE 14-A
Qalam 466747
SE-211: Software Design and Architecture Page 1
Object Oriented Design Principles (Class Level)
Introduction
Students have learned the theoretical concepts of class level object oriented design principles in
lectures. In this lab, students will learn how to identify and fix pieces of codes where these
principles are violated.
Objectives
After the completion of this lab, students will be able to identify which parts of software are
violating class level object-oriented principles and how to fix them.
Description
It’s a process of planning a software system where objects will interact with each other to solve
specific problems. The saying goes, "Proper Object-oriented design makes a developer's life
easy, whereas bad design makes it a disaster."
Lab Task
Task 1
We have learned the remaining 2 principles of class level object-oriented design formally known
as SOLID principles. The 2 principles are:
Interface segregation principle.
Dependency inversion principle.
Your task:
For each of the principles, you have to give two coding examples where the principles are
violating.
Give a brief explanation of why the piece of code is violating the principle.
A refactored version of the code, where the principles are respected.
Given a brief explanation of why the refactored version of the code is respecting the
principle.
Interface Segregation Principle:
Violating Code:
public interface Vehicle {
void travel();
void fuel();
}
public class Cars implements Vehicle {
@Override
public void travel() {
SE-211: Software Design and Architecture Page 2
System.out.println("Cars can travel.");
}
@Override
public void fuel() {
System.out.println("Cars need fuel.");
}
}
public class Bicycle implements Vehicle {
@Override
public void travel() {
System.out.println("Bicycles can travel.");
}
@Override
public void fuel() {
throw new UnsupportedOperationException("Bicycle don't need
fuel.");
}
}
Why the code is violating ISP:
Bicycle and cars both implement the Vehicle interface. There are two
methods in the interface travel() and fuel(). It is needed for the Cars class
but the fuel method is useless for the Bicycle class violating the ISP. We
should only use that interface that is giving us the required functionality and
not other.
Refactored Code:
public interface VehicleTravel {
void travel();
}
public interface VehicleFuel {
void fuel();
}
public class Cars implements VehicleTravel, VehicleFuel {
@Override
public void travel() {
System.out.println("Cars can travel");
SE-211: Software Design and Architecture Page 3
}
@Override
public void fuel() {
System.out.println("Cars need fuel");
}
}
public class Bicycle implements VehicleTravel, VehicleFuel {
@Override
public void travel() {
System.out.println("Bicycle can travel");
}
}
Why this code is respecting ISP:
Both the classes are implementing the interface they want. They are not just
using some random method in interface which they do not need. Bicycle
class only needs a travel method and not the fuel method. That is why we
have separated the interface into two, So that we can inherit them
differently, respecting the ISP.
Violating Code:
public interface Printer {
void print();
void scan();
}
public class SimplePrinter implements Printer {
@Override
public void print() {
System.out.println("Printing");
}
@Override
public void scan() {
throw new UnsupportedOperationException("Scan not supported");
}
Why this code is respecting ISP:
SE-211: Software Design and Architecture Page 4
The Printer interface defines print(), scan() methods, but SimplePrinter only supports printing.
By implementing the Printer interface, SimplePrinter is forced to provide dummy
implementation for scan(), which it does not support. This violates ISP because the interface is
broad, imposing unnecessary method on the implementing class.
Refactored Code:
public interface Printable {
void print();
}
public interface Scannable {
void scan();
}
public class SimplePrinter implements Printable {
@Override
public void print() {
System.out.println("Printing");
}
}
public class MultiFunctionPrinter implements Printable, Scannable{
@Override
public void print() {
System.out.println("Printing");
}
@Override
public void scan() {
System.out.println("Scanning");
}
}
Why this code is respecting ISP:
The refactored code breaks the Printer interface into two specific interfaces: Printable,
Scannable. SimplePrinter implements only Printable, while a MultiFunctionPrinter can
implement the two as needed. This adheres to ISP by allowing classes to depend only on the
interfaces relevant to their functionality, avoiding unnecessary method implementations.
Dependency Inversion Principle:
Violated Code:
SE-211: Software Design and Architecture Page 5
public class Database {
public void saveUser(String user) {
System.out.println("Saving user to database: " + user);
}
}
public class UserService {
private Database database;
public UserService() {
this.database = new Database();
}
public void addUser(String user) {
database.saveUser(user);
}
}
Why this code is violating DIP:
UserService (a high-level module) directly depends on the concrete Database class (a low-level
module) by creating an instance of it. This violates DIP because UserService is tightly coupled to
a specific data storage implementation. Changing the database will force us to change the
UserService Class.
Refactored Code:
public interface DataStore {
void save(String data);
}
public class Database implements DataStore {
@Override
public void save(String data) {
System.out.println("Saving to database: " + data);
}
}
public class UserService {
private DataStore dataStore;
public UserService(DataStore dataStore) {
this.dataStore = dataStore;
}
SE-211: Software Design and Architecture Page 6
public void addUser(String user) {
dataStore.save(user);
}
}
Why this code is respecting DIP:
The refactored code introduces a DataStore interface, which UserService depends on instead of
the concrete Database class. The specific storage implementation is injected into UserService via
the constructor. This adheres to DIP by decoupling the high-level module from low-level details.
Violating Code:
public class Fan {
public void turnOn() {
System.out.println("Fan is on");
}
public void turnOff() {
System.out.println("Fan is off");
}
}
public class Switch {
private Fan f1;
public Switch() {
this.f1 = new Fan();
}
public void operate() {
f1.turnOn();
}
}
Why this code is violating DIP:
In this code, the Switch class (a high-level module) directly creates and depends on the Fan class
(a low-level module). This tight coupling violates DIP because if we wanted to use the Switch
with a different device, like a Bulb, we’d have to modify the Switch class. This makes the code
rigid and hard to extend.
Refactored Code:
public interface Switchable {
void turnOn();
void turnOff();
SE-211: Software Design and Architecture Page 7
}
public class Fan implements Switchable {
@Override
public void turnOn() {
System.out.println("Fan: Fan turned on");
}
@Override
public void turnOff() {
System.out.println("Fan: Fan turned off");
}
}
public class Switch {
private Switchable device;
public Switch(Switchable device) {
this.device = device;
}
public void operate() {
device.turnOn();
}
}
Why this code is respecting DIP:
Here, we introduce a Switchable interface that defines the contract (turnOn and turnOff). Fan
implement this interface. The Switch class now depends on the Switchable abstraction rather
than a specific implementation.
Deliverables
Compile a single word document by filling in the solution part and submit this Word file on
LMS. This lab grading policy is as follows: The lab is graded between 0 to 10 marks. The
submitted solution can get a maximum of 5 marks. At the end of each lab or in the next lab, there
will be a quiz related to the tasks. The viva has a weightage of 5 marks. Insert the
solution/answer in this document. You must show the implementation of the tasks in the
designing tool, along with your completed Word document to get your work graded. You must
also submit this Word document on the LMS.
SE-211: Software Design and Architecture Page 8
SE-211: Software Design and Architecture Page 9