├── .DS_Store
├── .idea
├── .gitignore
├── misc.xml
├── modules.xml
└── vcs.xml
├── DesignPatterns
├── .DS_Store
├── .gitignore
├── .idea
│ ├── misc.xml
│ ├── modules.xml
│ ├── vcs.xml
│ └── workspace.xml
├── BehavioralPatterns
│ ├── ChainOfResponsibilityPattern.java
│ ├── CommandPattern.java
│ ├── IteratorPattern.java
│ ├── MediatorPattern.java
│ ├── MementoPattern.java
│ ├── ObserverPattern.java
│ ├── StatePattern.java
│ ├── StrategyPattern.java
│ ├── TemplatePattern.java
│ └── VisitorPattern.java
├── CreationalPatterns
│ ├── .DS_Store
│ ├── AbstractFactoryPattern.java
│ ├── BuilderPattern.java
│ ├── FactoryPattern.java
│ ├── PrototypePattern.java
│ └── SingletonPattern.java
├── DesignPatterns.iml
└── StructuralPatterns
│ ├── .DS_Store
│ ├── AdapterPattern.java
│ ├── BridgePattern.java
│ ├── CompositePattern.java
│ ├── DecoratorPattern.java
│ ├── FacadePattern.java
│ ├── FlyweightPattern.java
│ └── ProxyPattern.java
├── HLD
├── .DS_Store
├── ChatApp
│ ├── ChatApp.md
│ ├── ChatService.drawio
│ └── ChatService.png
├── ECommerceStore
│ ├── ECommerceStore.md
│ ├── ecommerce.drawio
│ └── ecommerce.drawio.png
├── GoogleDocs
│ ├── GoogleDoc.drawio
│ ├── GoogleDoc.png
│ └── GoogleDocs.md
├── RateLimiter
│ └── RateLimiter.md
├── Twitter
│ ├── Twitter.md
│ ├── TwitterHLD.drawio
│ └── TwitterHLD.drawio.png
├── URLShortener
│ ├── URLShortener.md
│ ├── URLshortener.drawio
│ └── URLshortener.png
├── Uber
│ ├── Uber.drawio
│ ├── Uber.md
│ └── Uber.png
├── WebHook
│ ├── WebHook.md
│ ├── Webhook.drawio
│ └── Webhook.png
└── Youtube
│ ├── Youtube.md
│ ├── youtube.drawio
│ └── youtube.png
├── LICENSE
├── LLD
├── ATM
│ ├── .gitignore
│ ├── .idea
│ │ ├── .gitignore
│ │ ├── gradle.xml
│ │ ├── misc.xml
│ │ ├── uiDesigner.xml
│ │ └── vcs.xml
│ ├── README.md
│ ├── build.gradle.kts
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle.kts
│ └── src
│ │ └── main
│ │ └── java
│ │ └── org
│ │ └── anuva04
│ │ ├── Controllers
│ │ ├── ATM.java
│ │ └── Transaction.java
│ │ ├── Enums
│ │ ├── Denomination.java
│ │ └── PaymentNetwork.java
│ │ ├── Main.java
│ │ ├── Models
│ │ ├── AtmCards
│ │ │ ├── AtmCard.java
│ │ │ ├── AxisVisaCard.java
│ │ │ └── SbiRupayCard.java
│ │ ├── Bank.java
│ │ ├── CashAvailabilityDataResponseModel.java
│ │ ├── CashReserve.java
│ │ └── Currency.java
│ │ └── Strategies
│ │ ├── CashDispenserStrategy.java
│ │ └── SimpleCashDispenseStrategy.java
├── ElevatorSystem
│ ├── .gitignore
│ ├── .idea
│ │ ├── .gitignore
│ │ ├── encodings.xml
│ │ ├── misc.xml
│ │ └── vcs.xml
│ ├── README.md
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── org
│ │ └── anuva04
│ │ ├── Controllers
│ │ └── ElevatorSystem.java
│ │ ├── Enums
│ │ ├── ElevatorDirection.java
│ │ ├── ElevatorStatus.java
│ │ └── ElevatorType.java
│ │ ├── Main.java
│ │ ├── Models
│ │ ├── AccelElevator.java
│ │ ├── ClassicElevator.java
│ │ ├── Elevator.java
│ │ └── ServiceElevator.java
│ │ ├── Strategies
│ │ ├── ElevatorAllocationStrategy.java
│ │ └── SimpleElevatorAllocationStrategy.java
│ │ └── Utils
│ │ └── Constants.java
├── MeetingScheduler
│ ├── .gitignore
│ ├── .idea
│ │ ├── .gitignore
│ │ ├── gradle.xml
│ │ ├── misc.xml
│ │ ├── uiDesigner.xml
│ │ └── vcs.xml
│ ├── README.md
│ ├── build.gradle.kts
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle.kts
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── org
│ │ │ └── anuva04
│ │ │ ├── Controllers
│ │ │ ├── CommandLineParser.java
│ │ │ └── MeetingScheduler.java
│ │ │ ├── Main.java
│ │ │ ├── Models
│ │ │ ├── Meeting.java
│ │ │ └── MeetingDb.java
│ │ │ └── Utils
│ │ │ ├── Constants.java
│ │ │ ├── Helper.java
│ │ │ └── Parsers
│ │ │ ├── AbstractCommandParser.java
│ │ │ ├── ChangeMeetingLocationCommandParser.java
│ │ │ ├── ChangeMeetingTimeCommandParser.java
│ │ │ ├── CreateMeetingCommandParser.java
│ │ │ ├── DeleteMeetingCommandParser.java
│ │ │ ├── ForwardMeetingCommandParser.java
│ │ │ ├── GetMeetingsForUsernameForDateCommandParser.java
│ │ │ └── ShowCalendarCommandParser.java
│ │ └── resources
│ │ ├── Requirements.txt
│ │ └── SampleInput.txt
└── VendingMachine
│ ├── .gitignore
│ ├── .idea
│ ├── .gitignore
│ ├── encodings.xml
│ ├── misc.xml
│ └── vcs.xml
│ ├── README.md
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── org
│ │ └── anuva04
│ │ ├── Constants.java
│ │ ├── Controllers
│ │ ├── AdminOperations.java
│ │ ├── UserOperations.java
│ │ └── VendingMachine.java
│ │ ├── Main.java
│ │ └── Models
│ │ ├── Item.java
│ │ └── Tray.java
│ └── resources
│ └── Requirements.txt
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/.DS_Store
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/DesignPatterns/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/DesignPatterns/.DS_Store
--------------------------------------------------------------------------------
/DesignPatterns/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
--------------------------------------------------------------------------------
/DesignPatterns/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DesignPatterns/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DesignPatterns/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DesignPatterns/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 | 1708695433845
32 |
33 |
34 | 1708695433845
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/ChainOfResponsibilityPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern lets you pass requests along a chain of processors until it reaches an appropriate processor which can handle it.
3 | * User doesn't need to know about all the available processors.
4 | * Only the head of the chain needs to be known to the users, and each processor can know its succeeding one.
5 | * In this example, user is provided the head of the chain that is Leave Request processor.
6 | * If the request provided by user is a leave request, it is handled immediately, else it is passed down the chain until an appropriate processor is found.
7 | * If no processor can process it, an appropriate message is returned to the user.
8 | * If new processors come in, they can be attached to the chain without any change required on the user side.
9 | */
10 |
11 | class ChainOfResponsibilityPattern {
12 | public static void main(String[] args) {
13 | RequestProcessor requestProcessor = getRequestProcessor();
14 |
15 | Request request = new LeaveRequest("123", "test leave request", "01/01/1970", "02/01/1970");
16 | System.out.println("Got request: " + request.description);
17 | requestProcessor.handle(request);
18 |
19 | Request request1 = new DatabaseAccessRequest("123", "test db request", "test_db", "read");
20 | System.out.println("Got request: " + request1.description);
21 | requestProcessor.handle(request1);
22 |
23 | Request request2 = new OtherRequest("123", "test other request");
24 | System.out.println("Got request: " + request2.description);
25 | requestProcessor.handle(request2);
26 | }
27 |
28 | public static RequestProcessor getRequestProcessor() {
29 | LeaveRequestProcessor leaveRequestProcessor = new LeaveRequestProcessor();
30 | RelocationRequestProcessor relocationRequestProcessor = new RelocationRequestProcessor();
31 | DatabaseAccessRequestProcessor databaseAccessRequestProcessor = new DatabaseAccessRequestProcessor();
32 |
33 | leaveRequestProcessor.setNextProcessor(relocationRequestProcessor);
34 | relocationRequestProcessor.setNextProcessor(databaseAccessRequestProcessor);
35 | databaseAccessRequestProcessor.setNextProcessor(null);
36 |
37 | return leaveRequestProcessor;
38 | }
39 | }
40 |
41 | abstract class RequestProcessor {
42 | protected RequestProcessor next;
43 |
44 | public void setNextProcessor(RequestProcessor next) {
45 | this.next = next;
46 | }
47 |
48 | public abstract void handle(Request request);
49 | }
50 |
51 | public class LeaveRequestProcessor extends RequestProcessor {
52 | @Override
53 | public void handle(Request request) {
54 | if(request instanceof LeaveRequest) {
55 | System.out.println("[LeaveRequestProcessor] Processing request...");
56 | } else {
57 | System.out.println("[LeaveRequestProcessor] Can't process request, handing over to next processor.");
58 | if(this.next != null) {
59 | this.next.handle(request);
60 | } else {
61 | System.out.println("[LeaveRequestProcessor] No available processor to handle the request.");
62 | }
63 | }
64 | }
65 | }
66 |
67 | public class RelocationRequestProcessor extends RequestProcessor {
68 | @Override
69 | public void handle(Request request) {
70 | if(request instanceof RelocationRequest) {
71 | System.out.println("[RelocationRequestProcessor] Processing request...");
72 | } else {
73 | System.out.println("[RelocationRequestProcessor] Can't process request, handing over to next processor.");
74 | if(this.next != null) {
75 | this.next.handle(request);
76 | } else {
77 | System.out.println("[RelocationRequestProcessor] No available processor to handle the request.");
78 | }
79 | }
80 | }
81 | }
82 |
83 | public class DatabaseAccessRequestProcessor extends RequestProcessor {
84 | @Override
85 | public void handle(Request request) {
86 | if(request instanceof DatabaseAccessRequest) {
87 | System.out.println("[DatabaseAccessRequestProcessor] Processing request...");
88 | } else {
89 | System.out.println("[DatabaseAccessRequestProcessor] Can't process request, handing over to next processor.");
90 | if(this.next != null) {
91 | this.next.handle(request);
92 | } else {
93 | System.out.println("[DatabaseAccessRequestProcessor] No available processor to handle the request.");
94 | }
95 | }
96 | }
97 | }
98 |
99 | class Request {
100 | String employeeId;
101 | String description;
102 |
103 | public Request(String employeeId, String description) {
104 | this.employeeId = employeeId;
105 | this.description = description;
106 | }
107 | }
108 |
109 | class LeaveRequest extends Request {
110 | public String startdate;
111 | public String endDate;
112 |
113 | public LeaveRequest(String employeeId, String description, String startdate, String endDate) {
114 | super(employeeId, description);
115 | this.startdate = startdate;
116 | this.endDate = endDate;
117 | }
118 | }
119 |
120 | class RelocationRequest extends Request {
121 | public String location;
122 | public String startDate;
123 |
124 | public RelocationRequest(String employeeId, String description, String location, String startDate) {
125 | super(employeeId, description);
126 | this.location = location;
127 | this.startDate = startDate;
128 | }
129 | }
130 |
131 | class DatabaseAccessRequest extends Request {
132 | public String dbName;
133 | public String accessType;
134 |
135 | public DatabaseAccessRequest(String employeeId, String description, String dbName, String accessType) {
136 | super(employeeId, description);
137 | this.dbName = dbName;
138 | this.accessType = accessType;
139 | }
140 | }
141 |
142 | class OtherRequest extends Request {
143 | public OtherRequest(String employeeId, String description) {
144 | super(employeeId, description);
145 | }
146 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/CommandPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used when we want to include all data in an object required to perform an action.
3 | * Hence, the executor need not know the details of how to perform the action. It can simply call the execute method of the object.
4 | * In this example, multiple ArithmeticOperation objects are created and each of them contains all details required to perform the action.
5 | * The executor simply picks up an object and execute it using the operate() method.
6 | * This is useful while building an architecture of message queues with multiple worker threads which can pick up tasks when possible and execute them without needing to know how to perform it.
7 | */
8 |
9 | import java.util.concurrent.*;
10 | class CommandPattern {
11 | public static void main(String[] args) {
12 | ExecutorService ex = Executors.newFixedThreadPool(3);
13 |
14 | BlockingQueue queue = new LinkedBlockingQueue<>();
15 | queue.offer(new AdditionOperation(1, 2, 5));
16 | queue.offer(new AdditionOperation(2, 3, 6));
17 | queue.offer(new SubtractionOperation(3, 4, 1));
18 | queue.offer(new MultiplicationOperation(4, 4, 4));
19 | queue.offer(new MultiplicationOperation(5, 2, 2));
20 | queue.offer(new DivisionOperation(6, 6, 3));
21 |
22 | for(int i = 0; i < 3; i++) {
23 | ex.submit(new ArithmeticOperationExecutor(queue));
24 | }
25 |
26 | ex.shutdown();
27 | }
28 | }
29 |
30 | abstract class ArithmeticOperation {
31 | protected int operand1;
32 | protected int operand2;
33 | protected int timeTaken;
34 | protected int id;
35 |
36 | public ArithmeticOperation(int id, int operand1, int operand2, int timeTaken) {
37 | this.operand1 = operand1;
38 | this.operand2 = operand2;
39 | this.timeTaken = timeTaken;
40 | this.id = id;
41 | }
42 |
43 | abstract void operate();
44 | }
45 |
46 | class AdditionOperation extends ArithmeticOperation {
47 | public AdditionOperation(int id, int operand1, int operand2) {
48 | super(id, operand1, operand2, 2);
49 | }
50 |
51 | @Override
52 | public void operate() {
53 | try {
54 | System.out.println("#" + this.id + " Sleeping for " + this.timeTaken + " seconds...");
55 | Thread.sleep(this.timeTaken);
56 | System.out.println("#" + this.id + " " + (this.operand1 + this.operand2));
57 | } catch (Exception e) {
58 | System.out.println(e.getMessage());
59 | System.out.println("#" + this.id + " " + Integer.MAX_VALUE);
60 | }
61 | }
62 | }
63 |
64 | class SubtractionOperation extends ArithmeticOperation {
65 | public SubtractionOperation(int id, int operand1, int operand2) {
66 | super(id, operand1, operand2, 3);
67 | }
68 |
69 | @Override
70 | public void operate() {
71 | try {
72 | System.out.println("#" + this.id + " Sleeping for " + this.timeTaken + " seconds...");
73 | Thread.sleep(this.timeTaken);
74 | System.out.println("#" + this.id + " " + (this.operand1 - this.operand2));
75 | } catch (Exception e) {
76 | System.out.println(e.getMessage());
77 | System.out.println("#" + this.id + " " + Integer.MAX_VALUE);
78 | }
79 | }
80 | }
81 |
82 | class MultiplicationOperation extends ArithmeticOperation {
83 | public MultiplicationOperation(int id, int operand1, int operand2) {
84 | super(id, operand1, operand2, 4);
85 | }
86 |
87 | @Override
88 | public void operate() {
89 | try {
90 | System.out.println("#" + this.id + " Sleeping for " + this.timeTaken + " seconds...");
91 | Thread.sleep(this.timeTaken);
92 | System.out.println("#" + this.id + " " + (this.operand1 * this.operand2));
93 | } catch (Exception e) {
94 | System.out.println(e.getMessage());
95 | System.out.println("#" + this.id + " " + Integer.MAX_VALUE);
96 | }
97 | }
98 | }
99 |
100 | class DivisionOperation extends ArithmeticOperation {
101 | public DivisionOperation(int id, int operand1, int operand2) {
102 | super(id, operand1, operand2, 5);
103 | }
104 |
105 | @Override
106 | public void operate() {
107 | try {
108 | System.out.println("#" + this.id + " Sleeping for " + this.timeTaken + " seconds...");
109 | Thread.sleep(this.timeTaken);
110 | System.out.println("#" + this.id + " " + (this.operand1 / this.operand2));
111 | } catch (Exception e) {
112 | System.out.println(e.getMessage());
113 | System.out.println("#" + this.id + " " + Integer.MAX_VALUE);
114 | }
115 | }
116 | }
117 |
118 | class ArithmeticOperationExecutor implements Runnable {
119 | private final BlockingQueue queue;
120 |
121 | public ArithmeticOperationExecutor(BlockingQueue queue) {
122 | this.queue = queue;
123 | }
124 |
125 | @Override
126 | public void run() {
127 | while(!Thread.currentThread().isInterrupted()) {
128 | try {
129 | ArithmeticOperation operation = queue.poll();
130 | if(operation == null) break;
131 | operation.operate();
132 | } catch(Exception e) {
133 | Thread.currentThread().interrupt();
134 | }
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/IteratorPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used to abstract traversal logic of a collection.
3 | * By doing that, we take care of separation of concerns. The collection itself stores information about the data and their connectivity only.
4 | * And the iterator class takes care of traversal.
5 | * In this example, a TreeNode is an element of a collection. It is only concerned with value and left and right children
6 | * Traversal is taken care of by BfsTree class which implements TreeIterable interface and implements the iteration logic.
7 | */
8 |
9 | import java.util.LinkedList;
10 | import java.util.Queue;
11 | class IteratorPattern {
12 | public static void main(String[] args) {
13 | TreeNode root = new TreeNode(1);
14 | root.left = new TreeNode(2);
15 | root.right = new TreeNode(3);
16 | root.left.left = new TreeNode(4);
17 | root.left.right = new TreeNode(5);
18 | root.right.right = new TreeNode(6);
19 | root.left.left.left = new TreeNode(8);
20 |
21 | BfsTree tree = new BfsTree(root);
22 |
23 | while(tree.hasNext()) {
24 | System.out.println(tree.next().value);
25 | }
26 | }
27 | }
28 |
29 | interface TreeIterable {
30 | public boolean hasNext();
31 | public T next();
32 | }
33 |
34 | public class TreeNode {
35 | public int value;
36 | public TreeNode left;
37 | public TreeNode right;
38 |
39 | public TreeNode(int value) {
40 | this.value = value;
41 | left = right = null;
42 | }
43 | }
44 |
45 | public class BfsTree implements TreeIterable {
46 | Queue queue;
47 |
48 | public BfsTree(TreeNode root) {
49 | queue = new LinkedList<>();
50 | queue.offer(root);
51 | }
52 |
53 | @Override
54 | public boolean hasNext() {
55 | if(queue.peek() == null) return false;
56 | return true;
57 | }
58 |
59 | @Override
60 | public TreeNode next() {
61 | if(queue.peek() == null) return null;
62 | if(queue.peek().left != null) queue.offer(queue.peek().left);
63 | if(queue.peek().right != null) queue.offer(queue.peek().right);
64 | return queue.poll();
65 | }
66 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/MediatorPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Mediator pattern is used when we want to reduce chaotic communication between various objects in a system.
3 | * In such a situation, we want all communication to be handled by a central object called the mediator; no object communicates directly to each other.
4 | * This helps remove dependencies and enables reuse of objects.
5 | * In this example, the submit button and loginOrRegister checkbox don't communicate with each other, and neither do they communicate with the title.
6 | * All state changes of any object are notified to the mediator which in turn changes states of other objects as required.
7 | * By doing this, we didn't have to write code of updating title in loginOrRegister checkbox, which means this checkbox can be reused somewhere else which doesn't need title related logic.
8 | */
9 |
10 | class MediatorPattern {
11 | public static void main(String[] args) {
12 | LoginForm form = new LoginForm();
13 | form.loginOrRegister.check();
14 | form.submit.click();
15 | form.loginOrRegister.check();
16 | form.submit.click();
17 | }
18 | }
19 |
20 | interface Mediator {
21 | public void notify(Component component, Event event);
22 | }
23 |
24 | class LoginForm implements Mediator {
25 | public String title;
26 | public Checkbox loginOrRegister;
27 | public Textbox loginUsername, loginPassword;
28 | public Textbox registerUsername, registerPassword;
29 | public Button submit, cancel;
30 |
31 | public LoginForm() {
32 | loginOrRegister = new Checkbox(this);
33 | loginUsername = new Textbox(this);
34 | loginPassword = new Textbox(this);
35 | registerUsername = new Textbox(this);
36 | registerPassword = new Textbox(this);
37 | submit = new Button(this);
38 | cancel = new Button(this);
39 | }
40 |
41 | @Override
42 | public void notify(Component component, Event event) {
43 | if(component == loginOrRegister && event == Event.CHECK) {
44 | if(loginOrRegister.checked) title = "Login";
45 | else title = "Register";
46 | System.out.println("Title: " + title);
47 | }
48 | if(component == submit && event == Event.CLICK) {
49 | if(loginOrRegister.checked) {
50 | System.out.println("Logging in...");
51 | } else System.out.println("Registering...");
52 | }
53 | }
54 | }
55 |
56 | class Component {
57 | protected Mediator mediator;
58 |
59 | public Component(Mediator mediator) {
60 | this.mediator = mediator;
61 | }
62 |
63 | public void click() {
64 | mediator.notify(this, Event.CLICK);
65 | }
66 |
67 | public void keypress() {
68 | mediator.notify(this, Event.KEYPRESS);
69 | }
70 | }
71 |
72 | class Button extends Component {
73 | public Button(Mediator mediator) {
74 | super(mediator);
75 | }
76 | }
77 |
78 | class Checkbox extends Component {
79 | public boolean checked = false;
80 |
81 | public Checkbox(Mediator mediator) {
82 | super(mediator);
83 | }
84 | public void check() {
85 | if(checked) checked = false;
86 | else checked = true;
87 | mediator.notify(this, Event.CHECK);
88 | }
89 | }
90 |
91 | class Textbox extends Component {
92 | public Textbox(Mediator mediator) {
93 | super(mediator);
94 | }
95 |
96 | public String input;
97 | }
98 |
99 | enum Event {
100 | CLICK,
101 | KEYPRESS,
102 | CHECK
103 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/MementoPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used when we want to store snapshot of an object's state in different times.
3 | * Instead of having a separate class manage this externally, it is better to have an utility within the concerned class itself to create a snapshot.
4 | * This promotes seperation of concerns.
5 | * Also, we need a caretaker class which maintains all mementos/snapshots of the object.
6 | * In this example, we are taking snapshots of the TextBox class using Memento class.
7 | * Editor class is storing a list of all mementos and asks the TextBox class to restore to a certain memento based on user input (undo/redo).
8 | */
9 |
10 | import java.util.*;
11 | class MementoPattern {
12 | public static void main(String[] args) {
13 | Editor editor = new Editor();
14 | editor.write("Hi");
15 | editor.save();
16 | editor.write(" I am");
17 | editor.save();
18 | editor.write(" Anuva");
19 | editor.save();
20 | editor.undo();
21 | editor.undo();
22 | editor.undo();
23 | editor.redo();
24 | editor.redo();
25 | editor.redo();
26 | editor.redo();
27 | }
28 | }
29 |
30 | class Editor {
31 | private List mementoList;
32 | private int pointer;
33 | private TextBox textBox;
34 |
35 | public Editor() {
36 | mementoList = new ArrayList<>();
37 | mementoList.add(new Memento(""));
38 | pointer = 0;
39 | textBox = new TextBox();
40 | }
41 |
42 | public void write(String s) {
43 | textBox.addText(s);
44 | System.out.println(textBox.showText());
45 | }
46 |
47 | public void save() {
48 | mementoList.add(textBox.save());
49 | pointer++;
50 | System.out.println("Saved");
51 | }
52 |
53 | public void undo() {
54 | if(pointer > 0) pointer--;
55 | textBox.restore(mementoList.get(pointer));
56 | System.out.println(textBox.showText());
57 | }
58 |
59 | public void redo() {
60 | if(pointer < mementoList.size() - 1) pointer++;
61 | textBox.restore(mementoList.get(pointer));
62 | System.out.println(textBox.showText());
63 | }
64 | }
65 |
66 | class TextBox {
67 | private StringBuilder text;
68 |
69 | public TextBox() {
70 | this.text = new StringBuilder();
71 | }
72 |
73 | public void addText(String s) {
74 | text.append(s);
75 | }
76 |
77 | public String showText() {
78 | return text.toString();
79 | }
80 |
81 | public Memento save() {
82 | return new Memento(text.toString());
83 | }
84 |
85 | public void restore(Memento m) {
86 | this.text = new StringBuilder(m.getText());
87 | }
88 | }
89 |
90 | class Memento {
91 | private String text;
92 | public Memento(String text) {
93 | this.text = text;
94 | }
95 |
96 | public String getText() {
97 | return this.text;
98 | }
99 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/ObserverPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used when multiple objects needs to be updated (called subscribers) when a certain change occurs in an object's state (called observable).
3 | * Instead of updating all subscribers of the change, or letting subscribers poll the publisher continuously,
4 | * the subscribers can subscribe to a system (called publisher) which will notify them whenever the observable's state changes.
5 | * In this example, channels are the observables.
6 | * YoutubeNotification class is the publisher which stores a list of all Subscribers for each channel.
7 | * User class implements Subscriber so that its notify() method can be used to notify it.
8 | * Whenever a new video is added to the channel, publisher notifies all subscribers.
9 | */
10 |
11 | import java.util.*;
12 | class ObserverPattern {
13 | public static void main(String[] args) {
14 | YoutubeNotification ytNotification = new YoutubeNotification();
15 | User user1 = new User("user1");
16 | User user2 = new User("user2");
17 | ytNotification.addSubscriber("channel1", user1);
18 | ytNotification.addSubscriber("channel1", user2);
19 |
20 | User user3 = new User("user3");
21 | ytNotification.addSubscriber("channel2", user3);
22 |
23 | ytNotification.addVideo("channel1");
24 | ytNotification.addVideo("channel2");
25 |
26 | ytNotification.removeSubscriber("channel1", user1);
27 | ytNotification.addVideo("channel1");
28 | }
29 | }
30 |
31 | class YoutubeNotification {
32 | private Map> channelSubsMap;
33 |
34 | public YoutubeNotification() {
35 | this.channelSubsMap = new HashMap<>();
36 | }
37 | public void addSubscriber(String channel, Subscriber subscriber) {
38 | if(!channelSubsMap.containsKey(channel)) {
39 | channelSubsMap.put(channel, new ArrayList<>());
40 | }
41 | channelSubsMap.get(channel).add(subscriber);
42 | }
43 |
44 | public void removeSubscriber(String channel, Subscriber subscriber) {
45 | channelSubsMap.get(channel).remove(subscriber);
46 | }
47 |
48 | public void addVideo(String channel) {
49 | for(Subscriber s : channelSubsMap.get(channel)) s.notify(channel);
50 | }
51 | }
52 |
53 | interface Subscriber {
54 | public void notify(String channel);
55 | }
56 |
57 | class User implements Subscriber {
58 | public String name;
59 |
60 | public User(String name) {
61 | this.name = name;
62 | }
63 |
64 | @Override
65 | public void notify(String channel) {
66 | System.out.println(this.name + ", " + channel + " has posted a new video!");
67 | }
68 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/StatePattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used when we need to change an object's behavior when its state changes.
3 | * Instead of accomplising this by maintaining a state variable and adding a lot of conditional statements,
4 | * we can store a different class instance (called state) inside our concerned class.
5 | * All information and logic required for object's behavior will be stored in the state object.
6 | * In this example, state stores the logic for phone ring/vibration/silence.
7 | * PhoneRinger stores an instance of state.
8 | * Whenever state changes, the state object is also changed inside PhoneRinger.
9 | */
10 | class StatePattern {
11 | public static void main(String[] args) {
12 | PhoneRinger ringer = new PhoneRinger("arial");
13 | ringer.ring();
14 |
15 | ringer.changeState(new SilentState(ringer));
16 | ringer.ring();
17 |
18 | ringer.changeState(new VibrationState(ringer));
19 | ringer.ring();
20 | }
21 | }
22 |
23 | class PhoneRinger {
24 | private State state;
25 | public String ringtone;
26 |
27 | public PhoneRinger(String ringtone) {
28 | state = new RingState(this);
29 | this.ringtone = ringtone;
30 | }
31 |
32 | public void changeState(State state) {
33 | this.state = state;
34 | }
35 |
36 | public void ring() {
37 | this.state.ring();
38 | }
39 | }
40 |
41 | abstract class State {
42 | protected PhoneRinger phoneRinger;
43 |
44 | public State(PhoneRinger phoneRinger) {
45 | this.phoneRinger = phoneRinger;
46 | }
47 |
48 | abstract void ring();
49 | }
50 |
51 | class RingState extends State {
52 | public RingState(PhoneRinger phoneRinger) {
53 | super(phoneRinger);
54 | }
55 | @Override
56 | public void ring() {
57 | System.out.println("Received call: Playing ringtone " + this.phoneRinger.ringtone);
58 | }
59 | }
60 |
61 | class VibrationState extends State {
62 | public VibrationState(PhoneRinger phoneRinger) {
63 | super(phoneRinger);
64 | }
65 | @Override
66 | public void ring() {
67 | System.out.println("Received call: Phone is vibrating");
68 | }
69 | }
70 |
71 | class SilentState extends State {
72 | public SilentState(PhoneRinger phoneRinger) {
73 | super(phoneRinger);
74 | }
75 | @Override
76 | public void ring() {
77 | System.out.println("Received call: Phone is silent");
78 | }
79 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/StrategyPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Strategy pattern is used when we need to change the behavior of an algorithm at runtime.
3 | * We create an interface with a method which is implemented by all concrete classes.
4 | * This method contains the logic of the algorithm and can be implemented differently in each class.
5 | * The caller class stores an instance of this interface which can be set to required class at runtime.
6 | * In this example, LoadBalancer class contains an instance of Strategy which is implemented by RoundRobin and Random strategy.
7 | * setStrategy method of the LoadBalancer class is used to set/modify the required concrete class at runtime.
8 | */
9 |
10 | import java.util.*;
11 | class StrategyPattern {
12 | public static void main(String[] args) {
13 | LoadBalancer lb = new LoadBalancer(100);
14 | lb.setStrategy(new RoundRobinStrategy());
15 |
16 | lb.assignTask(1);
17 | lb.assignTask(2);
18 | lb.assignTask(3);
19 | lb.assignTask(4);
20 |
21 | lb.setStrategy(new RandomStrategy());
22 |
23 | lb.assignTask(5);
24 | lb.assignTask(6);
25 | lb.assignTask(7);
26 | lb.assignTask(8);
27 | }
28 | }
29 |
30 | class LoadBalancer {
31 | private Strategy strategy;
32 | public List> instances;
33 |
34 | public LoadBalancer(int numInstances) {
35 | instances = new ArrayList<>();
36 | for(int i=0; i());
38 | }
39 | }
40 |
41 | public void setStrategy(Strategy strategy) {
42 | this.strategy = strategy;
43 | }
44 |
45 | public void assignTask(Integer task) {
46 | strategy.assignTask(this, task);
47 | }
48 | }
49 |
50 | interface Strategy {
51 | public void assignTask(LoadBalancer lb, Integer task);
52 | }
53 |
54 | class RoundRobinStrategy implements Strategy {
55 | int index = 0;
56 | @Override
57 | public void assignTask(LoadBalancer lb, Integer task) {
58 | lb.instances.get(index).add(task);
59 | System.out.println("Task " + task + " assigned to instance " + index + " using round robin strategy");
60 | index = (index + 1)%lb.instances.size();
61 | }
62 | }
63 |
64 | class RandomStrategy implements Strategy {
65 | Random random = new Random();
66 | @Override
67 | public void assignTask(LoadBalancer lb, Integer task) {
68 | int index = random.nextInt(lb.instances.size());
69 | System.out.println("Task " + task + " assigned to instance " + index + " using round robin strategy");
70 | }
71 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/TemplatePattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used when we have multiple code workflows with almost similar logic and only minor differences.
3 | * Instead of writing redundant logic for each workflow, we can segragate the code into multiple methods.
4 | * Code which is similar for all workflows can be implemented in base class, and dissimilar code can be implemented in child classes.
5 | * In this example, in a CI/CD pipeline, stages code checkout and compliance check logic are same for all pipelines so they are implemented in the abstract class.
6 | * Build, Test and Deploy logic are different so they are implemented in the extended classes.
7 | */
8 |
9 | class TemplatePattern {
10 | public static void main(String[] args) {
11 | FunctionAppPipeline functionAppPipeline = new FunctionAppPipeline();
12 | functionAppPipeline.runPipeline();
13 |
14 | WebappPipeline webappPipeline = new WebappPipeline();
15 | webappPipeline.runPipeline();
16 | }
17 | }
18 |
19 | abstract class CICDPipeline {
20 | public void runPipeline() {
21 | checkout();
22 | build();
23 | runTests();
24 | runComplianceChecks();
25 | deploy();
26 | }
27 | protected void checkout() {
28 | System.out.println("Checking out code...");
29 | System.out.println("Checked out code.");
30 | }
31 |
32 | protected abstract void build();
33 | protected abstract void runTests();
34 |
35 | protected void runComplianceChecks() {
36 | System.out.println("Running compliance checks...");
37 | System.out.println("Compliance checked cleared.");
38 | }
39 |
40 | protected abstract void deploy();
41 | }
42 |
43 | class FunctionAppPipeline extends CICDPipeline {
44 | @Override
45 | protected void build() {
46 | System.out.println("Building functionapp code...");
47 | System.out.println("Functionapp code built.");
48 | }
49 |
50 | @Override
51 | protected void runTests() {
52 | System.out.println("Running functionapp tests...");
53 | System.out.println("Tests cleared.");
54 | }
55 |
56 | @Override
57 | protected void deploy() {
58 | System.out.println("Deploying code to functionapp slot...");
59 | System.out.println("Deployed code to functionapp slot.");
60 | }
61 | }
62 |
63 | class WebappPipeline extends CICDPipeline {
64 | @Override
65 | protected void build() {
66 | System.out.println("Building webapp code...");
67 | System.out.println("Webapp code built.");
68 | }
69 |
70 | @Override
71 | protected void runTests() {
72 | System.out.println("Running webapp tests...");
73 | System.out.println("Tests cleared.");
74 | }
75 |
76 | @Override
77 | protected void deploy() {
78 | System.out.println("Deploying code to webapp slot...");
79 | System.out.println("Deployed code to webapp slot.");
80 | }
81 | }
--------------------------------------------------------------------------------
/DesignPatterns/BehavioralPatterns/VisitorPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Visitor pattern is used in cases we need to add new methods for a group of classes but we don't want to make major changes in the class's code.
3 | * In that case, the new methods are added in a separate class called visitor.
4 | * The visitor visits the concerned class using its accept method.
5 | * So, honestly, we do need to add this accept() method in classes (which is basically a code change) but it is very minimal and risk-free.
6 | * In this example, the different shapes implement accept() method to allow a visitor to execute its visit() method on the shape.
7 | * The visitor class has methods tailored for different types of shapes, and are leveraged using method overloading.
8 | */
9 |
10 | import java.util.*;
11 | class VisitorPattern {
12 | public static void main(String[] args) {
13 | List shapes = new ArrayList<>();
14 | shapes.add(new Circle(2));
15 | shapes.add(new Circle(3));
16 | shapes.add(new Square(4));
17 | shapes.add(new Rectangle(2, 3));
18 |
19 | ShapeVisitor visitor = new ShapeVisitor();
20 |
21 | for(Shape shape : shapes) {
22 | shape.accept(visitor);
23 | }
24 | }
25 | }
26 |
27 | interface Shape {
28 | public void accept(ShapeVisitor v);
29 | }
30 |
31 | class Circle implements Shape {
32 | public int radius;
33 |
34 | public Circle(int radius) {
35 | this.radius = radius;
36 | }
37 |
38 | @Override
39 | public void accept(ShapeVisitor v) {
40 | v.visit(this);
41 | }
42 | }
43 |
44 | class Square implements Shape {
45 | public int length;
46 |
47 | public Square(int length) {
48 | this.length = length;
49 | }
50 |
51 | @Override
52 | public void accept(ShapeVisitor v) {
53 | v.visit(this);
54 | }
55 | }
56 |
57 | class Rectangle implements Shape {
58 | public int length, width;
59 |
60 | public Rectangle(int length, int width) {
61 | this.length = length;
62 | this.width = width;
63 | }
64 |
65 | @Override
66 | public void accept(ShapeVisitor v) {
67 | v.visit(this);
68 | }
69 | }
70 |
71 | class ShapeVisitor {
72 | public void visit(Circle circle) {
73 | double perimeter = 2 * 3.14 * circle.radius;
74 | double area = 3.14 * circle.radius * circle.radius;
75 | System.out.println("[Circle] Radius: " + circle.radius + ", Perimeter: " + perimeter + ", Area: " + area);
76 | }
77 |
78 | public void visit(Square square) {
79 | int perimeter = 4 * square.length;
80 | int area = square.length * square.length;
81 | System.out.println("[Square] Length: " + square.length + ", Perimeter: " + perimeter + ", Area: " + area);
82 | }
83 |
84 | public void visit(Rectangle rectangle) {
85 | int perimeter = 2 * (rectangle.length + rectangle.width);
86 | int area = rectangle.length * rectangle.width;
87 | System.out.println("[Rectangle] Length: " + rectangle.length + ", Width: " + rectangle.width + ", Perimeter: " + perimeter + ", Area: " + area);
88 | }
89 | }
--------------------------------------------------------------------------------
/DesignPatterns/CreationalPatterns/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/DesignPatterns/CreationalPatterns/.DS_Store
--------------------------------------------------------------------------------
/DesignPatterns/CreationalPatterns/AbstractFactoryPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | Abstract factory pattern provides another level of abstraction to factory pattern.
3 | User provides required params to abstract factory which in turn creates a concrete factory which ultimately creates required objects.
4 | Type of factory to be created is determined at runtime based on user parameters (in this case, the OS on which this program runs).
5 |
6 | In this example, user provides length, width and mode for creating a GUI to an abstract factory.
7 | Abstract factory determines the OS on which this programs runs and creates a corresponding concrete factory.
8 | The concrete factory creates GUI using user provided arguments.
9 | **/
10 |
11 | import java.util.*;
12 | public class AbstractFactoryPattern {
13 | public static void main(String[] args) {
14 | Scanner sc = new Scanner(System.in);
15 | System.out.println("Enter mode: ");
16 | String userMode = sc.next();
17 | Mode mode;
18 | if (userMode.equalsIgnoreCase("dark")) mode = Mode.DARK;
19 | else mode = Mode.LIGHT;
20 | System.out.println("Enter length: ");
21 | int length = sc.nextInt();
22 | System.out.println("Enter width: ");
23 | int width = sc.nextInt();
24 |
25 | System.out.println(GUIFactory.buildGUI(mode, length, width));
26 | }
27 | }
28 |
29 | abstract class GUI {
30 | int length;
31 | int width;
32 | Mode mode;
33 | OS os;
34 |
35 | GUI(int length, int width, Mode mode, OS os) {
36 | this.length = length;
37 | this.width = width;
38 | this.mode = mode;
39 | this.os = os;
40 | }
41 |
42 | @Override
43 | public String toString() {
44 | return "Length: " + length + " width: " + width + " mode: " + mode + " OS: " + os;
45 | }
46 | }
47 |
48 | class DarkGui extends GUI {
49 | DarkGui(OS os, int length, int width) {
50 | super(length, width, Mode.DARK, os);
51 | }
52 | }
53 |
54 | class LightGui extends GUI {
55 | LightGui(OS os, int length, int width) {
56 | super(length, width, Mode.LIGHT, os);
57 | }
58 | }
59 |
60 | class WindowsGuiFactory {
61 | public static GUI buildGUI (Mode mode, int length, int width) {
62 | GUI gui = null;
63 | switch (mode) {
64 | case DARK:
65 | gui = new DarkGui(OS.WINDOWS, length, width);
66 | break;
67 | case LIGHT:
68 | gui = new LightGui(OS.WINDOWS, length, width);
69 | break;
70 | default:
71 | break;
72 | }
73 | return gui;
74 | }
75 | }
76 |
77 | class MacGuiFactory {
78 | public static GUI buildGUI (Mode mode, int length, int width) {
79 | GUI gui = null;
80 | switch (mode) {
81 | case DARK:
82 | gui = new DarkGui(OS.MAC_OS, length, width);
83 | break;
84 | case LIGHT:
85 | gui = new LightGui(OS.MAC_OS, length, width);
86 | break;
87 | default:
88 | break;
89 | }
90 | return gui;
91 | }
92 | }
93 |
94 | class LinuxGuiFactory {
95 | public static GUI buildGUI (Mode mode, int length, int width) {
96 | GUI gui = null;
97 | switch (mode) {
98 | case DARK:
99 | gui = new DarkGui(OS.LINUX, length, width);
100 | break;
101 | case LIGHT:
102 | gui = new LightGui(OS.LINUX, length, width);
103 | break;
104 | default:
105 | break;
106 | }
107 | return gui;
108 | }
109 | }
110 |
111 | class GUIFactory {
112 | public static GUI buildGUI(Mode mode, int length, int width) {
113 | GUI gui = null;
114 | OS os = null;
115 |
116 | String systemOs = System.getProperty("os.name");
117 | if(systemOs.toLowerCase().contains("windows")) os = OS.WINDOWS;
118 | else if(systemOs.toLowerCase().contains("mac")) os = OS.MAC_OS;
119 | else if(systemOs.toLowerCase().contains("ubuntu")) os = OS.LINUX;
120 |
121 |
122 | switch (os) {
123 | case WINDOWS:
124 | gui = WindowsGuiFactory.buildGUI(mode, length, width);
125 | break;
126 | case MAC_OS:
127 | gui = MacGuiFactory.buildGUI(mode, length, width);
128 | break;
129 | case LINUX:
130 | gui = LinuxGuiFactory.buildGUI(mode, length, width);
131 | break;
132 | default:
133 | break;
134 | }
135 | return gui;
136 | }
137 | }
138 |
139 | enum Mode {
140 | DARK, LIGHT;
141 | }
142 |
143 | enum OS {
144 | WINDOWS, MAC_OS, LINUX
145 | }
--------------------------------------------------------------------------------
/DesignPatterns/CreationalPatterns/BuilderPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Builder pattern is used in cases where object creation is a complex process
3 | * Complexity arises when a class has several fields and not all of them are necessary during object creation
4 | * This pattern provides separate methods for setting each of the fields
5 | * Once the final build() method is called, the object is created and thereafter it is immutable.
6 | */
7 |
8 | public class BuilderPattern {
9 | public static void main(String[] args){
10 | System.out.println("Preparing medium Caesar salad...");
11 | Salad caesarSalad = new Salad.Builder(Size.MEDIUM)
12 | .addLettuce()
13 | .addBrocolli()
14 | .addJalapeno()
15 | .addTomato()
16 | .addDressing(Dressing.THOUSAND_ISLAND)
17 | .build();
18 | System.out.println(caesarSalad);
19 |
20 | System.out.println("Preparing large Russian salad...");
21 | Salad russianSalad = new Salad.Builder(Size.LARGE)
22 | .addLettuce()
23 | .addBrocolli()
24 | .addTomato()
25 | .addMushroom()
26 | .addDressing(Dressing.MAYO)
27 | .addJalapeno()
28 | .build();
29 | System.out.println(russianSalad);
30 | }
31 | }
32 |
33 | class Salad {
34 | private Size size;
35 | private boolean lettuce;
36 | private boolean brocolli;
37 | private boolean tomato;
38 | private boolean jalapeno;
39 | private boolean mushroom;
40 | private Dressing dressing;
41 |
42 | private int price;
43 |
44 | public static class Builder {
45 | private Size size;
46 | private boolean lettuce = false;
47 | private boolean brocolli = false;
48 | private boolean tomato = false;
49 | private boolean jalapeno = false;
50 | private boolean mushroom = false;
51 | private Dressing dressing = null;
52 |
53 | private int price = 0;
54 |
55 | public Builder(Size size) {
56 | this.size = size;
57 |
58 | switch(size) {
59 | case SMALL:
60 | price += 20;
61 | break;
62 | case MEDIUM:
63 | price += 30;
64 | break;
65 | case LARGE:
66 | price += 40;
67 | break;
68 | default:
69 | break;
70 | }
71 | }
72 |
73 | public Builder addLettuce() {
74 | lettuce = true;
75 | price += 5;
76 | return this;
77 | }
78 |
79 | public Builder addBrocolli() {
80 | brocolli = true;
81 | price += 15;
82 | return this;
83 | }
84 |
85 | public Builder addTomato() {
86 | tomato = true;
87 | price += 5;
88 | return this;
89 | }
90 |
91 | public Builder addJalapeno() {
92 | jalapeno = true;
93 | price += 7;
94 | return this;
95 | }
96 |
97 | public Builder addMushroom() {
98 | mushroom = true;
99 | price += 10;
100 | return this;
101 | }
102 |
103 | public Builder addDressing(Dressing dressing) {
104 | this.dressing = dressing;
105 | price += 12;
106 | return this;
107 | }
108 |
109 | public Salad build() {
110 | return new Salad(this);
111 | }
112 | }
113 | private Salad(Builder builder) {
114 | size = builder.size;
115 | lettuce = builder.lettuce;
116 | brocolli = builder.brocolli;
117 | tomato = builder.tomato;
118 | jalapeno = builder.jalapeno;
119 | mushroom = builder.mushroom;
120 | dressing = builder.dressing;
121 |
122 | price = builder.price;
123 | }
124 |
125 | @Override
126 | public String toString() {
127 | String out = "Here's your salad with: ";
128 | if(lettuce) out += "lettuce, ";
129 | if(brocolli) out += "brocolli, ";
130 | if(tomato) out += "tomato, ";
131 | if(jalapeno) out += "jalapeno, ";
132 | if(mushroom) out += "mushroom, ";
133 | if(dressing != null) out += (dressing);
134 |
135 | out += ("\nPrice: " + price);
136 |
137 | return out;
138 | }
139 | }
140 |
141 | enum Size {
142 | SMALL, MEDIUM, LARGE
143 | }
144 |
145 | enum Dressing {
146 | HONEY_MUSTARD, MAYO, THOUSAND_ISLAND
147 | }
--------------------------------------------------------------------------------
/DesignPatterns/CreationalPatterns/FactoryPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | Factory pattern is used when we want to hide the logic of object creation from users.
3 | In this pattern, a factory class containing a method "getObject" is exposed to the user.
4 | In the implementation, "getObject" method returns an object of an abstract class.
5 | Based on input provided by users at runtime, "getObject" chooses the type of concrete object to create.
6 | This eliminates the need of coupling concrete object creation logic with client code and hence promotes loose-coupling.
7 |
8 | In this example, user provides pizza name to a factory.
9 | Based on pizza name, factory determines which pizza object to create.
10 | Each concrete pizza class has its own instructions for ingredients. User doesn't need to know about these details.
11 | **/
12 |
13 |
14 | import java.util.*;
15 | public class FactoryPattern {
16 | public static void main(String[] args) {
17 | String pizzaName = "";
18 | Scanner sc = new Scanner(System.in);
19 | System.out.println("Enter pizza name: ");
20 | pizzaName = sc.next();
21 | PizzaFactory pizzaFactory = new PizzaFactory();
22 | Pizza pizza = pizzaFactory.getPizza(pizzaName);
23 | if(pizza == null) {
24 | System.out.println(pizzaName + " is not made in our restaurant!");
25 | return;
26 | }
27 | pizza.getRecipe();
28 | }
29 | }
30 |
31 | class PizzaFactory {
32 | public Pizza getPizza(String name) {
33 | if(name.equalsIgnoreCase("ThreeCheesePizza")) {
34 | return new ThreeCheesePizza();
35 | }
36 | if(name.equalsIgnoreCase("ChicagoDeepDishPizza")) {
37 | return new ChicagoDeepDishPizza();
38 | }
39 | return null;
40 | }
41 | }
42 |
43 | abstract class Pizza {
44 | protected String cheese;
45 | protected String toppings;
46 | protected String crust;
47 |
48 | protected abstract void getRecipe();
49 |
50 | protected void printPizzaDetails() {
51 | System.out.println("Cheese: " + this.cheese);
52 | System.out.println("Toppings: " + this.toppings);
53 | System.out.println("Crust: " + this.crust);
54 | }
55 | }
56 |
57 | class ThreeCheesePizza extends Pizza {
58 | @Override
59 | public void getRecipe() {
60 | this.cheese = "Mozzarella + Cheddar + Parmesan";
61 | this.toppings = "Only cheese!";
62 | this.crust = "Handmade extra thin crust";
63 | System.out.println("Cooking a three-cheese pizza...");
64 | printPizzaDetails();
65 | }
66 | }
67 |
68 | class ChicagoDeepDishPizza extends Pizza {
69 | @Override
70 | public void getRecipe() {
71 | this.cheese = "Mozzarella + Parmesan";
72 | this.toppings = "Bacon + Pepperoni + Tomato";
73 | this.crust = "Thick cornmeal crust";
74 | System.out.println("Cooking a Chicago Deep Dish pizza...");
75 | printPizzaDetails();
76 | }
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/DesignPatterns/CreationalPatterns/PrototypePattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Prototype pattern is used when we want to create a multiple copies of an object without having to copy each parameter separately.
3 | * It can be used to create both shallow and deep copies.
4 | */
5 |
6 | import java.util.Formatter;
7 | public class PrototypePattern {
8 | public static void main(String[] args) {
9 | Car car = new Car(15, "black", 5);
10 |
11 | Car deepCopy = car.deepClone();
12 | Car shallowCopy = car.shallowClone();
13 |
14 | Formatter formatter = new Formatter();
15 | formatter.format("------------------------------------------------------------------------------------------\n");
16 | formatter.format("%20s %20s %20s %20s\n", "Parameter", "Original", "DeepClone", "ShallowClone");
17 | formatter.format("------------------------------------------------------------------------------------------\n");
18 | formatter.format("%20s %20s %20s %20s\n", "Object", car, deepCopy, shallowCopy);
19 | formatter.format("%20s %20s %20s %20s\n", "Mileage", car.mileage, deepCopy.mileage, shallowCopy.mileage);
20 | formatter.format("%20s %20s %20s %20s\n", "Color", car.color, deepCopy.color, shallowCopy.color);
21 | formatter.format("%20s %20s %20s %20s\n", "Seats", car.seats, deepCopy.seats, shallowCopy.seats);
22 |
23 | System.out.println(formatter);
24 | }
25 | }
26 |
27 | class Car {
28 | public int mileage;
29 | public String color;
30 | public int seats;
31 |
32 | public Car(int mileage, String color, int seats) {
33 | this.mileage = mileage;
34 | this.color = color;
35 | this.seats = seats;
36 | }
37 | public Car deepClone() {
38 | Car car = new Car(this.mileage, this.color, this.seats);
39 | return car;
40 | }
41 |
42 | public Car shallowClone() {
43 | return this;
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/DesignPatterns/CreationalPatterns/SingletonPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | Singleton pattern is used in cases where we want only a single instance of a class throughout the application.
3 |
4 | In this example, we want a single instance of Logger class.
5 | So, instead of creating Logger class instances using new keyword, we use a getInstance() method.
6 | getInstance() method first checks if instance is null or not. If not, it returns instance.
7 | Otherwise, it takes a lock on Logger class (to ensure that no parallel thread calls getInstance() at the same time),
8 | checks again if instance is null or not.
9 | If so, a new instance is created and then returned.
10 | **/
11 | public class SingletonPattern {
12 | public static void main(String[] args) {
13 | Logger logger1 = Logger.getInstance();
14 | Logger logger2 = Logger.getInstance();
15 | Logger logger3 = new Logger(); // this is a new instance
16 |
17 | System.out.println("Logger1: " + logger1);
18 | System.out.println("Logger2: " + logger2);
19 | System.out.println("Logger3: " + logger3);
20 | }
21 | }
22 |
23 | class Logger {
24 | private static Logger instance;
25 |
26 | public static Logger getInstance() {
27 | if(instance == null) {
28 | synchronized (Logger.class) {
29 | if(instance == null) {
30 | instance = new Logger();
31 | }
32 | }
33 | }
34 | return instance;
35 | }
36 | }
--------------------------------------------------------------------------------
/DesignPatterns/DesignPatterns.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/DesignPatterns/StructuralPatterns/.DS_Store
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/AdapterPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Adapter design pattern is used in scenarios where we want 2 incompatible types to collaborate.
3 | * One typical example of this scenario is when we want data from obtained from a certain API/database to be utilised in a different
4 | * code which is expecting a different schema.
5 | * It is used to make legacy code compatible with new code.
6 | * In this example, Summary class is legacy code which is compatible with OldEmployee class but not NewEmployee.
7 | * We don't want to modify legacy code.
8 | * So we create an adapter for NewEmployee which extends OldEmployee and hence is compatible with Summary.
9 | */
10 | class AdapterPattern {
11 | public static void main(String[] args) {
12 | OldEmployee employee1 = new OldEmployee("firstname1", "lastname1", "designation1", "old-employee-abc");
13 | NewEmployee employee2 = new NewEmployee("employee2", "lastname2", "designation2", "new-employee-def");
14 |
15 | Summary.getSummary(employee1); // works fine
16 | // Summary.getSummary(employee2); // throws compilation error
17 |
18 | NewEmployeeAdapter employeeAdapter = new NewEmployeeAdapter(employee2);
19 | Summary.getSummary(employeeAdapter); // works fine
20 | }
21 | }
22 |
23 | class Summary {
24 | public static void getSummary(OldEmployee employee) {
25 | System.out.println("Summary of employee with id " + employee.getEmployeeId());
26 | System.out.println("First Name: " + employee.getFirstName());
27 | System.out.println("Last Name: " + employee.getLastName());
28 | System.out.println("Designation: " + employee.getDesignation());
29 | }
30 | }
31 |
32 | class OldEmployee {
33 | private String firstName;
34 | private String lastName;
35 | private String designation;
36 | private String employeeId;
37 |
38 | public OldEmployee(String firstName, String lastName, String designation, String employeeId) {
39 | this.firstName = firstName;
40 | this.lastName = lastName;
41 | this.designation = designation;
42 | this.employeeId = employeeId;
43 | }
44 |
45 | public String getFirstName() {
46 | return firstName;
47 | }
48 |
49 | public String getLastName() {
50 | return lastName;
51 | }
52 |
53 | public String getDesignation() {
54 | return designation;
55 | }
56 |
57 | public String getEmployeeId() {
58 | return employeeId;
59 | }
60 | }
61 |
62 | class NewEmployee {
63 | private String name;
64 | private String surname;
65 | private String jobTitle;
66 | private String employeeId;
67 |
68 | public NewEmployee(String name, String surname, String jobTitle, String employeeId) {
69 | this.name = name;
70 | this.surname = surname;
71 | this.jobTitle = jobTitle;
72 | this.employeeId = employeeId;
73 | }
74 |
75 | public String getName() {
76 | return name;
77 | }
78 |
79 | public String getSurname() {
80 | return surname;
81 | }
82 |
83 | public String getJobTitle() {
84 | return jobTitle;
85 | }
86 |
87 | public String getEmployeeId() {
88 | return employeeId;
89 | }
90 | }
91 |
92 | class NewEmployeeAdapter extends OldEmployee {
93 | public NewEmployeeAdapter(NewEmployee newEmployee) {
94 | super(newEmployee.getName(), newEmployee.getSurname(), newEmployee.getJobTitle(), newEmployee.getEmployeeId());
95 | }
96 | }
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/BridgePattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Bridge pattern helps in separating out orthogonal properties into separate classes so as to reduce the number of combinations.
3 | * In this example, if Type is added as a property in Card class, for every new Type, a new class would have to be created for every Card.
4 | * Similarly, for every new Card, a new class would have to created for every Type.
5 | * This would lead to creation of N(number of cards) * M(number of types) classes
6 | * However, using this pattern, a new Type or Card can be created independently.
7 | * Hence, there will be a total of N+M classes only.
8 | */
9 | class BridgePattern {
10 | public static void main(String[] args) {
11 | Card sbiGoldCard = new SbiCard(new GoldType());
12 | sbiGoldCard.withdraw(50000);
13 | sbiGoldCard.withdraw(120000);
14 |
15 | Card axisPlatinumCard = new AxisCard(new PlatinumType());
16 | axisPlatinumCard.withdraw(80000);
17 | }
18 | }
19 |
20 | abstract class Card {
21 | protected Type type;
22 | protected Card(Type type) {
23 | this.type = type;
24 | }
25 | protected void withdraw(int amount) {
26 | if(amount > type.getLimit()) {
27 | System.out.println("Failure. Amount " + amount + " exceeds daily limit.");
28 | } else {
29 | this.withdrawFromBank(amount);
30 | }
31 | }
32 |
33 | protected abstract void withdrawFromBank(int amount);
34 | }
35 |
36 | class SbiCard extends Card {
37 | public SbiCard(Type type) {
38 | super(type);
39 | }
40 | @Override
41 | public void withdrawFromBank(int amount) {
42 | System.out.println("Calling SBI API... to withdraw amount: " + amount);
43 | }
44 | }
45 |
46 | class AxisCard extends Card {
47 | public AxisCard(Type type) {
48 | super(type);
49 | }
50 | @Override
51 | public void withdrawFromBank(int amount) {
52 | System.out.println("Calling Axis Bank API... to withdraw amount: " + amount);
53 | }
54 | }
55 |
56 | class Type {
57 | private int limit;
58 |
59 | protected Type(int limit) {
60 | this.limit = limit;
61 | }
62 | public int getLimit() {
63 | return limit;
64 | }
65 | }
66 |
67 | class StandardType extends Type {
68 | public StandardType() {
69 | super(20000);
70 | }
71 | }
72 |
73 | class GoldType extends Type {
74 | public GoldType() {
75 | super(50000);
76 | }
77 | }
78 |
79 | class PlatinumType extends Type {
80 | public PlatinumType() {
81 | super(100000);
82 | }
83 | }
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/CompositePattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Composite pattern is used in cases where we have a tree-like hierarchy of similar elements.
3 | * In this example, there are multiple instances of folders and files in a tree-like directory.
4 | * So we implement them from same interface and same methods are available to them.
5 | * Composite elements are elements with children, while leaf elements have no children.
6 | * We store a link of children/parent element in each element so that we are able to navigate through the tree.
7 | */
8 |
9 | import java.util.*;
10 | import java.lang.UnsupportedOperationException;
11 |
12 | class CompositePattern {
13 | public static void main(String[] args) {
14 | Folder SystemDesign = new Folder("SystemDesign", null);
15 |
16 | Directory DesignPatterns = new Folder("DesignPatterns", SystemDesign);
17 | System.out.println("Path of DesignPatterns:");
18 | DesignPatterns.printPath();
19 | System.out.println("");
20 |
21 | Directory ElevatorSystem = new Folder("ElevatorSystem", SystemDesign);
22 | System.out.println("Path of ElevatorSystem:");
23 | ElevatorSystem.printPath();
24 | System.out.println("");
25 |
26 | Directory StructuralDesignPatterns = new Folder("StructuralDesignPatterns", DesignPatterns);
27 | System.out.println("Path of StructuralDesignPatterns:");
28 | StructuralDesignPatterns.printPath();
29 | System.out.println("");
30 |
31 | System.out.println("Subdirectories of DesignPatterns:");
32 | DesignPatterns.printSubDirectories();
33 | System.out.println("");
34 |
35 | Directory CompositePattern = new File("CompositePattern", StructuralDesignPatterns);
36 | System.out.println("Path of CompositePattern:");
37 | CompositePattern.printPath();
38 | System.out.println("");
39 | System.out.println("Subdirectories of CompositePattern:");
40 | CompositePattern.printSubDirectories();
41 | System.out.println("");
42 |
43 | System.out.println("Subdirectories of SystemDesign:");
44 | SystemDesign.printSubDirectories();
45 | System.out.println("");
46 | }
47 | }
48 |
49 | interface Directory {
50 | public void printPath();
51 | public void printSubDirectories();
52 | public void add(Directory directory);
53 | public void remove(Directory directory);
54 | }
55 |
56 | // Composite element
57 | class Folder implements Directory {
58 | public String name;
59 | public Directory parent;
60 | public List subFolders;
61 |
62 | public Folder(String name, Directory parent) {
63 | this.name = name;
64 | this.parent = parent;
65 | this.subFolders = new ArrayList<>();
66 | if(parent != null) parent.add(this);
67 | }
68 |
69 | @Override
70 | public void printPath() {
71 | if(parent != null) parent.printPath();
72 | System.out.print("/" + this.name);
73 | }
74 |
75 | @Override
76 | public void printSubDirectories() {
77 | for(Directory child : this.subFolders) {
78 | if(child instanceof Folder) {
79 | Folder folder = (Folder) child;
80 | System.out.println(folder.name);
81 | } else {
82 | File file = (File) child;
83 | System.out.println(file.name);
84 | }
85 | }
86 | }
87 |
88 | @Override
89 | public void add(Directory child) {
90 | this.subFolders.add(child);
91 | }
92 |
93 | @Override
94 | public void remove(Directory child) {
95 | this.subFolders.remove(child);
96 | }
97 | }
98 |
99 | // Leaf element
100 | class File implements Directory {
101 | public String name;
102 | public Directory parent;
103 |
104 | public File(String name, Directory parent) {
105 | this.name = name;
106 | this.parent = parent;
107 | }
108 |
109 | @Override
110 | public void printPath() {
111 | if(parent != null) parent.printPath();
112 | System.out.print("/" + this.name);
113 | }
114 |
115 | @Override
116 | public void printSubDirectories() {
117 | System.out.print("This is a file.");
118 | }
119 |
120 | @Override
121 | public void add(Directory child) {
122 | throw new UnsupportedOperationException("Can't add in a file.");
123 | }
124 |
125 | @Override
126 | public void remove(Directory child) {
127 | throw new UnsupportedOperationException("Can't remove from a file.");
128 | }
129 | }
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/DecoratorPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used to attach additional behaviors/characteristics to elements.
3 | * When we have a situation where new responsibility asks arise of an object regularly, it is not a good idea to keep exntending the class.
4 | * This is because there can a huge number of combinations of various responsibilities and creating child classes for each of these is not feasible.
5 | * Instead we wrap the original class in various decorator classes to provide it with the required responsibilties.
6 | * This can be done statically or at runtime.
7 | * In this example, we have the original object Venue, and we keep decorating it with added charateristics like Balloons and Lights.
8 | */
9 |
10 | class DecoratorPattern {
11 | public static void main(String[] args) {
12 | Venue partyVenue = new PartyVenue();
13 | partyVenue = new Balloons(partyVenue);
14 | partyVenue = new Lights(partyVenue);
15 | partyVenue = new Sequins(partyVenue);
16 |
17 | System.out.println(partyVenue.decorate());
18 | }
19 | }
20 |
21 | interface Venue {
22 | String decorate();
23 | }
24 |
25 | class PartyVenue implements Venue {
26 | @Override
27 | public String decorate() {
28 | return "Party Venue";
29 | }
30 | }
31 |
32 | abstract class VenueDecorator implements Venue {
33 | private Venue venue;
34 |
35 | public VenueDecorator(Venue venue) {
36 | this.venue = venue;
37 | }
38 | @Override
39 | public String decorate() {
40 | return venue.decorate();
41 | }
42 | }
43 |
44 | class Balloons extends VenueDecorator {
45 | public Balloons(Venue venue) {
46 | super(venue);
47 | }
48 |
49 | public String decorate() {
50 | return super.decorate() + balloonDecorator();
51 | }
52 |
53 | private String balloonDecorator() {
54 | return " with balloons";
55 | }
56 | }
57 |
58 | class Sequins extends VenueDecorator {
59 | public Sequins(Venue venue) {
60 | super(venue);
61 | }
62 |
63 | public String decorate() {
64 | return super.decorate() + sequinDecorator();
65 | }
66 |
67 | private String sequinDecorator() {
68 | return " with sequins";
69 | }
70 | }
71 |
72 | class Lights extends VenueDecorator {
73 | public Lights(Venue venue) {
74 | super(venue);
75 | }
76 |
77 | public String decorate() {
78 | return super.decorate() + lightsDecorator();
79 | }
80 |
81 | private String lightsDecorator() {
82 | return " with lights";
83 | }
84 | }
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/FacadePattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used to abstract complexity of various operations of a class from users.
3 | * In this example, user has knowledge of only SendMoney() and GetBalance() methods.
4 | * Other intricate details of UPI service providers, getting details from bank etc. are not made visible to the users.
5 | */
6 |
7 | class FacadePattern {
8 | public static void main(String[] args) {
9 | UPIPaymentApp app = new UPIPaymentApp("dummy@okdummy");
10 |
11 | System.out.println("Balance: " + app.GetBalance());
12 |
13 | app.SendMoney(500);
14 | app.SendMoney(1500);
15 | }
16 | }
17 |
18 | class UPIPaymentApp {
19 | private String upiId;
20 |
21 | public UPIPaymentApp(String upiId) {
22 | this.upiId = upiId;
23 | }
24 | public void SendMoney(int amount) {
25 | int balance = GetBalance();
26 |
27 | if(balance >= amount) {
28 | System.out.println("Money transfer successful");
29 | } else {
30 | System.out.println("Not enough balance");
31 | }
32 | }
33 |
34 | public int GetBalance() {
35 | UpiServiceProvider upiServiceProvider = new UpiServiceProvider();
36 | upiServiceProvider.IsUpiValid(upiId);
37 | int accountNumber = upiServiceProvider.GetBank(upiId);
38 |
39 | Bank bank = new Bank();
40 | int balance = bank.GetBankBalance(accountNumber);
41 |
42 | System.out.println("Balance: " + balance);
43 |
44 | return balance;
45 | }
46 | }
47 |
48 | class UpiServiceProvider {
49 | public void IsUpiValid(String upiId) {
50 | System.out.println("Validating UPI ID...");
51 | System.out.println("UPI ID valid.");
52 | }
53 |
54 | public int GetBank(String upiId) {
55 | System.out.println("Finding Bank...");
56 | return 12345;
57 | }
58 | }
59 |
60 | class Bank {
61 | public int GetBankBalance(int accountNumber) {
62 | System.out.println("Getting balance for account " + accountNumber + "...");
63 | return 1000;
64 | }
65 | }
--------------------------------------------------------------------------------
/DesignPatterns/StructuralPatterns/FlyweightPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This pattern is used when we need to create a lot of objects of same class with very minimal differences in properties.
3 | * Each object requires memory, so it is efficient to create one object for a certain set of properties and reuse is wherever possible.
4 | * Ofcourse these objects should be immutable so as to avoid any unintentional behavior anywhere they get used.
5 | * In this example, say we are creating a terrain for a game. It can be viewed as a grid with different elements in each cell.
6 | * Most of these elements will be immutable.
7 | * So it is way more efficient to create 1 instance of each element and render it multiple times on the terrain.`
8 | */
9 |
10 | import java.util.HashMap;
11 | import java.util.ArrayList;
12 |
13 | class FlyweightPattern {
14 | public static void main(String[] args) {
15 | Terrain terrain = new Terrain(2, 2);
16 | terrain.setElement(ElementType.TREE, 0, 0);
17 | terrain.setElement(ElementType.WATER, 0, 1);
18 | terrain.setElement(ElementType.WATER, 1, 1);
19 | terrain.setElement(ElementType.LAND, 1, 0);
20 |
21 | terrain.render();
22 |
23 | // Observe that object address for same element types are same.
24 | System.out.println("0,0 element: " + terrain.terrain[0][0].render() + ", address: " + terrain.terrain[0][0]);
25 | System.out.println("0,0 element: " + terrain.terrain[0][1].render() + ", address: " + terrain.terrain[0][1]);
26 | System.out.println("0,0 element: " + terrain.terrain[1][0].render() + ", address: " + terrain.terrain[1][0]);
27 | System.out.println("0,0 element: " + terrain.terrain[1][1].render() + ", address: " + terrain.terrain[1][1]);
28 | }
29 | }
30 |
31 | interface Element {
32 | char render();
33 | }
34 |
35 | class Tree implements Element {
36 | @Override
37 | public char render() {
38 | return 'T';
39 | }
40 | }
41 |
42 | class Water implements Element {
43 | @Override
44 | public char render() {
45 | return 'W';
46 | }
47 | }
48 |
49 | class Rock implements Element {
50 | @Override
51 | public char render() {
52 | return 'W';
53 | }
54 | }
55 |
56 | class Land implements Element {
57 | @Override
58 | public char render() {
59 | return 'L';
60 | }
61 | }
62 |
63 | class ElementFactory {
64 | private HashMap elementMap = new HashMap<>();
65 |
66 | public Element getElement(ElementType elementType) {
67 | if(elementMap.containsKey(elementType)) {
68 | return elementMap.get(elementType);
69 | }
70 |
71 | Element element;
72 | switch(elementType) {
73 | case TREE:
74 | element = new Tree();
75 | break;
76 | case WATER:
77 | element = new Water();
78 | break;
79 | case ROCK:
80 | element = new Rock();
81 | break;
82 | case LAND:
83 | element = new Land();
84 | break;
85 | default:
86 | element = null;
87 | }
88 |
89 | if(element == null)
90 | System.out.println("Invalid element type " + elementType);
91 |
92 | elementMap.put(elementType, element);
93 | return element;
94 | }
95 | }
96 |
97 | enum ElementType {
98 | LAND, TREE, ROCK, WATER
99 | }
100 |
101 | class Terrain {
102 | public int length;
103 | public int width;
104 | Element[][] terrain;
105 | ElementFactory factory = new ElementFactory();
106 |
107 | public Terrain(int length, int width) {
108 | this.length = length;
109 | this.width = width;
110 | terrain = new Element[length][width];
111 | }
112 |
113 | public void setElement(ElementType elementType, int x, int y) {
114 | if(x >= this.length || y >= this.width) {
115 | throw new IndexOutOfBoundsException("Given coordinates are not within terrain dimensions");
116 | }
117 |
118 | terrain[x][y] = factory.getElement(elementType);
119 | }
120 |
121 | public void render() {
122 | for(int i=0; i employeeIdName = new HashMap<>();
50 |
51 | @Override
52 | public void add(int id, String name) {
53 | if(employeeIdName.containsKey(id)) {
54 | System.out.println("EmployeeId exists already");
55 | return;
56 | }
57 | employeeIdName.put(id, name);
58 | }
59 |
60 | @Override
61 | public void remove(int id) {
62 | if(!employeeIdName.containsKey(id)) {
63 | System.out.println("EmployeeId doesn't exist");
64 | return;
65 | }
66 | employeeIdName.remove(id);
67 | }
68 |
69 | @Override
70 | public void update(int id, String name) {
71 | if(!employeeIdName.containsKey(id)) {
72 | System.out.println("EmployeeId doesn't exist");
73 | return;
74 | }
75 | employeeIdName.put(id, name);
76 | }
77 |
78 | @Override
79 | public void printTable() {
80 | for (Map.Entry entry : employeeIdName.entrySet()) {
81 | System.out.println(entry.getKey() + " " + entry.getValue());
82 | }
83 | }
84 | }
85 |
86 | // Cached table in memory
87 | class TableProxy implements Table {
88 | private RealTable realTable = new RealTable();
89 | private String del = "DELETED";
90 |
91 | private HashMap employeeIdName = new HashMap<>();
92 |
93 | @Override
94 | public void add(int id, String name) {
95 | if(employeeIdName.containsKey(id)) {
96 | System.out.println("EmployeeId exists already");
97 | return;
98 | }
99 | employeeIdName.put(id, name);
100 | }
101 |
102 | @Override
103 | public void remove(int id) {
104 | if(!employeeIdName.containsKey(id) || employeeIdName.get(id).equals(del)) {
105 | System.out.println("EmployeeId doesn't exist");
106 | return;
107 | }
108 | employeeIdName.put(id, del);
109 | }
110 |
111 | @Override
112 | public void update(int id, String name) {
113 | if(!employeeIdName.containsKey(id) || employeeIdName.get(id).equals(del)) {
114 | System.out.println("EmployeeId doesn't exist");
115 | return;
116 | }
117 | employeeIdName.put(id, name);
118 | }
119 |
120 | public void backup() {
121 | // Updating real table only from this method
122 | for(Map.Entry entry : employeeIdName.entrySet()) {
123 | if(entry.getValue().equals(del)) {
124 | realTable.remove(entry.getKey());
125 | } else {
126 | if(realTable.employeeIdName.containsKey(entry.getKey())) {
127 | realTable.update(entry.getKey(), entry.getValue());
128 | } else {
129 | realTable.add(entry.getKey(), entry.getValue());
130 | }
131 | }
132 | }
133 | }
134 |
135 | @Override
136 | public void printTable() {
137 | realTable.printTable();
138 | }
139 | }
--------------------------------------------------------------------------------
/HLD/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/.DS_Store
--------------------------------------------------------------------------------
/HLD/ChatApp/ChatService.drawio:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/HLD/ChatApp/ChatService.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/ChatApp/ChatService.png
--------------------------------------------------------------------------------
/HLD/ECommerceStore/ecommerce.drawio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/ECommerceStore/ecommerce.drawio.png
--------------------------------------------------------------------------------
/HLD/GoogleDocs/GoogleDoc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/GoogleDocs/GoogleDoc.png
--------------------------------------------------------------------------------
/HLD/Twitter/TwitterHLD.drawio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/Twitter/TwitterHLD.drawio.png
--------------------------------------------------------------------------------
/HLD/URLShortener/URLshortener.drawio:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/HLD/URLShortener/URLshortener.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/URLShortener/URLshortener.png
--------------------------------------------------------------------------------
/HLD/Uber/Uber.drawio:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/HLD/Uber/Uber.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/Uber/Uber.png
--------------------------------------------------------------------------------
/HLD/WebHook/WebHook.md:
--------------------------------------------------------------------------------
1 | # WebHook
2 | Design a WebHook system
3 |
4 | ## Functional Requirements
5 | - Clients should be able to register to the webhook service along with event types they are interested in.
6 | - Clients should be notified on registered URLs when events they're interested in happen.
7 | - Security is an important consideration as clients will be open to receiving communication from the service.
8 | - Guarantee ordering of events per webhook subscriber (especially for related events).
9 | - Allow clients to list, update, delete their webhook subscriptions.
10 |
11 | ## Non-functional Requirements
12 | - System should be scalable and should be able to handle millions of webhook events every day.
13 | - System should be reliable and should guarantee at-least-once delivery.
14 | - System should have low latency.
15 | - System should be durable and persist undelivered events until they're successfully delivered or expired.
16 |
17 | ## Resource estimation
18 |
19 | ### Requirements
20 | - 1M webhook events per day with 5x increase during spikes.
21 | - Default expiry of events is 30 days.
22 | - All delivered/undelivered events should be retained for 30 days.
23 | - Each event size is 5KB.
24 |
25 | During peak hours, as traffic increases by 5x, `5M events need to be processed and delivered`.
26 |
27 | As each event is of size 5KB, `average bandwidth required = 1M x 5KB /day = 57KB/s`. This can go up to `57 x 5 = 285KB/s during peak hours`.
28 |
29 | Given, events need to be stored for 30 days, `amount of storage needed for usual traffic = 1M x 5KB x 30 = 150GB`.
30 |
31 | ## API Design
32 | 1. Register a WebHook
33 |
`POST /webhooks`
34 |
Request:
35 | ```json
36 | {
37 | "url": "https://client.example.com/webhook",
38 | "event_types": ["document.created", "document.updated"]
39 | }
40 |
41 | ```
42 |
Response:
43 | ```json
44 | {
45 | "webhook_id": "wh_12345",
46 | "status": "active"
47 | }
48 | ```
49 | 2. Get WebHook Details
50 |
`GET /webhooks/{webhook_id}`
51 |
Response:
52 | ```json
53 | {
54 | "webhook_id": "wh_12345",
55 | "url": "https://client.example.com/webhook",
56 | "event_types": ["document.created"],
57 | "status": "active",
58 | "created_at": "2025-05-07T12:00:00Z"
59 | }
60 | ```
61 | 3. List all WebHooks
62 |
`GET /webhooks`
63 |
Response:
64 | ```json
65 | {
66 | "webhooks": [
67 | {
68 | "webhook_id": "wh_12345",
69 | "url": "https://client.example.com/webhook",
70 | "event_types": ["document.created"]
71 | },
72 | {
73 | "webhook_id": "wh_67890",
74 | "url": "https://client.example.com/user-webhook",
75 | "event_types": ["user.updated"]
76 | }
77 | ]
78 | }
79 | ```
80 | 4. Update a WebHook
81 |
`PUT /webhooks/{webhook_id}`
82 |
Request:
83 | ```json
84 | {
85 | "url": "https://new.example.com/webhook",
86 | "event_types": ["document.deleted"]
87 | }
88 | ```
89 |
Response:
90 | ```json
91 | {
92 | "status": "updated"
93 | }
94 | ```
95 | 5. Delete a WebHook
96 |
`DELETE /webhooks/{webhook_id}`
97 |
Response:
98 | ```json
99 | {
100 | "status": "deleted"
101 | }
102 | ```
103 | 6. Deliver an event (initiated by Server)
104 |
`POST https://client.example.com/webhook`
105 |
Request:
106 | ```json
107 | {
108 | "event_id": "evt_abc123",
109 | "event_type": "document.created",
110 | "timestamp": "2025-05-07T12:34:56Z",
111 | "payload": {
112 | "document_id": "doc_7890",
113 | "created_by": "user_123"
114 | }
115 | }
116 | ```
117 |
118 | ## Data Storage
119 |
120 | ### `Subscription` table
121 | Stores registered webhook subscriptions of all users. We can use relational DB (e.g., `Postgres`, `MySQL`) for this table because it’s structured, transactional and queryable. It can be indexed on `user_id` and `event_types` to quickly fetch subscriptions of a particular user or all subscriptions for a particular event type.
122 |
Schema:
123 | ```
124 | webhook_id (UUID, PK)
125 | user_id (UUID)
126 | callback_url (string)
127 | event_types (Enum[])
128 | status (Enum (ACTIVE/INACTIVE))
129 | created_at (timestamp)
130 | ```
131 |
132 | ### `EventsDelivery` table
133 | Records delivery attempts and results for observability and retries. This table will have to handle high read and write traffic. As we need at-least-once delivery guarantee, strong ACID properties are not necessary. Keeping these in mind, a non-relational DB like `MongoDB` would be a good choice. This table can be indexed on `status` to quickly fetch failed deliveries and retry them.
134 |
135 | Also, if `payload` or `response_message` are too long, they can be stored separately in object storage and keep references here.
136 |
Schema:
137 | ```
138 | delivery_id (UUID, PK)
139 | event_id (UUID)
140 | webhook_id (UUID, FK)
141 | event_type (Enum)
142 | payload (JSON)
143 | status (Enum)
144 | retry_count (integer)
145 | delivery_time (timestamp)
146 | response_code (integer)
147 | response_message (string)
148 | ```
149 |
150 | ## High-level Design
151 | 
152 |
153 | `Webhook Management Service` handles the creation, updates and management of webhooks. This service exposes CRUD APIs for webhooks. This service stores registered webhooks in `Subscription` table.
154 |
155 | `Events Producer Service` creates new events from external triggers. It creates individual events for each subscriber using data from `Subscription` table and stores in `Events Delivery` table. It also publishes the events to a Message Queue for async handling.
156 |
157 | `Dispatcher Service` workers consume events from the message queue and attempt delivery to clients. Status is updated in `Events Delivery` table according to success or failure. `Retry Service` retries failed deliveries for a fixed number of times before abandoning them permanently.
158 |
159 | ## Bottlenecks and scaling
160 |
161 | ### Dispatcher scalability
162 | `Dispatcher service` has to deliver millions of events daily and can easily become a bottleneck. This will lead to high latency, failed deliveries and increased retries. To resolve this, dispatcher service should have multiple workers that can be scaled horizontally as per traffic. Also, `event delivery message queue` can be sharded by event type and dedicated dispatcher workers can be created so that they can scale independently.
163 |
164 | ### Retry backlog
165 | Misconfigured or flaky client URLs can lead to significant increase in retry backlog. This leads to wastage of immense resources in `Retry Service`. Hence, retries should be handled by a separate service instead of `Dispatcher service` itself. Exponential backoff should be used while retrying for the same client URL. Also, a max retry limit should be set and thereafter the event should be expired.
166 |
167 | ### Metadata cache
168 | Each time an event needs to be dispatched to a certain webhook, all metadata related to the webhook is required. This info can be cached in `Dispatcher Service` and `Retry Service` for heavily used webhooks.
169 |
170 | ## Security
171 | Security is critical in webhook system since client URLs are exposed over public internet — anyone can POST data to them. Following measures can be taken to secure such a system.
172 |
173 | ### Authentication
174 | Only signed payloads should be accepted by client endpoints (e.g., `HMAC-SHA256`). When a client registers a webhook, generate a secret key (e.g., per-client or per-webhook). When sending a webhook event, compute HMAC over payload using the secret key and include the signature in header. Client receiving the webhook will verify the signature using their secret. Secrets should be rotated periodically.
175 |
176 | ### Secure client URLs
177 | Enforce HTTPS-only client URLs. Use TLS 1.2 or higher. Optionally validate server certificates — prevent MITM attacks. Reject IPs with self-signed or expired certs.
178 |
179 | Validate webhook URLs at registration time and before each dispatch. Block internal IPs (e.g., `127.0.0.1`, `169.254.x.x`, `10.x.x.x`, etc.)
180 |
181 | ### Rate Limiting + Circuit Breakers
182 | To protect from malicious clients, implement per client rate limits, circuit breakers for clients failing consistently and exponential backoff on retry attempts.
183 |
184 | > On top of all of these, implement proper audit and monitoring system to identify malicious clients.
185 |
--------------------------------------------------------------------------------
/HLD/WebHook/Webhook.drawio:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/HLD/WebHook/Webhook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/WebHook/Webhook.png
--------------------------------------------------------------------------------
/HLD/Youtube/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/HLD/Youtube/youtube.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Anuva Bhattacharjee
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LLD/ATM/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
--------------------------------------------------------------------------------
/LLD/ATM/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/LLD/ATM/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
--------------------------------------------------------------------------------
/LLD/ATM/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LLD/ATM/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LLD/ATM/README.md:
--------------------------------------------------------------------------------
1 | # ATM System - Low-Level Design (LLD)
2 |
3 | The ATM System is a software application that simulates the functionalities of an Automated Teller Machine (ATM). This system is designed to demonstrate the low-level design of an ATM using object-oriented principles.
4 |
5 | ## Architecture Overview
6 |
7 | The ATM System follows a layered architecture, comprising the following layers:
8 |
9 | - **User Interface Layer:** This layer is responsible for interacting with the user, capturing input, and displaying information. It includes the `Main` class, which serves as the entry point for the system and handles user interactions through the command-line interface.
10 |
11 | - **Controller Layer:** This layer contains the controllers that handle user requests and orchestrate the interactions between different components of the system. It includes the `ATM` class, which manages the overall ATM operations, such as cash reserve management and user transactions.
12 |
13 | - **Model Layer:** This layer consists of the data models and entities used in the system. It includes classes like `AtmCard`, `CashReserve`, and `Transaction` that represent ATM cards, cash reserves, and user transactions, respectively.
14 |
15 | - **Strategy Layer:** This layer encapsulates different strategies for cash dispensing. It includes the `CashDispenserStrategy` interface and its implementation, such as the `SimpleCashDispenseStrategy`, which defines the logic for dispensing cash based on the available cash reserve.
16 |
17 | - **Enums:** This package contains different enumerations used in the system, such as `Denomination` for representing various currency denominations and `PaymentNetwork` for defining payment network types.
18 |
19 | - **Models Package:** This package contains the concrete implementations of ATM cards, such as `AxisVisaCard` and `SbiRupayCard`, which extend the `AtmCard` class and define card-specific details like the bank and payment network.
20 |
21 | ## Features and Functionality
22 |
23 | The ATM System supports the following features:
24 |
25 | - **User Login:** The system allows users to log in using an ATM card, currently implemented with dummy card details.
26 |
27 | - **Cash Withdrawal:** Users can withdraw cash from the ATM. The system verifies the PIN and checks the cash availability before dispensing the requested amount.
28 |
29 | - **PIN Change:** Users can change the PIN associated with their ATM card.
30 |
31 | - **Balance Inquiry:** Users can check the balance of their linked bank account.
32 |
33 | - **Mini Statement:** Users can request a mini statement of their recent transactions.
34 |
35 | - **Admin Login:** The system provides an admin login option to manage the cash reserve. Only authorized administrators can modify the cash reserve.
36 |
37 | ## Getting Started
38 |
39 | To run the ATM System, follow these steps:
40 |
41 | 1. Clone the repository to your local machine.
42 | 2. Open the project in your preferred Java IDE.
43 | 3. Build the project using Gradle to resolve dependencies. You can use the following command in the terminal or command prompt:
44 | ./gradlew build
45 | 4. Run the `Main` class to start the ATM system.
46 | 5. Follow the instructions displayed in the console to perform different operations.
47 | - For user login, enter `1`.
48 | - For admin login, enter `2`. Use the password "admin12345" for admin login.
49 |
50 | ## Extensibility and Customization
51 |
52 | The ATM System is designed to be extensible and customizable. You can add new features or modify existing functionalities by extending or implementing the relevant classes and interfaces. For example, you can introduce new types of ATM cards, implement additional cash dispensing strategies, or integrate the system with real banking services.
53 |
54 | ## Note
55 |
56 | The ATM System is a simulated application and does not interact with real banks or handle actual monetary transactions. It serves as a demonstration of low-level design concepts and can be further developed for practical usage.
--------------------------------------------------------------------------------
/LLD/ATM/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("java")
3 | }
4 |
5 | group = "org.anuva04"
6 | version = "1.0-SNAPSHOT"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | implementation("org.jetbrains:annotations:24.0.0")
14 | testImplementation(platform("org.junit:junit-bom:5.9.1"))
15 | testImplementation("org.junit.jupiter:junit-jupiter")
16 | }
17 |
18 | tasks.test {
19 | useJUnitPlatform()
20 | }
--------------------------------------------------------------------------------
/LLD/ATM/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/LLD/ATM/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/LLD/ATM/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jun 17 19:25:54 IST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/LLD/ATM/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/LLD/ATM/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ATM"
2 |
3 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Controllers/ATM.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Models.AtmCards.AtmCard;
4 | import org.anuva04.Models.CashReserve;
5 | import org.anuva04.Strategies.CashDispenserStrategy;
6 |
7 | import java.util.Scanner;
8 | import java.util.UUID;
9 |
10 | public class ATM {
11 | private UUID id;
12 | private CashReserve cashReserve;
13 | private CashDispenserStrategy cashDispenserStrategy;
14 |
15 | public ATM() {
16 | cashReserve = new CashReserve();
17 | this.id = UUID.randomUUID();
18 | }
19 |
20 | // Method to set cash dispensing strategy
21 | public void setCashDispenserStrategy(CashDispenserStrategy cashDispenserStrategy) {
22 | this.cashDispenserStrategy = cashDispenserStrategy;
23 | }
24 |
25 | // Method to handle user requests after ATM card is inserted and PIN is verified
26 | public void startTransaction(AtmCard atmCard) {
27 | Scanner sc = new Scanner(System.in);
28 | Transaction transaction = new Transaction();
29 | if (!transaction.verifyPin(atmCard)) {
30 | System.out.println("Wrong PIN!!!");
31 | return;
32 | }
33 | while (true) {
34 | System.out.println("Choose an option: ");
35 | System.out.println(
36 | "1: Withdraw cash\n" +
37 | "2: Change Pin\n" +
38 | "3: Check balance\n" +
39 | "4: Get mini statement\n" +
40 | "5: Exit");
41 | int option = sc.nextInt();
42 | boolean exit = false;
43 | switch (option) {
44 | case 1:
45 | transaction.withdraw(cashReserve, cashDispenserStrategy);
46 | break;
47 | case 2:
48 | transaction.changePin(atmCard);
49 | break;
50 | case 3:
51 | transaction.checkBalance(atmCard);
52 | break;
53 | case 4:
54 | transaction.getMiniStatement(atmCard);
55 | break;
56 | case 5:
57 | System.out.println("Thank you for visiting!!!");
58 | exit = true;
59 | break;
60 | default:
61 | System.out.println("Invalid option!!!");
62 | }
63 | if (exit) {
64 | break;
65 | }
66 | }
67 | }
68 |
69 | // Method to update data about cash reserve in ATM
70 | public void modifyCashReserve(CashReserve newCashReserve) {
71 | this.cashReserve.modifyCashReserve(newCashReserve);
72 | System.out.println("Cash reserve modified successfully!");
73 | }
74 |
75 | // Method to verify admin login
76 | public boolean adminLogin(String password) {
77 | if (password.equalsIgnoreCase("admin12345")) {
78 | return true;
79 | }
80 | return false;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Controllers/Transaction.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Models.AtmCards.AtmCard;
4 | import org.anuva04.Models.CashAvailabilityDataResponseModel;
5 | import org.anuva04.Models.CashReserve;
6 | import org.anuva04.Strategies.CashDispenserStrategy;
7 |
8 | import java.util.Scanner;
9 |
10 | // Contains all facilities provided by ATM to users
11 | public class Transaction {
12 | Scanner sc = new Scanner(System.in);
13 |
14 | // Method to withdraw cash from ATM
15 | public void withdraw(CashReserve cashReserve, CashDispenserStrategy cashDispenserStrategy) {
16 | System.out.println("Enter amount: ");
17 | int amount = sc.nextInt();
18 | // Contact bank to check user's balance
19 | // If not enough balance, cancel transaction
20 | // else
21 | CashAvailabilityDataResponseModel response = cashDispenserStrategy.getCashAvailability(cashReserve, amount);
22 | if (!response.isCashAvailable) {
23 | System.out.println("Cash not available!");
24 | return;
25 | }
26 | // Contact bank to deduct balance
27 | CashReserve cash = cashDispenserStrategy.dispenseCash(cashReserve, response.cashReserve);
28 | if (cash == null) {
29 | System.out.println("Something went wrong! Please contact XXXX");
30 | // Contact bank to initiate refund
31 | } else {
32 | System.out.println("Please collect cash!");
33 | }
34 | }
35 |
36 | // Method to change ATM card PIN
37 | public void changePin(AtmCard atmCard) {
38 | System.out.println("Enter new PIN: ");
39 | int newPin = sc.nextInt();
40 | // Contact bank to change PIN
41 | System.out.println("Pin changed successfully!");
42 | }
43 |
44 | // Method to check balance of bank account linked to given ATM card
45 | public void checkBalance(AtmCard atmCard) {
46 | // Contact bank to check balance
47 | System.out.println("Balance for account linked to card " + atmCard.getCardNumber() + " is YY");
48 | }
49 |
50 | // Method to get Mini-statement of bank account linked to given ATM card
51 | public void getMiniStatement(AtmCard atmCard) {
52 | // Contact bank to get mini-statement
53 | System.out.println("Mini-statement: ###########");
54 | }
55 |
56 | // Method to verify ATM card PIN
57 | public boolean verifyPin(AtmCard atmCard) {
58 | System.out.println("Please enter PIN: ");
59 | int pin = sc.nextInt();
60 |
61 | // PIN verification process
62 | return atmCard.getBank().verifyAtmPin(atmCard.getCardNumber(), pin);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Enums/Denomination.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Enums;
2 |
3 | public enum Denomination {
4 | TWO_THOUSAND, THOUSAND, FIVE_HUNDRED, HUNDRED, FIFTY
5 | }
6 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Enums/PaymentNetwork.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Enums;
2 |
3 | public enum PaymentNetwork {
4 | VISA, MASTERCARD, RUPAY
5 | }
6 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Main.java:
--------------------------------------------------------------------------------
1 | package org.anuva04;
2 |
3 | import org.anuva04.Controllers.ATM;
4 | import org.anuva04.Enums.Denomination;
5 | import org.anuva04.Models.AtmCards.AtmCard;
6 | import org.anuva04.Models.AtmCards.SbiRupayCard;
7 | import org.anuva04.Models.CashReserve;
8 | import org.anuva04.Strategies.SimpleCashDispenseStrategy;
9 |
10 | import java.time.LocalDate;
11 | import java.util.Scanner;
12 |
13 | public class Main {
14 |
15 | // Method to simulate insertion of cash in ATM
16 | public static void handleModifyCashReserve(ATM atm) {
17 | Scanner sc = new Scanner(System.in);
18 | System.out.println("Enter details to modify cash reserve... Enter q to exit: ");
19 | CashReserve request = new CashReserve();
20 | while (true) {
21 | System.out.print("Enter denomination type (TWO_THOUSAND, THOUSAND, FIVE_HUNDRED, HUNDRED, FIFTY) or \"q\" to exit: ");
22 | String input = sc.next();
23 | if (input.equalsIgnoreCase("q")) {
24 | break;
25 | }
26 | Denomination denomination = Denomination.valueOf(input.toUpperCase());
27 | System.out.println("Enter count: ");
28 | Integer count = sc.nextInt();
29 | try {
30 | request.updateCash(denomination, count);
31 | } catch (Exception e) {
32 | System.out.println(e.getMessage());
33 | }
34 | }
35 | atm.modifyCashReserve(request);
36 | }
37 |
38 | // Running main method means ATM is up and running
39 | public static void main(String[] args) {
40 | ATM atm = new ATM();
41 | atm.setCashDispenserStrategy(new SimpleCashDispenseStrategy());
42 | Scanner sc = new Scanner(System.in);
43 |
44 | while (true) {
45 | System.out.println("1: User login\n2: Admin login");
46 | int loginType = sc.nextInt();
47 | switch (loginType) {
48 | case 1:
49 | // ATM card insertion stage
50 | AtmCard dummyAtmCard = new SbiRupayCard("1234321", 999, "Anuva", LocalDate.now());
51 | atm.startTransaction(dummyAtmCard);
52 | break;
53 | case 2:
54 | System.out.print("Enter admin password: ");
55 | String input = sc.next();
56 | if (atm.adminLogin(input)) {
57 | System.out.println("Admin Logged in successfully!");
58 | handleModifyCashReserve(atm);
59 | } else {
60 | System.out.println("Invalid password!");
61 | }
62 | break;
63 | default:
64 | System.out.println("Invalid option!");
65 | break;
66 | }
67 | }
68 |
69 | }
70 | }
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/AtmCards/AtmCard.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models.AtmCards;
2 |
3 | import org.anuva04.Enums.PaymentNetwork;
4 | import org.anuva04.Models.Bank;
5 |
6 | import java.time.LocalDate;
7 |
8 | public class AtmCard {
9 | private String cardNumber;
10 | private int CVV;
11 | private PaymentNetwork paymentNetwork;
12 | private String ownerName;
13 | private LocalDate expiryDate;
14 | private Bank bank;
15 |
16 | public AtmCard(String cardNumber, int CVV, String ownerName, LocalDate expiryDate) {
17 | this.cardNumber = cardNumber;
18 | this.CVV = CVV;
19 | this.ownerName = ownerName;
20 | this.expiryDate = expiryDate;
21 | }
22 |
23 | public void setPaymentNetwork(PaymentNetwork paymentNetwork) {
24 | this.paymentNetwork = paymentNetwork;
25 | }
26 |
27 | public void setBank(Bank bank) {
28 | this.bank = bank;
29 | }
30 |
31 | public Bank getBank() {
32 | return this.bank;
33 | }
34 |
35 | public String getCardNumber() {
36 | return cardNumber;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/AtmCards/AxisVisaCard.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models.AtmCards;
2 |
3 | import org.anuva04.Enums.PaymentNetwork;
4 | import org.anuva04.Models.Bank;
5 |
6 | import java.time.LocalDate;
7 |
8 | public class AxisVisaCard extends AtmCard {
9 | public AxisVisaCard(String cardNumber, int CVV, String ownerName, LocalDate expiryDate) {
10 | super(cardNumber, CVV, ownerName, expiryDate);
11 | this.setBank(new Bank("Axis Bank"));
12 | this.setPaymentNetwork(PaymentNetwork.VISA);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/AtmCards/SbiRupayCard.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models.AtmCards;
2 |
3 | import org.anuva04.Enums.PaymentNetwork;
4 | import org.anuva04.Models.Bank;
5 |
6 | import java.time.LocalDate;
7 |
8 | public class SbiRupayCard extends AtmCard {
9 | public SbiRupayCard(String cardNumber, int CVV, String ownerName, LocalDate expiryDate) {
10 | super(cardNumber, CVV, ownerName, expiryDate);
11 | this.setBank(new Bank("State Bank of India"));
12 | this.setPaymentNetwork(PaymentNetwork.RUPAY);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/Bank.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | public class Bank {
4 | private String bankName;
5 |
6 | public Bank(String bankName) {
7 | this.bankName = bankName;
8 | }
9 |
10 | public boolean verifyAtmPin(String cardNumber, int pin) {
11 | // Pin verification logic here
12 | return true;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/CashAvailabilityDataResponseModel.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | public class CashAvailabilityDataResponseModel {
4 | public boolean isCashAvailable;
5 | public CashReserve cashReserve;
6 |
7 | // Response returned by getCashAvailability method Cash dispensing strategy
8 | public CashAvailabilityDataResponseModel(boolean isCashAvailable, CashReserve cashReserve) {
9 | this.isCashAvailable = isCashAvailable;
10 | this.cashReserve = cashReserve;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/CashReserve.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import org.anuva04.Enums.Denomination;
4 |
5 | import java.util.HashMap;
6 |
7 | public class CashReserve {
8 | private HashMap cashReserveMap;
9 |
10 | public void modifyCashReserve(CashReserve newCashReserve) {
11 | newCashReserve.cashReserveMap.forEach((currency, count) -> {
12 | this.cashReserveMap.put(currency, this.cashReserveMap.get(currency) + count);
13 | });
14 | }
15 |
16 | public CashReserve() {
17 | cashReserveMap = new HashMap<>();
18 | for (Denomination denomination : Denomination.values()) {
19 | cashReserveMap.put(denomination, 0);
20 | }
21 | }
22 |
23 | public HashMap getCashReserveMap() {
24 | return cashReserveMap;
25 | }
26 |
27 | public void updateCash(Denomination denomination, Integer count) {
28 | cashReserveMap.put(denomination, count);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Models/Currency.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import org.anuva04.Enums.Denomination;
4 |
5 | public class Currency {
6 | public static int getValue(Denomination denomination) {
7 | switch (denomination) {
8 | case FIFTY:
9 | return 50;
10 | case HUNDRED:
11 | return 100;
12 | case FIVE_HUNDRED:
13 | return 500;
14 | case THOUSAND:
15 | return 1000;
16 | case TWO_THOUSAND:
17 | return 2000;
18 | default:
19 | throw new IllegalArgumentException("Denomination not supported!");
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Strategies/CashDispenserStrategy.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Strategies;
2 |
3 | import org.anuva04.Models.CashAvailabilityDataResponseModel;
4 | import org.anuva04.Models.CashReserve;
5 |
6 | public interface CashDispenserStrategy {
7 | CashReserve dispenseCash(CashReserve cashReserve, CashReserve cashRequest);
8 |
9 | CashAvailabilityDataResponseModel getCashAvailability(CashReserve cashReserve, int amount);
10 | }
11 |
--------------------------------------------------------------------------------
/LLD/ATM/src/main/java/org/anuva04/Strategies/SimpleCashDispenseStrategy.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Strategies;
2 |
3 | import org.anuva04.Enums.Denomination;
4 | import org.anuva04.Models.CashAvailabilityDataResponseModel;
5 | import org.anuva04.Models.CashReserve;
6 | import org.anuva04.Models.Currency;
7 |
8 | import java.util.Map;
9 |
10 | // Works for denomination [50, 100, 500, 1000, 2000]
11 | public class SimpleCashDispenseStrategy implements CashDispenserStrategy {
12 | @Override
13 | public CashReserve dispenseCash(CashReserve cashReserve, CashReserve cashRequest) {
14 | cashRequest.getCashReserveMap().forEach((key, value) -> {
15 | cashReserve.getCashReserveMap().put(key, cashReserve.getCashReserveMap().get(key) - value);
16 | });
17 | return cashRequest;
18 | }
19 |
20 | @Override
21 | public CashAvailabilityDataResponseModel getCashAvailability(CashReserve cashReserve, int amount) {
22 | boolean isCashAvailable = false;
23 | CashReserve result = new CashReserve();
24 |
25 | for (Map.Entry entry : cashReserve.getCashReserveMap().entrySet()) {
26 | Denomination denomination = entry.getKey();
27 | Integer count = entry.getValue();
28 |
29 | while (count > 0 && amount > 0 && Currency.getValue(denomination) <= amount) {
30 | amount -= Currency.getValue(denomination);
31 | count -= 1;
32 | if (result.getCashReserveMap().containsKey(denomination)) {
33 | result.getCashReserveMap().put(denomination, result.getCashReserveMap().get(denomination) + 1);
34 | } else {
35 | result.getCashReserveMap().put(denomination, 1);
36 | }
37 | }
38 | }
39 |
40 | if (amount == 0) isCashAvailable = true;
41 |
42 | return new CashAvailabilityDataResponseModel(isCashAvailable, result);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/README.md:
--------------------------------------------------------------------------------
1 | # Elevator System
2 |
3 | The Elevator System is a program that simulates an elevator control system. It includes classes for managing elevators, different elevator types, and strategies for allocating elevators to requests.
4 |
5 | ## ElevatorSystem
6 |
7 | The `ElevatorSystem` class is the main controller class for the elevator system. It maintains a list of elevators, handles elevator requests from external switches, and processes these requests using an elevator allocation strategy.
8 |
9 | ### Class Structure
10 |
11 | - `ElevatorSystem`
12 | - `elevatorList`: A list of elevators in the system.
13 | - `numElevators`: The number of elevators currently in the system.
14 | - `requests`: A queue to store elevator requests from external switches.
15 | - `requestProcessorScheduler`: A scheduled executor service for processing elevator requests.
16 | - `allocationStrategy`: The elevator allocation strategy used to assign elevators to requests.
17 |
18 | ### Methods
19 |
20 | - `addElevator(ElevatorType type)`: Adds a new elevator of the specified type to the system.
21 | - `requestElevator(int fromFloor)`: Simulates an external switch requesting an elevator from a specific floor.
22 | - `addStop(int elevatorId, int floor)`: Simulates an internal switch in an elevator, adding a stop at a specific floor.
23 | - `requestProcessor()`: Processes elevator requests from the queue and assigns them to the appropriate elevator based on the allocation strategy.
24 | - `getStatus()`: Prints the current status of all elevators in the system.
25 | - `setAllocationStrategy(ElevatorAllocationStrategy allocationStrategy)`: Sets the elevator allocation strategy for the system.
26 |
27 | ## Elevator
28 |
29 | The `Elevator` class represents an elevator in the system. It maintains information such as the current floor, direction, capacity, and stops requested by internal switches.
30 |
31 | ### Class Structure
32 |
33 | - `Elevator`
34 | - `requestProcessorScheduler`: A scheduled executor service for processing elevator requests.
35 | - `id`: The unique identifier of the elevator.
36 | - `currentFloor`: The current floor where the elevator is located.
37 | - `status`: The status of the elevator (e.g., working, out of service).
38 | - `floors`: A list to track the floors where the elevator has stops.
39 | - `direction`: The direction in which the elevator is moving.
40 | - `maxCapacity`: The maximum capacity of the elevator.
41 | - `currentCapacity`: The current number of passengers in the elevator.
42 |
43 | ### Methods
44 |
45 | - `addStop(int floor)`: Simulates an internal switch in the elevator, adding a stop at a specific floor.
46 | - `requestProcessor()`: Processes the stops requested by internal switches and updates the elevator's state accordingly.
47 | - `getStatus()`: Gets the status of the elevator.
48 | - Getter and setter methods for various properties of the elevator.
49 |
50 | ## ElevatorAllocationStrategy
51 |
52 | The `ElevatorAllocationStrategy` interface defines the contract for different strategies used to allocate elevators to requests. It includes a single method, `getElevator`, which takes a list of elevators and a floor as input and returns the ID of the elevator that should be assigned to the request.
53 |
54 | ### Interface Structure
55 |
56 | - `ElevatorAllocationStrategy`
57 | - `getElevator(List elevatorList, int floor)`: Assigns an elevator from the given list to the specified floor.
58 |
59 | ### SimpleElevatorAllocationStrategy
60 |
61 | The `SimpleElevatorAllocationStrategy` class is an implementation of the `ElevatorAllocationStrategy` interface. It provides a simple strategy for allocating elevators based on certain criteria.
62 |
63 | #### Class Structure
64 |
65 | - `SimpleElevatorAllocationStrategy`
66 |
67 | #### Methods
68 |
69 | - `getElevator(List elevatorList, int floor)`: Assigns the elevator with the closest distance to the specified floor, considering factors such as elevator direction and current capacity.
70 | ---
71 | #### Java Version
72 |
73 | The code is written in Java 11.
74 |
75 | #### Build System
76 |
77 | The build system used for this project is Maven. Maven provides a standard project structure and handles dependencies, compilation, and packaging.
78 |
79 | To build the project using Maven, navigate to the root directory of the project and run the following command:
80 |
81 | `mvn clean install`
82 |
83 | This will compile the source code, run tests, and package the project into a JAR file.
84 |
85 | ---
86 |
87 | ### Scope for developments
88 | - Error Handling and Exception Handling: The code lacks explicit error handling and exception handling mechanisms. Adding appropriate error handling and exception handling would make the code more robust and reliable.
89 | - Improve Logging: Instead of using System.out.println() for logging, consider using a logging framework such as Log4j or java.util.logging. This allows for more advanced logging capabilities, such as log levels, log file rotation, and customizable log formats.
90 | - Implement Unit Tests: Write unit tests to verify the functionality of the classes and ensure that they work as expected. This will help catch bugs early and make it easier to maintain and refactor the code in the future.
91 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.anuva04
8 | ElevatorSystem
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 11
13 | 11
14 | UTF-8
15 |
16 |
17 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Controllers/ElevatorSystem.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Enums.ElevatorType;
4 | import org.anuva04.Models.AccelElevator;
5 | import org.anuva04.Models.ClassicElevator;
6 | import org.anuva04.Models.Elevator;
7 | import org.anuva04.Models.ServiceElevator;
8 | import org.anuva04.Strategies.ElevatorAllocationStrategy;
9 |
10 | import java.util.ArrayDeque;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.concurrent.Executors;
14 | import java.util.concurrent.ScheduledExecutorService;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | public class ElevatorSystem {
18 | private final List elevatorList = new ArrayList<>();
19 | private int numElevators = 0;
20 | private final ArrayDeque requests = new ArrayDeque<>();
21 | private final ScheduledExecutorService requestProcessorScheduler;
22 | private ElevatorAllocationStrategy allocationStrategy;
23 |
24 | public ElevatorSystem() {
25 | this.requestProcessorScheduler = Executors.newSingleThreadScheduledExecutor();
26 | this.requestProcessorScheduler.scheduleAtFixedRate(this::requestProcessor, 100, 100, TimeUnit.MILLISECONDS);
27 | }
28 |
29 | // Add new elevator of required type to Controllers.ElevatorSystem
30 | public void addElevator(ElevatorType type) {
31 | System.out.println("Received request to add elevator of type:" + type);
32 | this.numElevators++;
33 | switch (type) {
34 | case CLASSIC:
35 | this.elevatorList.add(new ClassicElevator(this.numElevators));
36 | break;
37 | case SERVICE:
38 | this.elevatorList.add(new ServiceElevator(this.numElevators));
39 | break;
40 | case ACCEL:
41 | this.elevatorList.add(new AccelElevator(this.numElevators));
42 | break;
43 | }
44 | }
45 |
46 | // Simulates external switch to request for elevator from any floor
47 | public void requestElevator(int fromFloor) {
48 | this.requests.add(fromFloor);
49 | }
50 |
51 | // Simulates internal switch in an elevator to stop at any floor
52 | public void addStop(int elevatorId, int floor) {
53 | this.elevatorList.get(elevatorId - 1).addStop(floor);
54 | }
55 |
56 | // Method to process all requests coming from external switches
57 | private void requestProcessor() {
58 | Integer floor = this.requests.poll();
59 | if (floor != null) {
60 | System.out.println("Got elevator request for floor: " + floor);
61 | int closestElevatorId = this.allocationStrategy.getElevator(elevatorList, floor);
62 | if (closestElevatorId == 0) {
63 | System.out.println("No elevator available, trying again in a while!");
64 | this.requests.addFirst(floor);
65 | return;
66 | }
67 | System.out.println("Found closest elevator: " + closestElevatorId);
68 | this.elevatorList.get(closestElevatorId - 1).addStop(floor);
69 | }
70 | }
71 |
72 | // Method to print current status of all the elevators
73 | public void getStatus() {
74 | System.out.println("Status of all elevators:");
75 | for (Elevator elevator : this.elevatorList) {
76 | System.out.println("Models.Elevator ID: " + elevator.getId() +
77 | " | Current Floor: " + elevator.getCurrentFloor() +
78 | " | Direction: " + elevator.getDirection());
79 | }
80 | }
81 |
82 | public void setAllocationStrategy(ElevatorAllocationStrategy allocationStrategy) {
83 | this.allocationStrategy = allocationStrategy;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Enums/ElevatorDirection.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Enums;
2 |
3 | public enum ElevatorDirection {
4 | UP, DOWN
5 | }
6 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Enums/ElevatorStatus.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Enums;
2 |
3 | public enum ElevatorStatus {
4 | WORKING, NOT_WORKING
5 | }
6 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Enums/ElevatorType.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Enums;
2 |
3 | public enum ElevatorType {
4 | CLASSIC, SERVICE, ACCEL
5 | }
6 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Main.java:
--------------------------------------------------------------------------------
1 | package org.anuva04;
2 |
3 | import org.anuva04.Controllers.ElevatorSystem;
4 | import org.anuva04.Enums.ElevatorType;
5 | import org.anuva04.Strategies.SimpleElevatorAllocationStrategy;
6 |
7 | import java.util.Scanner;
8 |
9 | public class Main {
10 | public static void main(String[] args) {
11 | ElevatorSystem elevatorSystem = new ElevatorSystem();
12 | elevatorSystem.setAllocationStrategy(new SimpleElevatorAllocationStrategy());
13 | System.out.println("For elevator status - 1");
14 | System.out.println("For requesting elevator - 2");
15 | System.out.println("For adding stop - 3");
16 | System.out.println("For adding new elevator - 4");
17 | Scanner scanner = new Scanner(System.in);
18 | int floor;
19 | while (true) {
20 | int req = scanner.nextInt();
21 | switch(req){
22 | case 1:
23 | elevatorSystem.getStatus();
24 | break;
25 | case 2:
26 | System.out.print("Type floor number: ");
27 | floor = scanner.nextInt();
28 | elevatorSystem.requestElevator(floor);
29 | break;
30 | case 3:
31 | System.out.print("Type floor number: ");
32 | floor = scanner.nextInt();
33 | System.out.print("Type elevator number: ");
34 | int elevator = scanner.nextInt();
35 | elevatorSystem.addStop(elevator, floor);
36 | break;
37 | case 4:
38 | System.out.print("Enter type of elevator (CLASSIC/SERVICE/ACCEL): ");
39 | String type = scanner.next();
40 | ElevatorType elevatorType;
41 | try {
42 | elevatorType = ElevatorType.valueOf(type.toUpperCase());
43 | elevatorSystem.addElevator(elevatorType);
44 | } catch (IllegalArgumentException e) {
45 | System.out.println("Invalid elevator type: " + type);
46 | }
47 | break;
48 | default:
49 | System.out.println("Invalid input!!!");
50 | }
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Models/AccelElevator.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | public class AccelElevator extends Elevator {
6 | public AccelElevator(int id) {
7 | super(id);
8 | this.setMaxCapacity(500);
9 | this.requestProcessorScheduler.scheduleAtFixedRate(this::requestProcessor, 100, 100, TimeUnit.MILLISECONDS);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Models/ClassicElevator.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | public class ClassicElevator extends Elevator {
6 | public ClassicElevator(int id) {
7 | super(id);
8 | this.setMaxCapacity(500);
9 | this.requestProcessorScheduler.scheduleAtFixedRate(this::requestProcessor, 100, 1000, TimeUnit.MILLISECONDS);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Models/Elevator.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 | import java.util.Random;
7 | import java.util.concurrent.Executors;
8 | import java.util.concurrent.ScheduledExecutorService;
9 |
10 | import org.anuva04.Enums.ElevatorStatus;
11 | import org.anuva04.Enums.ElevatorDirection;
12 | import org.anuva04.Utils.Constants;
13 |
14 | public class Elevator {
15 | protected ScheduledExecutorService requestProcessorScheduler = Executors.newSingleThreadScheduledExecutor();
16 | private final int id;
17 | private int currentFloor;
18 | private final ElevatorStatus status;
19 | private final List floors;
20 | private ElevatorDirection direction;
21 | private int maxCapacity;
22 | private int currentCapacity = 0;
23 |
24 | public Elevator(int id) {
25 | this.id = id;
26 | this.currentFloor = 0;
27 | this.status = ElevatorStatus.WORKING;
28 | this.direction = ElevatorDirection.UP;
29 | this.floors = new ArrayList<>(Collections.nCopies(Constants.NUM_FLOORS, false));
30 | }
31 |
32 | // Simulates internal switch in an elevator to stop at any floor
33 | public void addStop(int floor) {
34 | System.out.println("Got request to stop at floor: " + floor + " for elevator ID: " + this.id);
35 | this.floors.set(floor, true);
36 | }
37 |
38 | // Method to process all requests coming from internal switches of the elevator
39 | protected void requestProcessor() {
40 | if (this.currentFloor == 0) this.direction = ElevatorDirection.UP;
41 | if (this.currentFloor == Constants.NUM_FLOORS - 1) this.direction = ElevatorDirection.DOWN;
42 | if (this.direction == ElevatorDirection.UP) {
43 | if (findAndProcessRequest(ElevatorDirection.UP)) return;
44 | if (findAndProcessRequest(ElevatorDirection.DOWN)) {
45 | this.direction = ElevatorDirection.DOWN;
46 | }
47 | } else {
48 | if (findAndProcessRequest(ElevatorDirection.DOWN)) return;
49 | if (findAndProcessRequest(ElevatorDirection.UP)) {
50 | this.direction = ElevatorDirection.UP;
51 | }
52 | }
53 | }
54 |
55 | private boolean findAndProcessRequest(ElevatorDirection direction) {
56 | if (direction == ElevatorDirection.UP) {
57 | for (int floor = this.currentFloor; floor < Constants.NUM_FLOORS; floor++) {
58 | if (this.floors.get(floor)) {
59 | this.updateElevatorInfo(floor);
60 | return true;
61 | }
62 | }
63 | } else {
64 | for (int floor = this.currentFloor; floor >= 0; floor--) {
65 | if (this.floors.get(floor)) {
66 | this.updateElevatorInfo(floor);
67 | return true;
68 | }
69 | }
70 | }
71 | return false;
72 | }
73 |
74 | private void updateElevatorInfo(int floor) {
75 | this.floors.set(floor, false);
76 | this.currentFloor = floor;
77 | Random random = new Random();
78 | int randomNumber = random.nextInt(this.maxCapacity + 30);
79 | this.setCurrentCapacity(randomNumber);
80 | }
81 |
82 | public ElevatorStatus getStatus() {
83 | return status;
84 | }
85 |
86 | public ElevatorDirection getDirection() {
87 | return direction;
88 | }
89 |
90 | public int getId() {
91 | return id;
92 | }
93 |
94 | public int getCurrentFloor() {
95 | return currentFloor;
96 | }
97 |
98 | public int getCurrentCapacity() {
99 | return currentCapacity;
100 | }
101 |
102 | public void setCurrentCapacity(int currentCapacity) {
103 | this.currentCapacity = currentCapacity;
104 | }
105 |
106 | public int getMaxCapacity() {
107 | return maxCapacity;
108 | }
109 |
110 | public void setMaxCapacity(int maxCapacity) {
111 | this.maxCapacity = maxCapacity;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Models/ServiceElevator.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | public class ServiceElevator extends Elevator {
6 | public ServiceElevator(int id) {
7 | super(id);
8 | this.setMaxCapacity(1000);
9 | this.requestProcessorScheduler.scheduleAtFixedRate(this::requestProcessor, 100, 1000, TimeUnit.MILLISECONDS);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Strategies/ElevatorAllocationStrategy.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Strategies;
2 |
3 | import org.anuva04.Models.Elevator;
4 | import java.util.List;
5 |
6 | public interface ElevatorAllocationStrategy {
7 | public int getElevator(List elevatorList, int floor);
8 | }
9 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Strategies/SimpleElevatorAllocationStrategy.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Strategies;
2 |
3 | import org.anuva04.Enums.ElevatorDirection;
4 | import org.anuva04.Models.Elevator;
5 | import org.anuva04.Enums.ElevatorStatus;
6 | import org.anuva04.Utils.Constants;
7 |
8 | import java.util.List;
9 |
10 | public class SimpleElevatorAllocationStrategy implements ElevatorAllocationStrategy{
11 | @Override
12 | public int getElevator(List elevatorList, int floor) {
13 | int closestElevatorId = 0;
14 | int closestDistance = Integer.MAX_VALUE;
15 | for (Elevator elevator : elevatorList) {
16 | if (elevator.getStatus() == ElevatorStatus.NOT_WORKING) continue;
17 | if (elevator.getCurrentCapacity() >= elevator.getMaxCapacity() - 30) continue;
18 | int distance;
19 | if (elevator.getDirection() == ElevatorDirection.UP) {
20 | if (floor >= elevator.getCurrentFloor()) {
21 | distance = floor - elevator.getCurrentFloor();
22 | } else {
23 | distance = (Constants.NUM_FLOORS - elevator.getCurrentFloor()) + (Constants.NUM_FLOORS - floor);
24 | }
25 | } else {
26 | if (floor <= elevator.getCurrentFloor()) {
27 | distance = elevator.getCurrentFloor() - floor;
28 | } else {
29 | distance = elevator.getCurrentFloor() + floor;
30 | }
31 | }
32 | if (distance < closestDistance) {
33 | closestElevatorId = elevator.getId();
34 | closestDistance = distance;
35 | }
36 | }
37 | return closestElevatorId;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LLD/ElevatorSystem/src/main/java/org/anuva04/Utils/Constants.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils;
2 |
3 | public class Constants {
4 | public static int NUM_FLOORS = 20;
5 | }
6 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("java")
3 | }
4 |
5 | group = "org.anuva04"
6 | version = "1.0-SNAPSHOT"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | testImplementation(platform("org.junit:junit-bom:5.9.1"))
14 | testImplementation("org.junit.jupiter:junit-jupiter")
15 | }
16 |
17 | tasks.test {
18 | useJUnitPlatform()
19 | }
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuva04/SystemDesign/2338ea19d4f60812e6e37206f7b13a150e4ca78a/LLD/MeetingScheduler/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jul 16 14:10:46 IST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "MeetingScheduler"
2 |
3 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Controllers/CommandLineParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Utils.Parsers.*;
4 | import org.anuva04.Utils.Constants;
5 |
6 | import java.util.Map;
7 |
8 | public class CommandLineParser {
9 | // Method to determine command type and call appropriate CommandParser instance
10 | public static String parseAndExecuteCommand(String command, Map args) {
11 | AbstractCommandParser parser;
12 | switch (command) {
13 | case Constants.CREATE_MEETING:
14 | parser = new CreateMeetingCommandParser();
15 | break;
16 | case Constants.DELETE_MEETING:
17 | parser = new DeleteMeetingCommandParser();
18 | break;
19 | case Constants.GET_MEETINGS:
20 | parser = new GetMeetingsForUsernameForDateCommandParser();
21 | break;
22 | case Constants.CHANGE_LOCATION:
23 | parser = new ChangeMeetingLocationCommandParser();
24 | break;
25 | case Constants.CHANGE_TIME:
26 | parser = new ChangeMeetingTimeCommandParser();
27 | break;
28 | case Constants.FORWARD_MEETING:
29 | parser = new ForwardMeetingCommandParser();
30 | break;
31 | case Constants.SHOW_CALENDAR:
32 | parser = new ShowCalendarCommandParser();
33 | break;
34 | default:
35 | throw new IllegalArgumentException("Command doesn't exist.");
36 | }
37 | String error = parser.validate(args);
38 | if(error == null) {
39 | parser.callMethod(args);
40 | }
41 | return error;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Controllers/MeetingScheduler.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 |
5 | import java.util.*;
6 |
7 | // Entry point to a Meeting Scheduler app
8 | public class MeetingScheduler {
9 | public MeetingDb meetingDb;
10 |
11 | public MeetingScheduler() {
12 | this.meetingDb = MeetingDb.getInstance();
13 | }
14 |
15 | // Simulates calling various methods on UI
16 | public void init() {
17 | Scanner sc = new Scanner(System.in);
18 | while(true) {
19 | System.out.println("Enter command: ");
20 | String command = sc.nextLine();
21 | Scanner scanner = new Scanner(command);
22 | List tokens = new ArrayList<>();
23 | while (scanner.hasNext()) {
24 | tokens.add(scanner.next());
25 | }
26 | scanner.close();
27 |
28 | // Command
29 | String method = tokens.get(0);
30 | // List of arguments
31 | Map args = new HashMap<>();
32 | for (int i = 1; i < tokens.size(); i += 2) {
33 | String option = tokens.get(i);
34 | String value = tokens.get(i + 1);
35 | args.put(option, value);
36 | }
37 |
38 | try {
39 | String errorMessage = CommandLineParser.parseAndExecuteCommand(method, args);
40 | if(errorMessage == null) {
41 | System.out.println("Command executed successfully.");
42 | } else {
43 | System.out.println("Command validation failed at: " + errorMessage);
44 | }
45 | } catch (Exception e) {
46 | System.out.println("An exception has occurred while executing command: " + e.getMessage());
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Main.java:
--------------------------------------------------------------------------------
1 | package org.anuva04;
2 |
3 | import org.anuva04.Controllers.MeetingScheduler;
4 |
5 | public class Main {
6 | public static void main(String[] args) {
7 | MeetingScheduler ms = new MeetingScheduler();
8 | ms.init();
9 | }
10 | }
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Models/Meeting.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import java.time.LocalDateTime;
4 | import java.util.*;
5 |
6 | public class Meeting {
7 | public String title;
8 | public String location;
9 | public String organizer;
10 | public LocalDateTime startTime;
11 | public int duration;
12 | public UUID id;
13 | public Set invitees;
14 |
15 | public Meeting(String title, String location, String organizer, LocalDateTime startTime, int duration, UUID id) {
16 | this.title = title;
17 | this.location = location;
18 | this.organizer = organizer;
19 | this.startTime = startTime;
20 | this.duration = duration;
21 | this.id = id;
22 | this.invitees = new HashSet<>();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Constants.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils;
2 |
3 | public class Constants {
4 | // Method names
5 | public static final String CREATE_MEETING = "create-meeting";
6 | public static final String DELETE_MEETING = "delete-meeting";
7 | public static final String GET_MEETINGS = "get-meetings";
8 | public static final String CHANGE_LOCATION = "change-location";
9 | public static final String CHANGE_TIME = "change-time";
10 | public static final String FORWARD_MEETING = "forward-meeting";
11 | public static final String SHOW_CALENDAR = "show-calendar";
12 |
13 | // Method arguments
14 | public static final String ORGANIZER = "--organizer";
15 | public static final String REQUESTER = "--requester";
16 | public static final String START_TIME = "--startTime";
17 | public static final String DURATION = "--duration";
18 | public static final String LOCATION = "--location";
19 | public static final String TITLE = "--title";
20 | public static final String INVITEES = "--invitees";
21 | public static final String MEETING_ID = "--meetingId";
22 | public static final String USERNAME = "--username";
23 | public static final String DATE = "--date";
24 |
25 | public static final String INVITEES_DELIMITER = ",";
26 | }
27 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Helper.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils;
2 |
3 | import java.time.LocalDate;
4 | import java.time.LocalDateTime;
5 | import java.time.format.DateTimeFormatter;
6 |
7 | public class Helper {
8 | // Method to convert string to LocalDateTime
9 | public static LocalDateTime getLocalDateTime(String date) {
10 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm");
11 | LocalDateTime dateTime = LocalDateTime.parse(date, formatter);
12 | return dateTime;
13 | }
14 |
15 | // Method to extract date from datetime
16 | public static LocalDate getLocalDate(String sdate) {
17 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
18 | LocalDate date = LocalDate.parse(sdate, formatter);
19 | return date;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/AbstractCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | public abstract class AbstractCommandParser {
7 | public String validate(Map args) {
8 | for(String arg : getRequiredArgs()) {
9 | if(!args.containsKey(arg)) return arg;
10 | }
11 | return null;
12 | }
13 |
14 | protected abstract List getRequiredArgs();
15 | public abstract void callMethod(Map args);
16 | }
17 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/ChangeMeetingLocationCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 |
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.UUID;
9 |
10 | public class ChangeMeetingLocationCommandParser extends AbstractCommandParser {
11 | private static List requiredArgs = List.of(Constants.MEETING_ID, Constants.LOCATION, Constants.REQUESTER);
12 |
13 | @Override
14 | protected List getRequiredArgs() {
15 | return requiredArgs;
16 | }
17 |
18 | @Override
19 | public void callMethod(Map args) {
20 | MeetingDb meetingDb = MeetingDb.getInstance();
21 |
22 | UUID meetingId = UUID.fromString(args.get(Constants.MEETING_ID));
23 | String location = args.get(Constants.LOCATION);
24 | String requester = args.get(Constants.REQUESTER);
25 |
26 | meetingDb.changeMeetingLocation(meetingId, location, requester);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/ChangeMeetingTimeCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 | import org.anuva04.Utils.Helper;
6 |
7 | import java.time.LocalDateTime;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.UUID;
11 |
12 | public class ChangeMeetingTimeCommandParser extends AbstractCommandParser {
13 | private static List requiredArgs = List.of(Constants.MEETING_ID, Constants.START_TIME, Constants.DURATION, Constants.REQUESTER);
14 |
15 | @Override
16 | protected List getRequiredArgs() {
17 | return requiredArgs;
18 | }
19 |
20 | @Override
21 | public void callMethod(Map args) {
22 | MeetingDb meetingDb = MeetingDb.getInstance();
23 |
24 | UUID meetingId = UUID.fromString(args.get(Constants.MEETING_ID));
25 | int duration = Integer.parseInt(args.get(Constants.DURATION));
26 | LocalDateTime startTime = Helper.getLocalDateTime(args.get(Constants.START_TIME));
27 | String requester = args.get(Constants.REQUESTER);
28 |
29 | meetingDb.changeMeetingTime(meetingId, startTime, duration, requester);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/CreateMeetingCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 | import org.anuva04.Utils.Helper;
6 |
7 | import java.time.LocalDateTime;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | public class CreateMeetingCommandParser extends AbstractCommandParser {
12 | private static List requiredArgs = List.of(Constants.ORGANIZER, Constants.START_TIME, Constants.TITLE, Constants.DURATION, Constants.LOCATION, Constants.INVITEES);
13 |
14 | @Override
15 | protected List getRequiredArgs() {
16 | return requiredArgs;
17 | }
18 |
19 | @Override
20 | public void callMethod(Map args) {
21 | MeetingDb meetingDb = MeetingDb.getInstance();
22 |
23 | String organizer = args.get(Constants.ORGANIZER);
24 | String title = args.get(Constants.TITLE);
25 | LocalDateTime startTime = Helper.getLocalDateTime(args.get(Constants.START_TIME));
26 | int duration = Integer.parseInt(args.get(Constants.DURATION));
27 | String location = args.get(Constants.LOCATION);
28 | List invitees = List.of(args.get(Constants.INVITEES).split(Constants.INVITEES_DELIMITER));
29 |
30 | meetingDb.createMeeting(organizer, startTime, duration, location, title, invitees);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/DeleteMeetingCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 |
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.UUID;
9 |
10 | public class DeleteMeetingCommandParser extends AbstractCommandParser {
11 | private static List requiredArgs = List.of(Constants.REQUESTER, Constants.MEETING_ID);
12 |
13 | @Override
14 | protected List getRequiredArgs() {
15 | return requiredArgs;
16 | }
17 |
18 | @Override
19 | public void callMethod(Map args) {
20 | MeetingDb meetingDb = MeetingDb.getInstance();
21 |
22 | String requester = args.get(Constants.REQUESTER);
23 | UUID meetingId = UUID.fromString(args.get(Constants.MEETING_ID));
24 |
25 | meetingDb.deleteMeeting(meetingId, requester);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/ForwardMeetingCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 |
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.UUID;
9 |
10 | public class ForwardMeetingCommandParser extends AbstractCommandParser {
11 | private static List requiredArgs = List.of(Constants.MEETING_ID, Constants.INVITEES);
12 |
13 | @Override
14 | protected List getRequiredArgs() {
15 | return requiredArgs;
16 | }
17 |
18 | @Override
19 | public void callMethod(Map args) {
20 | MeetingDb meetingDb = MeetingDb.getInstance();
21 |
22 | UUID meetingId = UUID.fromString(args.get(Constants.MEETING_ID));
23 | List invitees = List.of(args.get(Constants.INVITEES).split(Constants.INVITEES_DELIMITER));
24 |
25 | meetingDb.forwardMeeting(meetingId, invitees);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/GetMeetingsForUsernameForDateCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 | import org.anuva04.Utils.Helper;
6 |
7 | import java.time.LocalDate;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | public class GetMeetingsForUsernameForDateCommandParser extends AbstractCommandParser {
12 | private static List requiredArgs = List.of(Constants.USERNAME, Constants.DATE);
13 |
14 | @Override
15 | protected List getRequiredArgs() {
16 | return requiredArgs;
17 | }
18 |
19 | @Override
20 | public void callMethod(Map args) {
21 | MeetingDb meetingDb = MeetingDb.getInstance();
22 |
23 | String username = args.get(Constants.USERNAME);
24 | LocalDate date = Helper.getLocalDate(args.get(Constants.DATE));
25 |
26 | meetingDb.getMeetingsForUsernameForDate(username, date);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/java/org/anuva04/Utils/Parsers/ShowCalendarCommandParser.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Utils.Parsers;
2 |
3 | import org.anuva04.Models.MeetingDb;
4 | import org.anuva04.Utils.Constants;
5 | import org.anuva04.Utils.Helper;
6 |
7 | import java.time.LocalDate;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | public class ShowCalendarCommandParser extends AbstractCommandParser {
12 | private static List requiredArgs = List.of(Constants.DATE, Constants.INVITEES);
13 |
14 | @Override
15 | protected List getRequiredArgs() {
16 | return requiredArgs;
17 | }
18 |
19 | @Override
20 | public void callMethod(Map args) {
21 | MeetingDb meetingDb = MeetingDb.getInstance();
22 |
23 | LocalDate date = Helper.getLocalDate(args.get(Constants.DATE));
24 | List invitees = List.of(args.get(Constants.INVITEES).split(Constants.INVITEES_DELIMITER));
25 |
26 | meetingDb.showCalendar(date, invitees);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/resources/Requirements.txt:
--------------------------------------------------------------------------------
1 | Meeting scheduler will work under the scope of a single organization.
2 | Functional requirements:
3 | - User should be able to schedule a meeting at a desired time with desired participants.
4 | - User can search for participants by their username.
5 | - User should be able to cancel self-created meetings.
6 | - User should be able to view meeting invites (self-created and invitations from others).
7 | - User should be able to accept/decline invites -- not implemented yet.
8 | - User should be able to check others' schedules to determine suitable time for meeting.
9 | - Schedule will be shown for next 30 days
--------------------------------------------------------------------------------
/LLD/MeetingScheduler/src/main/resources/SampleInput.txt:
--------------------------------------------------------------------------------
1 | // Create new meeting by user1
2 | create-meeting --organizer user1 --startTime 2023-08-08T12:00 --duration 30 --title SampleMeeting --location MSTeams --invitees in1,in2,in3
3 |
4 | // Create another meeting for user1
5 | create-meeting --organizer user1 --startTime 2023-08-08T14:00 --duration 30 --title AnotherSampleMeeting --location MSTeams --invitees user2,in2,in4
6 |
7 | // Create new meeting for user2
8 | create-meeting --organizer user2 --startTime 2023-08-09T12:00 --duration 60 --title DifferentSampleMeeting --location MSTeams --invitees in1,in2,user1
9 |
10 | // Get meetings for user1
11 | get-meetings --username user1 --date 2023-08-08
12 |
13 | // Get meetings for user2
14 | get-meetings --username user2 --date 2023-08-08
15 |
16 | // Delete meeting by user1
17 | delete-meeting --meetingId --requester user1
18 |
19 | // Change meeting time
20 | change-time --meetingId --startTime 2023-08-15T12:00 --duration 25 --requester user2
21 |
22 | // Change meeting location
23 | change-location --meetingId --location GoogleMeet --requester user2
24 |
25 | // Show calendar
26 | show-calendar --date 2023-08-08 --invitees user1,user2
27 |
28 | // Forward meeting
29 | forward-meeting --meetingId --invitees newInvitee
--------------------------------------------------------------------------------
/LLD/VendingMachine/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/LLD/VendingMachine/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/README.md:
--------------------------------------------------------------------------------
1 | # Vending Machine LLD
2 |
3 | This is a simple implementation of a Vending Machine using Java. The Vending Machine allows users to select and purchase items, and administrators to manage the inventory. It provides a command-line interface for interaction.
4 |
5 | ## Code Files
6 |
7 | The code files are organized under the following packages:
8 | - `org.anuva04`: The main package that contains the `Main` class as the entry point of the program.
9 | - `Main.java`: **Entry point** of the program. It initializes the Vending Machine and starts the application.
10 |
11 |
12 | - `org.anuva04.Controllers`: Contains the `VendingMachine`, `UserOperations`, and `AdminOperations` classes.
13 | - `VendingMachine.java`: Simulates the display and input options (keypad) of the Vending Machine. It initializes the machine and handles user and admin operations.
14 | - `UserOperations.java`: Implements the methods available to users. It displays the available items, handles user input, and performs the transaction.
15 | - `AdminOperations.java`: Implements the methods available to administrators. It handles admin authentication and provides functionality to manage the inventory.
16 |
17 |
18 | - `org.anuva04.Models`: Contains the `Item` and `Tray` classes.
19 | - `Item.java`: Defines the `Item` class, representing a physical item that can be bought by a user.
20 | - `Tray.java`: Defines the `Tray` class, representing a tray in each slot of the Vending Machine. It contains items of the same type and manages item addition, removal, and retrieval.
21 |
22 |
23 | - `org.anuva04.Constants`: Contains the `Constants` class that provides environment variables and secrets.
24 | - `Constants.java`: Provides environment variables and secrets, such as an emergency message and an admin password.
25 |
26 | ## Usage
27 |
28 | To use the Vending Machine, follow these steps:
29 |
30 | 1. Ensure you have **JDK 11** and **Maven** installed on your system.
31 | 2. Clone the project repository and navigate to the project's root directory.
32 | 3. Build the project using the command: `mvn clean install`.
33 | 4. Run the program using the command: `mvn exec:java -Dexec.mainClass="org.anuva04.Main"`.
34 | 5. The program will display a home screen with two options: "1: User" and "2: Admin".
35 | 6. Proceed with the desired option as explained in the previous version of the README.
--------------------------------------------------------------------------------
/LLD/VendingMachine/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.anuva04
8 | VendingMachine
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 11
13 | 11
14 | UTF-8
15 |
16 |
17 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Constants.java:
--------------------------------------------------------------------------------
1 | package org.anuva04;
2 |
3 | // Environment variables and secrets
4 | public class Constants {
5 | public static String EmergencyMessage = "If you face any difficulty during the transaction, please contact us at: XXXXXXXXX";
6 | public static int AdminPass = 12345;
7 | }
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Controllers/AdminOperations.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Constants;
4 | import org.anuva04.Models.Item;
5 |
6 | import java.util.Scanner;
7 |
8 | // Collection of methods available to admins
9 | public class AdminOperations {
10 | private VendingMachine vm;
11 |
12 | public AdminOperations(VendingMachine vm) {
13 | this.vm = vm;
14 | }
15 |
16 | public void init() {
17 | System.out.println("Enter card in slot");
18 | // Card entered by admin
19 | System.out.println("Enter PIN");
20 | Scanner sc = new Scanner(System.in);
21 | int pin = sc.nextInt();
22 | if(pin != Constants.AdminPass) {
23 | System.out.println("Invalid PIN!");
24 | return;
25 | }
26 | // Provide access
27 | handleAdminOperation();
28 | }
29 |
30 | private void handleAdminOperation() {
31 | Scanner sc = new Scanner(System.in);
32 | while(true) {
33 | System.out.println("Enter slot number or 0 to exit");
34 | int slot = sc.nextInt();
35 | if(slot == 0) {
36 | break;
37 | } else if(slot > vm.inventory.size() || slot < 0){
38 | System.out.println("Invalid slot number!");
39 | break;
40 | }
41 | vm.inventory.get(slot).removeAllItems();
42 |
43 | System.out.println("Enter item name: ");
44 | String itemName = sc.next();
45 | System.out.println("Enter item price: ");
46 | int itemPrice = sc.nextInt();
47 | System.out.println("Enter item quantity: ");
48 | int itemQuantity = sc.nextInt();
49 |
50 | vm.inventory.get(slot).setPrice(itemPrice);
51 |
52 | for(int i = 1; i <= itemQuantity; i++) {
53 | boolean status = vm.inventory.get(slot).addItem(new Item(itemName, itemPrice));
54 | if(!status) {
55 | System.out.println("Maximum capacity reached.");
56 | break;
57 | }
58 | }
59 |
60 | System.out.println("Items added to slot " + slot + " successfully!");
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Controllers/UserOperations.java:
--------------------------------------------------------------------------------
1 | // TODO: user can cancel transaction anytime before item is dispensed
2 |
3 | package org.anuva04.Controllers;
4 |
5 | import java.util.Scanner;
6 |
7 | import org.anuva04.Constants;
8 |
9 | // Collection of methods available to users
10 | public class UserOperations {
11 | VendingMachine vm;
12 |
13 | public UserOperations(VendingMachine vm) {
14 | this.vm = vm;
15 | }
16 | public void init(){
17 | System.out.println("Displaying all items");
18 | for(int slot = 1; slot <= vm.numSlots; slot++){
19 | if(vm.inventory.get(slot).peekItem() == null) continue;
20 | System.out.println("Slot: " + slot +
21 | " | price: " + vm.inventory.get(slot).getPrice() +
22 | " | item: " + vm.inventory.get(slot).peekItem().name +
23 | " | quantity: " + vm.inventory.get(slot).getItemsQuantity()
24 | );
25 | }
26 | System.out.println("Enter slot number or 0 for exit ");
27 | Scanner sc = new Scanner(System.in);
28 | int input = sc.nextInt();
29 | if(input == 0){
30 | System.out.println("Thank you for visiting!");
31 | } else if(input >= 1 && input <= vm.numSlots) {
32 | handleTransaction(input);
33 | } else {
34 | System.out.println("Invalid option!");
35 | }
36 | }
37 |
38 | private void handleTransaction(int slot) {
39 | if(vm.inventory.get(slot).peekItem() == null) {
40 | System.out.println("Slot is empty!");
41 | return;
42 | }
43 |
44 | if(!handleMoneyTransaction(slot)) return;
45 |
46 | // Dispense item
47 | System.out.println("Please collect item: " + vm.inventory.get(slot).dispenseItem().name);
48 | System.out.println(Constants.EmergencyMessage);
49 | }
50 |
51 | private boolean handleMoneyTransaction(int slot) {
52 | System.out.println("Please enter amount: " + vm.inventory.get(slot).getPrice());
53 |
54 | // User can pay via cash or card
55 | Scanner sc = new Scanner(System.in);
56 | int amount = sc.nextInt();
57 | if(amount == vm.inventory.get(slot).getPrice()) {
58 | return true;
59 | } else if (amount < vm.inventory.get(slot).getPrice()) {
60 | System.out.println("Amount entered is less than price of product.");
61 | return false;
62 | } else {
63 | // library methods to handle CashDispenserStrategy
64 | // similar to ATM system
65 | System.out.println("Please collect change: " + (amount - vm.inventory.get(slot).getPrice()));
66 | return true;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Controllers/VendingMachine.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Controllers;
2 |
3 | import org.anuva04.Models.Tray;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Scanner;
8 |
9 | // Simulates display and input options (keypad) of Vending Machine
10 | public class VendingMachine {
11 | int numSlots;
12 | Map inventory;
13 |
14 | public VendingMachine(int numSlots, int traySize) {
15 | this.numSlots = numSlots;
16 | inventory = new HashMap<>();
17 | for(int slot = 1; slot <= numSlots; slot++) {
18 | inventory.put(slot, new Tray(0, traySize));
19 | }
20 | }
21 |
22 | // Simulates home-screen of Vending Machine display
23 | public void init() {
24 | while(true) {
25 | System.out.println("Press 1: User, 2: Admin ");
26 | Scanner sc = new Scanner(System.in);
27 | int input = sc.nextInt();
28 | switch (input) {
29 | case 1:
30 | UserOperations userOperations = new UserOperations(this);
31 | userOperations.init();
32 | break;
33 | case 2:
34 | AdminOperations adminOperations = new AdminOperations(this);
35 | adminOperations.init();
36 | break;
37 | default:
38 | System.out.println("Invalid option!");
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Main.java:
--------------------------------------------------------------------------------
1 | package org.anuva04;
2 |
3 | import org.anuva04.Controllers.VendingMachine;
4 |
5 | public class Main {
6 | // Method to simulate a physical Vending Machine up and running
7 | public static void main(String[] args) {
8 | VendingMachine vm = new VendingMachine(9, 10);
9 | vm.init();
10 | }
11 | }
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Models/Item.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | // A physical item that can be bought by an user
4 | public class Item {
5 | public String name;
6 | public int price;
7 |
8 | public Item(String name, int price) {
9 | this.name = name;
10 | this.price = price;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/java/org/anuva04/Models/Tray.java:
--------------------------------------------------------------------------------
1 | package org.anuva04.Models;
2 |
3 | import java.util.Queue;
4 | import java.util.LinkedList;
5 |
6 | // A tray in each slot of Vending Machine which usually contains items of same type
7 | public class Tray {
8 | private int price;
9 | private Queue- items;
10 |
11 | private int traySize;
12 |
13 | public Tray(int price, int traySize) {
14 | this.price = price;
15 | this.items = new LinkedList<>();
16 | this.traySize = traySize;
17 | }
18 |
19 | public void setPrice(int price) {
20 | this.price = price;
21 | }
22 |
23 | public int getPrice() {
24 | return price;
25 | }
26 |
27 | public boolean addItem(Item item) {
28 | if(items.size() >= traySize) {
29 | return false;
30 | }
31 | this.items.add(item);
32 | return true;
33 | }
34 |
35 | public Item peekItem() {
36 | return this.items.peek();
37 | }
38 |
39 | public Item dispenseItem(){
40 | return this.items.poll();
41 | }
42 |
43 | public void removeAllItems() {
44 | this.items.clear();
45 | }
46 |
47 | public int getTraySize() {
48 | return traySize;
49 | }
50 |
51 | public int getItemsQuantity () {
52 | return this.items.size();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/LLD/VendingMachine/src/main/resources/Requirements.txt:
--------------------------------------------------------------------------------
1 | Functional Requirements:
2 | 1. Vending machine (VM) displays available items, their codes and prices.
3 | 2. User can choose to pay with cash or card (debit or credit card).
4 | 2.a. If paying with cash, VM will return change (if any) if available.
5 | 2.b. If change not available, VM will return entire amount and not dispense any item.
6 | 3. Emergency contact number is available to reach out to in case of hardware failures.
7 | 4. User has the option to cancel transaction at any point before item is dispensed.
8 | 5. Admin should be able to insert/remove items from VM.
9 | 5.a. To do so, admin can insert card and enter PIN to get access to VM.
10 | 5.b. Once items are modified, VM updates its metadata automatically.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Table of contents:
2 | - [HLD](https://github.com/anuva04/SystemDesign/tree/main/HLD)
3 | - [Rate Limiter](https://github.com/anuva04/SystemDesign/blob/main/HLD/RateLimiter/RateLimiter.md)
4 | - [URL Shortener](https://github.com/anuva04/SystemDesign/blob/main/HLD/URLShortener/URLShortener.md)
5 | - [E-commerce Store](https://github.com/anuva04/SystemDesign/blob/main/HLD/ECommerceStore/ECommerceStore.md)
6 | - [Twitter](https://github.com/anuva04/SystemDesign/blob/main/HLD/Twitter/Twitter.md)
7 | - [Chat System](https://github.com/anuva04/SystemDesign/blob/main/HLD/ChatApp/ChatApp.md)
8 | - [Video Sharing Platform](https://github.com/anuva04/SystemDesign/blob/main/HLD/Youtube/Youtube.md)
9 | - [Cab Aggregator](https://github.com/anuva04/SystemDesign/blob/main/HLD/Uber/Uber.md)
10 | - [Collaborative Editing System](https://github.com/anuva04/SystemDesign/blob/main/HLD/GoogleDocs/GoogleDocs.md)
11 | - [WebHook System](https://github.com/anuva04/SystemDesign/blob/main/HLD/WebHook/WebHook.md)
12 | - [LLD](https://github.com/anuva04/SystemDesign/tree/main/LLD)
13 | - [ATM](https://github.com/anuva04/SystemDesign/tree/main/LLD/ATM)
14 | - [Elevator System](https://github.com/anuva04/SystemDesign/tree/main/LLD/ElevatorSystem)
15 | - [Vending Machine](https://github.com/anuva04/SystemDesign/tree/main/LLD/VendingMachine)
16 | - [Meeting Scheduler](https://github.com/anuva04/SystemDesign/tree/main/LLD/MeetingScheduler)
17 | - [Design Patterns](https://github.com/anuva04/SystemDesign/tree/main/DesignPatterns)
18 | - [Creational Patterns](https://github.com/anuva04/SystemDesign/tree/main/DesignPatterns/CreationalPatterns)
19 | - [Factory](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/CreationalPatterns/FactoryPattern.java)
20 | - [Abstract Factory](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/CreationalPatterns/AbstractFactoryPattern.java)
21 | - [Builder](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/CreationalPatterns/BuilderPattern.java)
22 | - [Singleton](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/CreationalPatterns/SingletonPattern.java)
23 | - [Prototype](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/CreationalPatterns/PrototypePattern.java)
24 | - [Structural Patterns](https://github.com/anuva04/SystemDesign/tree/main/DesignPatterns/StructuralPatterns)
25 | - [Adapter](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/AdapterPattern.java)
26 | - [Bridge](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/BridgePattern.java)
27 | - [Composite](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/CompositePattern.java)
28 | - [Decorator](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/DecoratorPattern.java)
29 | - [Facade](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/FacadePattern.java)
30 | - [Flyweight](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/FlyweightPattern.java)
31 | - [Proxy](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/StructuralPatterns/ProxyPattern.java)
32 | - [Behavioral Patterns](https://github.com/anuva04/SystemDesign/tree/main/DesignPatterns/BehavioralPatterns)
33 | - [Chain of Responsibility](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/ChainOfResponsibilityPattern.java)
34 | - [Command](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/CommandPattern.java)
35 | - [Iterator](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/IteratorPattern.java)
36 | - [Mediator](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/MediatorPattern.java)
37 | - [Memento](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/MementoPattern.java)
38 | - [Observer](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/ObserverPattern.java)
39 | - [Template](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/TemplatePattern.java)
40 | - [State](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/StatePattern.java)
41 | - [Strategy](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/StrategyPattern.java)
42 | - [Visitor](https://github.com/anuva04/SystemDesign/blob/main/DesignPatterns/BehavioralPatterns/VisitorPattern.java)
--------------------------------------------------------------------------------