0% found this document useful (0 votes)
11 views8 pages

078. 1.1. LLD - 2

The document discusses the SOLID principles of software design, emphasizing the importance of single responsibility, open/closed, Liskov substitution, interface segregation, and dependency inversion principles. It provides examples of Java code to illustrate these concepts and encourages software engineers to be polyglots, familiar with multiple programming languages. Additionally, it covers various programming paradigms and the significance of proper class and interface design.

Uploaded by

litesh.arora
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views8 pages

078. 1.1. LLD - 2

The document discusses the SOLID principles of software design, emphasizing the importance of single responsibility, open/closed, Liskov substitution, interface segregation, and dependency inversion principles. It provides examples of Java code to illustrate these concepts and encourages software engineers to be polyglots, familiar with multiple programming languages. Additionally, it covers various programming paradigms and the significance of proper class and interface design.

Uploaded by

litesh.arora
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

Post-lecture Content

SOLID Principles: https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-


b34ce2f1e898

HW:

1. Refactor this code such that it does not violate the SRP principle.
2. Refactor this code such that it does not violate the LSP principle.
3. You are given the implementation for this business requirement here. Change it for the new
requirements.
LLD - 2
Java vs other languages

1. As a software engineer - never tie yourself to 1 programming language or framework


2. I hate Java
3. FAANG / Booking.com / Gojek / Rippling - Java
4. A software engineer should be Polyglot - you should know multiple languages
5. Programming concepts / paradigms / patterns

wrt Java. Apply across languages. Python / Haskell / Rust

Recap
LLD
Programming Paradigms
Object Oriented
Functional
Procedural
Delcarative
Reactive
Event Based
Classes - Abstraction (hiding details) / entities / concepts
Attributes (member variables)
Behavior (methods)
method vs function -> methods are functions bound to an object
Relationships with other classes (is-a: inheritance, has-a: variables)
Objects - Snapshots / instance of a class
tangible
Class Inheritance
Abstract Classes
Incomplete blueprints
missing details - abstract methods
we can't intantiate them
extend and complete them
Interfaces
Abstract class vs Interface
interface has incompete methods only (old stuff)
no state in interface
A class can implement many interfaces, but cannot extend multiple classes
Runtime Polymorphism
Encapsulation - data hiding
Getter Setter
Data Validation

