# delete all the *.class file in a directory
find . -name "*.class" -type f -delete
Invoice Class does not follow this, if calculation logic changes because of tax, or printing logic changes or we change the database we’re saving to, in all these cases Invoice class will change. Instead, we should create InvoicePrinter and Invoice DAO class.
InvoiceDAO class, we have a method called saveToDB but we have a new requirement of saving to file (or caching)InvoiceDAO which does not follow Open/Closed principle, we create an interface and implement it both the classes for DB and File
// 1. Code Violating LSP
// Base class
public class Account {
public void deposit(double amount) {}
public void withdraw(double amount) {}
}
// Subclass: SavingsAccount (LSP Compliant)
public class SavingsAccount extends Account {
@Override
public void withdraw(double amount) {}
}
// Subclass: FixedDepositAccount (LSP Violation)
public class FixedDepositAccount extends Account {
@Override
public void withdraw(double amount) {
throw new UnsupportedOperationException("Withdrawals are not allowed in Fixed Deposit Account");
}
}
// Client code
public class BankService {
public static void processWithdrawal(Account account, double amount) {
account.withdraw(amount);
}
public static void main(String[] args) {
SavingsAccount savings = new SavingsAccount();
processWithdrawal(savings, 100); // Works fine
FixedDepositAccount fixedDeposit = new FixedDepositAccount();
processWithdrawal(fixedDeposit, 100); // Throws UnsupportedOperationException (LSP Violation)
}
}
// 2. Correct code adhering to LSP
// Base class for accounts
public abstract class Account {
public abstract void deposit(double amount);
}
// Interface for accounts that allow withdrawals
public interface Withdrawable {
void withdraw(double amount);
}
// Subclass: SavingsAccount (Withdrawable)
public class SavingsAccount extends Account implements Withdrawable {
@Override
public void deposit(double amount) {}
@Override
public void withdraw(double amount) {}
}
// Subclass: FixedDepositAccount (No withdrawals allowed)
public class FixedDepositAccount extends Account {
@Override
public void deposit(double amount) {}
// No withdraw method here, adhering to LSP
}
// Client code
public class BankService {
// Withdrawable object can be replaced by instance of any class
// that implements this interface
public static void processWithdrawal(Withdrawable account, double amount) {
account.withdraw(amount);
}
public static void main(String[] args) {
SavingsAccount savings = new SavingsAccount();
processWithdrawal(savings, 100); // Works fine
FixedDepositAccount fixedDeposit = new FixedDepositAccount();
// processWithdrawal(fixedDeposit, 100); // Compile-time error (LSP compliance)
}
}
// 3. Similarly we can create another class adhering LSP
public class CurrentAccount extends Account implements Withdrawable {
// Override deposit and withdraw here...
}
// inside BankService
// processWithdrawal can be called on instance of CurrentAccount class as well.
CurrentAccount curr = new CurrentAccount();
processWithdrawal(curr, 100); // Works fine
RestrauntEmployee has some methods which do not align well with the implementation of waiter class. Hence, to follow interface segregation, these should be broken down into separate interfaces like below -

Keyboard interface which is implemented by WiredKeyboard and BluetoothKeyboard classes. Similarly we have Mouse interface and WiredMouse and BluetoothMouse classes.Macbook class implementation depends on concrete classes - WiredKeyboard and WiredMouse.

IS-A relationship is implemented using inheritance.
// Superclass
class Vehicle {
String make;
String model;
public Vehicle(String make, String model) {
this.make = make;
this.model = model;
}
}
// Subclass (Car IS-A Vehicle)
class Car extends Vehicle {
int numberOfDoors;
public Car(String make, String model, int numberOfDoors) {
super(make, model); // Inherit from Vehicle
this.numberOfDoors = numberOfDoors;
}
}
// Component class (Engine)
class Engine {
int horsepower;
String type;
public Engine(int horsepower, String type) {
this.horsepower = horsepower;
this.type = type;
}
}
// Class that HAS-A Engine
class Car {
String make;
String model;
Engine engine; // Composition: Car HAS-A Engine
public Car(String make, String model, Engine engine) {
this.make = make;
this.model = model;
this.engine = engine;
}
}