System Design LAC
website·Indexed 29 days ago
https://system-design-lac.vercel.appA comprehensive guide to software design principles and patterns, featuring detailed explanations and examples of SOLID principles, creational, structural, and behavioral design patterns implemented in Java and TypeScript.
What's inside System Design LAC
- Creational design patterns focus on object creation mechanisms, providing ways to instantiate objects while decoupling the client code from the specific classes being created. This increases flexibility and reusability in software development. Common creational patterns include: Singleton, Factory Method, Abstract Factory Method, Builder, Prototype, and Object Pool.
Overview of Creational Design Patterns
Creational design patterns provide mechanisms to create objects in a manner suitable for a given situation. Their primary goal is to decouple client code from the specific classes or objects being instantiated, thereby increasing flexibility and reusability in software development. Common creational patterns include:
- Singleton Pattern
- Factory Method Pattern
- Abstract Factory Method
- Builder Pattern
- Prototype Pattern
- Object Pool
Compare Template Method pattern vs Polymorphism
While both involve inheritance, the Template Method pattern is a higher-level design structure specifically for organizing algorithms, whereas polymorphism is a fundamental OOP concept for object behavior.Category Template Method Polymorphism Purpose Defines algorithm structure; subclasses provide specific step implementations. Treats different classes as a common superclass/interface for different behavior. Design Level High-level design pattern for organizing algorithms. Fundamental OOP concept focusing on object behavior. Abstraction Higher level Lower level Implementation Abstract or virtual methods Inheritance or interfaces Understand Liskov's Substitution Principle (LSP)
Liskov's Substitution Principle (LSP) states that objects of a superclass should be substitutable with objects of its subclasses without affecting the correctness of the program. If a program is designed to work with a certain type, it should also work correctly with any subtype of that type. Formally: if a property q(x) is provable about objects x of type T, then q(y) should be provable for objects y of type S, where S is a subtype of T.Implement the State behavioral design pattern
The State pattern allows an object to alter its behavior when its internal state changes, making it appear as if the object changed its class. This is particularly useful when an object's behavior depends on its internal state and needs to change dynamically at runtime without using complex conditional statements.
Key components of the pattern:
- Context: The object whose behavior changes. It maintains a reference to the current state and delegates behavior to it.
- State: An interface or abstract class defining common methods for all concrete states.
- Concrete State: Specific implementations of the State interface, each providing behavior unique to that state.
Implement the Observer design pattern
The Observer pattern is a behavioral design pattern used to define a subscription mechanism to notify multiple objects (observers) about events happening to the object they are observing (the subject). It establishes a one-to-many dependency so that when the subject's state changes, all registered dependents are notified and updated automatically. This is also known as the Publisher-Subscriber model.
Key characteristics:
- Subscribers can be added or removed in real-time.
- Subscribers do not need to be of the same type.
- Common use cases include event listeners in GUI frameworks, reactive programming, and notification systems (e.g., social media followers or YouTube subscriptions).
Implement the Command behavioral design pattern
The Command pattern is a behavioral design pattern that encapsulates a request as a stand-alone object. This decoupling allows for parameterizing clients with different requests, queuing or logging requests, and supporting undoable operations. It is particularly useful in multithreaded environments.
Key Components
- Command: An interface that defines the method for executing an operation (e.g.,
executeCommand()). - Concrete Command: Implements the Command interface; it binds the receiver object to the action to be performed.
- Receiver: The object that contains the actual business logic to perform the work.
- Invoker: The object that triggers the command. It does not need to know the internal logic of the receiver, only how to call the command's execution method.
- Client: The object that creates the Concrete Command and associates it with a Receiver, then passes the command to the Invoker.
- Command: An interface that defines the method for executing an operation (e.g.,
Implement the Mediator Pattern to reduce object dependencies
The Mediator pattern is a behavioral design pattern used to reduce chaotic dependencies between objects by restricting direct communication. Instead of objects referring to each other explicitly, they collaborate only via a mediator object, promoting loose coupling and allowing interaction logic to vary independently.
Key Components
- Mediator: An interface that defines how participating objects (Colleagues) communicate.
- ConcreteMediator: Implements the Mediator interface and coordinates communication among Colleague objects, maintaining a list of registered participants.
- Colleague: An abstract class or interface for communication with other colleagues.
- Concrete Colleague: Specific implementations that send and receive messages via the Mediator. They are typically unaware of other concrete colleagues.
Implement the Factory Method Pattern
The Factory Method pattern delegates the creation of objects to subclasses. It is used when objects share a common characteristic or hierarchy (e.g., different types of HTML elements) and you want to avoid using thenewoperator manually. Instead, a factory method (typically calledcreate) abstracts the instantiation logic and returns an object conforming to a common interface.Implement 'Has-a' relationships via Composition
Composition is a strong 'has-a' relationship where a parent class is composed of one or more objects of another class. The lifetime of the composed objects is tightly coupled to the parent; if the parent object is destroyed, the composed objects are also destroyed. Composed objects cannot exist independently.public class Car { private Engine engine; public Car() { // The Engine is created inside the Car, coupling their lifecycles engine = new Engine(); } }Implement the Prototype Pattern in TypeScript
The Prototype Pattern is used to create new objects by copying an existing prototypical instance. This avoids the overhead of manual object creation and property assignment, especially when objects need to be cloned at runtime or when the
newoperator is too expensive.Key implementation steps:
- Define a
Prototypeinterface that declares aclone()method. - Implement this interface in concrete classes (e.g., game characters like Soldiers).
- Use the
clone()method to produce identical copies of an object, then modify specific properties as needed.
interface Prototype { clone(): Prototype; } class Soldier implements Prototype { constructor(public weapon: string, public rank: string) {} clone(): Prototype { return new Soldier(this.weapon, this.rank); } } // Usage const basicSoldier = new Soldier('Rifle', 'Private'); const clonedSoldier = basicSoldier.clone() as Soldier; clonedSoldier.rank = 'Sergeant'; // Modify properties after cloning- Define a
Implement the Composite Design Pattern in Java
The Composite pattern is a structural design pattern used to compose objects into tree structures to represent part-whole hierarchies. It allows clients to treat individual objects (leaves) and compositions of objects (composites) uniformly through a common interface.
Key Components:
- Component: An interface or abstract class defining common methods for all objects in the composition (e.g.,
FileSystemComponent). - Leaf: An individual object that implements the Component interface and represents the 'part' (e.g.,
File). - Composite: A container that holds other components (both leaves and other composites) and implements the Component interface, representing the 'whole' (e.g.,
Directory).
// Component: Common interface for both leaf and composite objects interface FileSystemComponent { void showDetails(); } // Leaf: Represents individual objects class File implements FileSystemComponent { private String name; public File(String name) { this.name = name; } public void showDetails() { System.out.println("File: " + name); } } // Composite: Represents containers that can hold other components class Directory implements FileSystemComponent { private String name; private List<FileSystemComponent> components; public Directory(String name) { this.name = name; components = new ArrayList<>(); } public void addComponent(FileSystemComponent component) { components.add(component); } public void removeComponent(FileSystemComponent component) { components.remove(component); } public void showDetails() { System.out.println("Directory: " + name); for (FileSystemComponent component : components) { component.showDetails(); } } } // Usage public class CompositeExample { public static void main(String[] args) { FileSystemComponent file1 = new File("document.txt"); FileSystemComponent file2 = new File("image.jpg"); FileSystemComponent subdirectory = new Directory("documents"); FileSystemComponent directory = new Directory("root"); ((Directory) subdirectory).addComponent(file1); ((Directory) directory).addComponent(file2); ((Directory) directory).addComponent(subdirectory); directory.showDetails(); } }- Component: An interface or abstract class defining common methods for all objects in the composition (e.g.,