Runtime Polymorphism
class Person {

}
class Student extends Person {

}
class BrilliantStudent extends Student {

}
class Professor extends Person {

void foo() {
// a Person variable can store any object of Person or any child class
Person person = new Person();
Person person = new Student(); // each student is also a person
Person person = new Professor(); // each professor is also a person
}

Runtime and compile time polymorphism


generic classes
ArrayList<Integer> ArrayList<Person>

function overloading
method overriding
Java - usually runtime
Rust - always compiletime

Today
SOLID Principles

guidelines that have been created for you - readable, extensible, maintabile
guidelines not rules

Who is the client?

End user (doesn't deal with the code)


Programmers
outside your company
inside your company
a backend team could be a client for another backend team

API - Application Programming Interface Website - backend server - frontend (browser) - expose some API endpoint

Client may or may not be able to change your code

S - Single Responsility
A class / method / whatever -> 1 and only 1 task
doing more than 1 thing is bad
O - Open Close
Any code/class should be open for extension and closed for mofidication
customizing behavior should be possible by extending the code and not need direct modification
L - Liskov's Substitution
Runtime Polymorphism
Any child class-object should be substitutable for a parent-class object.
I - Interface Segregation
Anyone who needs an interface should not be forced to implement functions that it does not need
Interfaces should be minimal
D - Dependency Inversion
Code should not have hard dependencies

Dependency Injection Inversion of Control MVC

Code that does payments

Your code

public class Currency {


public static Currency INR = new Currency("INR", 70);
public static Currency EUR = new Currency("EUR", 90);

@Getter @Setter
private String symbol;
@Getter @Setter
private double converstionRateToUSD;

public Currency(String symbol, double conversionRateToUSD) {


this.symbol = symbol;
this.conversionRateToUSD = conversionRateToUSD;
}
}

class Money {
@Getter @Setter
private Currency currency;
@Getter @Setter
private double amount;

public Money(Currency currency, double amount) {


this.currency = currency;
this.amount = amount;
}
}

client

class Client {
public void payment() {
Money request = new Money(Currency.INR, 100);
Money balance = new Money(Currency.EUR, 50);

// conversion
double normalizedBalance = balance.getAmount() * balance.getCurrency().getConversionRateToUSD();
double normalizedRequest = request.getAmount() * request.getCurrency().getConversionRateToUSD();

// checking
if(normalizedBalance >= normalizedRequest) {
// make payment
}
}
}

SRP
The client is asking the object for data (avoid this)
Always ask your objects to do stuff for you

class Money{
boolean isGreaterThanOrEqualTo(Money m2) {
// conversions
// returning a boolean
}
}

class MoneyComparisonUtils {
public static isGreaterThanOrEqualTo(Money m1, Money m2) {}
}

class Client {
public void payment() {
Money request = new Money(Currency.INR, 100);
Money balance = new Money(Currency.EUR, 50);
if(balance.isGreaterThanOrEqualTo(request)) {
// make payment
}
}
}

Class / Struct

A class can have encapsulation / data valiation / behaviour (methods) A struct just holds information / dataclass

// dataclass
class Point {
int x;
int y;
}

HR Management system

Full Time
Part Time

abstract class Employee {


private String name, employeeId;
public abstract void save(String saveDir);
}
class FullTimeEmployee extends Employee {
private String address;
public void save(String saveDir) {
// serialize object
StringBuilder serialized = new StringBuilder();
serialized.append("## Employee Record ##");
serialized.append(System.lineSeparator());
serialized.append("Name: " + this.getName());
// save to file
try {
Path path = Paths.get(this.getName().replace(" ", "_")) + ".rec";
Files.write(path, serialized.toString().getBytes());
System.out.println("Saved employee: " + this.toString());
} catch(IOException e) {
System.out.println("ERROR: could not save employee. Reason: " + e.getMessage());
}
}
}
class PartTimeEmployee extends Employee {
private double advancePaid;

public void save(String saveDir) {


// serialize object
StringBuilder serialized = new StringBuilder();
serialized.append("## Employee Record ##");
serialized.append(System.lineSeparator());
serialized.append("Name: " + this.getName());
serialized.append("Advance Paid: " + this.getAdvancePaid());
// save to file
try {
Path path =Paths.get(this.getName().replace(" ", "_")) + ".rec";
Files.write(path, serialized.toString().getBytes());
System.out.println("Saved employee: " + this.toString());
} catch(IOException e) {
System.out.println("ERROR: could not save employee. Reason: " + e.getMessage());
}
}
}

function save the employee data to a file

normal class - method - directly interacting with the DB

via ORM - Object Relational Mapper


DAO - Data Access Object
Open Close
Classes should be closed for changes but open for extension

class Bird {
void fly(String birdType) {
if(birdType.equals("kiwi")) {
//
} else if (birdType.equals("hen")) {
//
}
}
}

class Bird {
abstract void fly();
}
class Hen extends Bird {
//
}

Bad code? because if we want to add a new bird type - change the already implemented code

More code vs Difficult Code - both are bad More code is preferrable to Difficult Code

void solve() {
// intiliaze an array of size 10
int ar[10];
// go over each iter
for(int i = 0; i < 10; i++) {
// input from stdin
ar[i] = Integer.parseInt(br.readLine());
}
// go over each item
for(int i = 0; i < 10; i++) {
// multiple by itself
ar[i] = ar[i] * ar[i];
}

// take 10 numbers from the stdin, and sqaure them.


// suports programming by intention
}

ar = [i * i for i in ar]
map = {
key: value
}

Creators of java were creating the language


- goal: the language will be used by people who are stupider than the creators

Liskov's Substitution Principle


runtime polymorphism

class Bird {
abstract void fly() {

}
}

class Kiwi extends Bird {


void fly() {
throw new KiwiCantFlyException("no wings :(");
}
}

class client {
void foo(Bird bird) {
bird.fly();
}
}

class Stack<T> extends ArrayList<T> {


void push(T val) {
this.append(val);
}
T pop() {
return this.remove(this.length());
}
}

get(int i)
set(int i, int val)
A stack CAN BE implemented as an array but A stack is NOT an array

Stack is-a Array (wrong)

Interface Segregation Principle


interfaces should be minimal
your interface users should not be forced to implement methods they dont want
split your class/interface into multiple interfaces

abstract class Bird {

interface CanFly {
void fly() {}
}

class Kiwi extends Bird {

class Eagle extends Bird implements CanFly {


void fly() {}
}

void foo() {
Bird b = new Kiwi();
b.fly(); // compiler error
}

Dependency Inversion / Injection


Dependency Inversion / Dependency Injection / Inversion of Control

High level modules should not depend on low level modules


Abstractions should not depend on details

// dependencies
abstract class Engine {}
class V8Engine extends Engine {}
class TurboChargedEngine extends Engine {}

abstract class Tyre {}


class RubberTyre extends Tyre {}
class SelfInflatingTyre extends Tyre {}

abstract class Body {}


class PlasticBody extends Body {}
class BullproofBody extends Body {}

// library code
class Car {
TurboChargedEngine engine;
SelfInflatingTyre backLeftTyre, backRightTyre, ..;
BullproofBody body;

public Car() {

}
}

// client wants a normal car


class NormalCar {
PlasticBody body;

// better library code


class Car {
// inversion
Engine engine;
Tyre backLeftTyre, backRightTyre, ..;
Body body;
// injection
public Car(Engine engine, Tyre backLeftTyre, backRightTyre, Body body) {
this.engine = engine;
this.back...
}
}

void foo() {
Car normalCar = new Car(new NormalEngine(), new NormalTyre(), new PlasticBody());
Car sportsCar = new Car(new V8EngineEngine(), new SelfInflatingTyre(), new BulletProofBody());
}

class SavePlayerInformation {
DBConnection connection;
public void save(Player player) {
String serialized = player.toString();
connection.saveToTable("table-name", serialized);
}
}

class SavePlayerInformation {
Writable connection;
public SavePlayerInformation(Writable connection) {
this.connection = connection;
}
public void save(Player player) {
String serialized = player.toString();
connection.write(serialized);
}
}

Dependency Inversion - classes should only have relations to high-level abstractions Dependency Injection - setter method -
constructor - Spring also provides @autowired

Inversion of Control - in case of frameworks

Create a GUI library / webserver library (Django / Spring / Rails)

Create a GUI library that allows you to create games - Game Engine

// Library
class GameEngine {
public void drawCharachter(Character c) {
// draw c on the screen
}

public int getKeypress() {


// return the keycode
}
}

// Client
class Main {
public static void main(String args[]) {
Character characters[];
while(true) {
// wait for event
int keycode = gameEngine.getKeypress();

// handle event

// re-render the screen


for(Character c : characters) {
gameEngine.drawCharachter(c);
}
}
}
}

// Framework
class GameEngine {
public Game() {

}
public abstract void handleKeypress(int keycode);

public static void main(String args[]) {


while(true) {
this.characters.render();
handleKeypress();
}
}
}

// Client
class MyGame extends Game {
public MyGame () {

}
public handleKeypress(int keycode) {
// custom logic here
}
public ArrayList<Character> getCharactersToDraw() {

}
}

django / spring controller / request

Inversion of Control

SOLID & Inversion of Control

1. Client has control and uses the library as helper utils


2. Library/Framework has control, and the client is just telling what changes it wished to make
don't have Homework/Assignments section Extra material section links to some problem statements and github repos pull
request to this github repo share this pull request in your scaler chat groups

class Bird {
}

class Weapon {
}

class FighterJet

inheritance Fighterjet is-a bird? (inheritance) Fighterjet is-a weapon?

composition has-a relationship (car has an engine) (variables) can-do relationship (fightjet can fly, fighterjet can attack)
(implementing interfaces / multiple inheritance)

The real world is not a tree. The real world is more of a DAG.

Liskov - child class object should be able to replace to parent class object

MVC / MVP DAO / DTO / VO / ...

Compiletime polymorphism - happens at compile time

class List<T> {
public List() {}
abstract public int size();
}

class List<Integer> {
public List() {}
abstract public int size();
}

class List<Boolean> {
public List() {}
abstract public int size();
}

// client
List<Integer> something

Compile Time polymorphism

Runtime polymophism

class Person{}
class Manager extends Person {}
class Employee extends Person {}
void foo(Employee val) {

void foo(Manager val) {

void spam() {
Person p;
if(condition) {
p = new Employee();
} else {
p = new Manager();
}
foo(p);
}

type based dispactch -> runtime polymorphism (in most languages) Rust

compiler

You might also like