Java Day2 Java Solid Principal

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 12

Lab Manual- Java Solid Principal

Prepared for:

Date: 18th June 2024


Prepared by:

Document Name: Lab Manual

Document Number SDLab333

Contributor:
Contents
1. Solid Principal in Java..................................................................................................................................3
1.1 Single Responsibility Principle (SRP)................................................................................................3
1.2 Open/Closed Principle (OCP)..........................................................................................................4
1.3 Liskov Substitution Principle (LSP)...................................................................................................6
1.4 Interface Segregation Principle (ISP)...............................................................................................8
1.5 Dependency Inversion Principle (DIP).............................................................................................9
2. Single Responsibility Principle (SRP) – Example........................................................................................11
2.1 Explanation:..................................................................................................................................12
2.2 Compile and Run...........................................................................................................................12
1. Solid Principal in Java
SOLID principle is an acronym that stands for 5 key principles in
software development:
 S – Single Responsibility Principle
 O – Open Closed Principle
 L – Liskov Substitution Principle
 I – Interface Segregation Principle
 D – Dependency Inversion Principle

1.1 Single Responsibility Principle (SRP)

Definition: A class should have only one reason to change, meaning it should have only one job or
responsibility.

Real-life Example: Imagine a restaurant.

 Chef: Responsible only for cooking food.


 Waiter: Responsible only for taking orders and serving food.
 Cashier: Responsible only for billing and handling payments.

If a waiter started cooking or a chef started handling payments, it would violate the SRP. Each role
has a single responsibility.
1.2 Open/Closed Principle (OCP)

Definition: Software entities should be open for extension but closed for modification.

Real-life Example: A plug socket.

 The design of a plug socket is fixed and doesn't change. However, you can extend its
functionality by plugging in different devices (lamps, chargers, etc.) without modifying the
socket itself.

The socket is closed for modification (its design doesn’t change) but open for extension (you can
add different devices).
Definition: Software entities (classes, modules, functions, etc.) should be open for extension but
closed for modification.

Example: Drawing shapes where we can add new shapes without changing existing code.

/* Open/Closed Principle (OCP)


Definition: Software entities (classes, modules, functions, etc.) should be
open for extension but closed for modification.

Example: Drawing shapes where we can add new shapes without changing existing
code.
*/
// Abstract shape
abstract class Shape {
abstract void draw();
}

// Circle shape
class Circle extends Shape {
void draw() {
System.out.println("Drawing Circle");
}
}

// Rectangle shape
class Rectangle extends Shape {
void draw() {
System.out.println("Drawing Rectangle");
}
}

// Drawing class
class Drawing {
private List<Shape> shapes = new ArrayList<>();

public void addShape(Shape shape) {


shapes.add(shape);
}
public void drawAllShapes() {
for (Shape shape : shapes) {
shape.draw();
}
}
}

1.3 Liskov Substitution Principle (LSP)

Definition: Objects of a superclass should be replaceable with objects of a subclass without


affecting the functionality.

Real-life Example: Transportation.

 Superclass: Vehicle
 Subclasses: Car, Bike, Bus

You can substitute any specific type of vehicle for another. If you replace a car with a bike in a
scenario where both are supposed to provide transportation, the system (transportation) should
still work correctly. If a type of vehicle (like a toy car that doesn't move) doesn't fulfill the same role
as a vehicle, it violates the LSP.

Definition: Objects of a superclass should be replaceable with objects of a subclass without


affecting the functionality.

Example: Managing a collection of birds where subclasses can replace the superclass.
In this case, Ostrich violates LSP because it can't fly, leading to an exception. To follow LSP,

we need to restructure our classes or logic to handle such cases correctly.

/* Liskov Substitution Principle (LSP)


Definition: Objects of a superclass should be replaceable with objects of a
subclass without affecting the functionality.

Example: Managing a collection of birds where subclasses can replace the


superclass.

In this case, Ostrich violates LSP because it can't fly, leading to an


exception. To follow LSP,
we need to restructure our classes or logic to handle such cases correctly.

*/
class Bird {
public void fly() {
System.out.println("Flying");
}
}

class Sparrow extends Bird {


@Override
public void fly() {
System.out.println("Sparrow flying");
}
}

class Ostrich extends Bird {


@Override
public void fly() {
throw new UnsupportedOperationException("Ostriches can't fly");
}
}

public class BirdSanctuary {


private List<Bird> birds = new ArrayList<>();

public void addBird(Bird bird) {


birds.add(bird);
}

public void letBirdsFly() {


for (Bird bird : birds) {
bird.fly();
}
}
public static void main(String[] args) {
BirdSanctuary sanctuary = new BirdSanctuary();
sanctuary.addBird(new Sparrow());
sanctuary.addBird(new Ostrich()); // This will cause an issue

sanctuary.letBirdsFly(); // This will fail for Ostrich


}
}

1.4 Interface Segregation Principle (ISP)

Definition: No client should be forced to depend on methods it does not use.

Real-life Example: Appliances.

 A kitchen blender and a vacuum cleaner both operate using electricity. However, they have
different interfaces: a blender might have buttons for speed settings and pulse, while a
vacuum cleaner might have settings for suction power.

If you were forced to use a common interface for all appliances, you would have to include
irrelevant methods for each device. By having separate, specific interfaces, each appliance only
uses the methods it needs.

Definition: No client should be forced to depend on methods it does not use.


Example: Separate interfaces for different functionalities of a printer.

interface Printer {
void print(Document document);
}

interface Scanner {
void scan(Document document);
}

class Document {}

// Implementing both interfaces


class MultiFunctionPrinter implements Printer, Scanner {
public void print(Document document) {
System.out.println("Printing document");
}

public void scan(Document document) {


System.out.println("Scanning document");
}
}

// Implementing only the Printer interface


class SimplePrinter implements Printer {
public void print(Document document) {
System.out.println("Printing document");
}
}

1.5 Dependency Inversion Principle (DIP)

Definition: High-level modules should not depend on low-level modules. Both should depend on
abstractions. Abstractions should not depend on details. Details should depend on abstractions.

Real-life Example: A remote control and various devices.

 High-level module: Remote control


 Low-level modules: TV, air conditioner, stereo system

Instead of the remote control being designed specifically for each device, it uses an abstract
interface like IR (infrared) or Bluetooth. Each device (TV, air conditioner, etc.) implements this
interface. The remote control does not need to know the details of each device; it just sends signals
via the abstract interface.

By using this abstraction, you can use the same remote control for different devices without
redesigning it for each specific one.
Definition: High-level modules should not depend on low-level modules.
Both should depend on abstractions. Abstractions should not depend on details. Details should
depend on abstractions.

Example: Using an interface for switching a device on and off.

By using the Switchable interface, the ElectricSwitch class does not depend on the specific
implementations of devices, adhering to the Dependency Inversion Principle .

interface Switchable {
void turnOn();
void turnOff();
}

class LightBulb implements Switchable {


public void turnOn() {
System.out.println("LightBulb is turned on");
}

public void turnOff() {


System.out.println("LightBulb is turned off");
}
}

class Fan implements Switchable {


public void turnOn() {
System.out.println("Fan is turned on");
}

public void turnOff() {


System.out.println("Fan is turned off");
}
}

class ElectricSwitch {
private Switchable device;

public ElectricSwitch(Switchable device) {


this.device = device;
}

public void operate(boolean on) {


if (on) {
device.turnOn();
} else {
device.turnOff();
}
}
}
2. Single Responsibility Principle (SRP) – Example

Here's a very simple example in Java that follows the Single Responsibility Principle (SRP). This
principle states that a class should have only one reason to change, meaning it should have only
one job or responsibility.

Let's create a program that handles employee management, where we separate the responsibilities
of handling employee data and calculating their salary.

1. Employee class: Responsible for storing employee data.


2. SalaryCalculator class: Responsible for calculating the salary of the employee.

Employee.java

// Employee.java
public class Employee {
private String name;
private int hoursWorked;
private double hourlyRate;

public Employee(String name, int hoursWorked, double hourlyRate) {


this.name = name;
this.hoursWorked = hoursWorked;
this.hourlyRate = hourlyRate;
}

public String getName() {


return name;
}

public int getHoursWorked() {


return hoursWorked;
}

public double getHourlyRate() {


return hourlyRate;
}
}

SalaryCalculator.java

// SalaryCalculator.java
public class SalaryCalculator {
public double calculateSalary(Employee employee) {
return employee.getHoursWorked() * employee.getHourlyRate();
}
}
Main.java

// Main.java
public class Main {
public static void main(String[] args) {
Employee employee = new Employee("John Doe", 40, 20.0);
SalaryCalculator salaryCalculator = new SalaryCalculator();
double salary = salaryCalculator.calculateSalary(employee);
System.out.println("Salary of " + employee.getName() + ": $" +
salary);
}
}

2.1 Explanation:

 Employee.java: This class is only responsible for storing employee data.


 SalaryCalculator.java: This class is responsible for calculating the salary based on the employee data.
 Main.java: This is the entry point of the program, which creates an instance of Employee and
SalaryCalculator, and prints the calculated salary.

This way, each class has a single responsibility, making the code easier to understand and maintain.

2.2 Compile and Run

javac *.java

java Main

You might also like