
Explore how design patterns illuminate large code bases by showing context-driven use cases, advantages, and trade-offs, with a six-video progression from basics to real-world implementations in TypeScript.
Maximize learning in this TypeScript design patterns and SOLID principles course by completing all six videos per pattern, using pause screens for hands-on practice, quizzes, and Q&A to deepen understanding.
Access all course resources via the GitHub repository's main branch. The Readme serves as the single source of truth, linking lecture notes and code branches.
Explore design patterns as reusable solutions to common software design problems in TypeScript, and trace their architectural history from Christopher Alexander to the Gang of Four.
Explore design patterns and SOLID principles to gain reusable, modular code, improve maintainability and communication, and learn ready-made solutions for common problems.
Use design patterns with caution, not as one-size-fits-all solutions. Evaluate contextual differences, avoid overengineering, weigh performance trade-offs, and consider evolving requirements before applying a pattern.
Identify three broad design pattern categories—creational, structural, and behavioral—and explore how each solves object creation, structure, or communication challenges, with examples like singleton, adapter, and chain of responsibility.
Learn to read UML class diagrams with confidence, interpreting properties, methods, and access modifiers while exploring examples of classes, interfaces, abstract classes, and the decorator pattern.
Set up a TypeScript development environment with parcel for zero-boilerplate compilation to JavaScript. Initialize npm, create a minimal VS Code project, and enable parcel watch to auto compile TypeScript.
Explore object oriented programming in TypeScript by examining core concepts such as abstraction, encapsulation, polymorphism, and inheritance, and their role in Gang of Four design patterns.
Explain object oriented programming lingo by clarifying the user of the class (the developer) and showing interfaces as contracts that let dog and cat classes interact.
Explore abstraction in TypeScript by hiding implementation details and exposing an essential interface for shapes, enabling a single calculate total area function to compute areas of circles and rectangles.
Demonstrate abstraction in practice by using the JavaScript date class to obtain current year, month, and date. Learn how the date object's simple API hides complex logic behind the scenes.
Explore how type provides an abstraction layer that converts objects into sql queries and hides database specifics behind an api, while the application layer defines user entities for crud operations.
Explore how abstraction hides complex details behind a simple API and improves maintainability when area calculations change. Exposing a single function like calculate total area boosts reusability, modularity, and security.
Explore encapsulation as the core principle that enables separation of concerns and data hiding, managing a bank account's private balance via deposit and withdraw methods.
Explore how encapsulation hides private data in the JavaScript date object while exposing only needed methods. Understand how abstraction and encapsulation relate to Unix epoch time and date calculations.
Explore how encapsulation hides data and controls data integrity in programs, illustrated by a bank account example where balance is private and only deposits or withdrawals can modify it.
Explore subtype polymorphism in TypeScript, treating circle and rectangle as shapes through a common shape interface to compute area and perimeter.
Explore polymorphism in Express.js through middleware that share a single interface of request, response, and next. See how interchangeable middleware offers flexibility and advantages in real-world apps.
Explore how polymorphism enables code reusability and interface consistency with a shape interface for circle and rectangle, enabling area and perimeter functions, and boosting flexibility, scalability, robustness, and collaboration.
Learn how inheritance lets a child class reuse a parent’s properties and methods, shown via an animal base class and a dog subclass with a shared move method.
Explore a real world inheritance pattern in a TypeScript e-commerce example, where a product base class is extended by book and electronics with overridden display methods.
Explore inheritance advantages in object oriented programming, including overriding methods and enabling abstraction, polymorphism, and encapsulation, to boost code reusability and prepare for Gang of Four design patterns.
Explore solid design principles, their relation to gang of four patterns, and review the five principles—single responsive ability, open closed, liskov substitution, interface segregation, and dependency inversion—with TypeScript examples.
Explore how the single responsibility principle assigns one reason to change. See a TypeScript example where the user class handles name and email, while authentication is in a separate class.
Refactor a blog post class to separate display logic into a dedicated blog post display class, demonstrating the real world application of the single responsibility principle and maintainability.
Explore the advantages of the single responsibility principle, including easier maintenance, improved understandability, easier testing, reduced coupling, and reusable blog post and blog post display class implementations.
explains the open-closed principle, showing how to extend behavior without modifying existing code using inheritance, illustrated with a discount system for online shopping.
Demonstrate the open closed principle with a discount system using a customer interface and regular and premium classes that implement a give discount method.
Explore the advantages of the open closed principle, including reduced bugs, increased code usability, and easier versioning, by extending new customer types like gold without modifying existing code.
This lecture explains the Liskov substitution principle, showing how subtypes replace a parent without changing desirable properties, using an abstract shape with rectangle and square to calculate areas in TypeScript.
Explore a Liskov substitution scenario with a payment processor hierarchy. Derive credit card, debit card, and PayPal processors from an abstract processor and share a generic execute payment function.
Discover how the Liskov substitution principle boosts code reusability, flexibility, and modularity. Extend the payment processor class to add new processors, like Bitcoin, without changing existing code.
Apply the interface segregation principle to split a monolithic interface into separate printer, scanner, and fax interfaces, preventing clients from depending on unused methods.
Explore a real world blogging platform example to apply the interface segregation principle, separating admin and regular user capabilities into post creation, commenting, and sharing through dedicated interfaces.
Explore the advantages of the interface segregation principle, including avoiding unnecessary methods in interfaces, improved maintainability, reduced change impact, stronger encapsulation, and easier testing.
Explore the dependency inversion principle, where high level modules depend on abstractions, not on low level details, and see refactoring ideas using interfaces to decouple the database.
Learn the dependency inversion principle by implementing a database interface with a save method, so a high level module uses abstractions to save to MySQL or MongoDB.
Apply the dependency inversion principle to decouple high level modules from database implementations by relying on a database interface, enabling interchangeable MongoDB or MySQL backends.
Master creational design patterns from the gang of four, focusing on object creation to control complexity. Explore singleton, factory, abstract factory, builder, and prototype patterns and their applications.
Explore the singleton design pattern, a creational pattern that ensures a class has one instance and provides a global access point through a private constructor and a get instance method.
Identify code smells that indicate using the singleton pattern, such as global variables and shared resources, and learn to centralize a single instance for database connections and data passing.
Explore a real world singleton implementation with a logger class. Implement a private constructor, a static get instance method, and a log method that prints timestamped messages to the console.
Enforce a single instance to write to the file and prevent concurrent access, improving performance, thread safety, and consistency by sharing one file connection and centralizing configuration.
Explore the caveats of the singleton pattern, including global state, tight coupling, testing difficulties, and restricted subclassing, and how to balance it with structural and behavioral patterns.
Explore where to apply the singleton pattern, including caching, service proxies or proxy servers, shared resources, configuration data, logger files, and database connections to ensure a single instance across modules.
Explore the prototype design pattern, a creational pattern that enables cloning objects from existing instances. Implement a concrete prototype with a prototype interface, clone method, and get user details.
Use the prototype pattern when creating a new object is costlier than cloning an existing one, especially for complex objects with many properties and large state managed by Redux.
Explore a real world prototype pattern implementation in TypeScript using an abstract shape class and a shape properties interface to clone rectangles and circles.
Explore the prototype pattern's advantages in TypeScript, including avoiding reference errors by creating deep clones of large or nested objects, and simplifying object creation with a simple clone method.
Explore the caveats of the prototype pattern, including shallow vs deep copying in JavaScript and TypeScript, and the complexity of clone methods for nested objects using JSON.stringify.
Explore prototype pattern use cases across graphics, games, distributed systems, data pipelines, and UI state cloning. Clone existing data or objects with deep copies to create new, modified instances.
Learn how the builder pattern orchestrates building complex objects step by step with a builder, a director, and concrete builders, culminating in a product in TypeScript.
Identify when to use the builder pattern by recognizing design smells like complex, multi-part objects and step-by-step creation, including combination explosion and immutable objects.
Explore a real-world TypeScript implementation of the builder pattern by constructing a customer onboarding object for a financial institution, assembling personal details, contact info, and preferences step by step.
Explore the builder pattern's advantages, including a fluent interface, separation of construction and business logic, and multiple representations, enabling immutable, well structured objects built by a director with minimal parameters.
Examine the builder pattern's caveats, including increased complexity, extra code, potential runtime errors, mutability concerns, refactoring and performance costs, and the need for clear documentation.
Explore how the builder pattern applies to meal ordering, construction, and gaming, using meal builders and a director to assemble burgers, drinks, desserts, or houses and characters.
Explore the factory pattern, a creational design pattern, by building a car factory that creates sedan, SUV, and hatchback objects from a shared abstract car class.
Identify when to use the factory pattern to create many similar classes from one superclass. Offer a plug-and-play create method for sedan, SUV, or hatchback and hide construction complexity.
Explore a real-world factory pattern implementation for payment processing, creating PayPal, Stripe, and bank transfer processors from a single factory, each handling payments via a shared abstract processor.
The factory design pattern decouples client code from concrete implementations, enabling flexible addition of new processors like Google Pay while encapsulating object creation.
Explore the factory design pattern's caveats, including general drawbacks like increased complexity and refactoring challenges, and examine the hidden types problem from decoupling.
Explore factory pattern use cases across real-world scenarios, abstracting database connections for MySQL, Postgres, and MongoDB, UI widgets, and logging to console, files, or remote servers.
Explore the abstract factory pattern, a creational design pattern that provides interfaces for creating families of related and dependent objects. See how the factory creates product a and product b.
Use the abstract factory pattern to create interdependent objects that belong to a family and enable switching between families, such as residential vs commercial or Mac OS vs Windows OS.
Explore a real-world implementation of the abstract factory pattern for cross-platform ui, building Windows and Mac OS buttons and checkboxes via gui factories, enabling platform-specific rendering with shared functionality.
The abstract factory pattern ensures consistency among products by creating components from the same family, like buttons and checkboxes across Windows and Mac OS factories.
Explore five caveats of the abstract factory pattern, including increased complexity, limited flexibility for adding new product types, maintenance challenges, and tight coupling with the client code.
Explore abstract factory pattern use cases, from platform-specific ui components and cross-platform graphics and sound to database queries and connections, using Windows and Linux factories for MySQL and Postgres.
Explore structural design patterns that shape the composition and structure of classes and objects, enabling decoupling, flexibility, and maintainability, including adapter, bridge, composite, decorator, and facade patterns.
Explore the facade pattern, a structural design pattern that wraps a complex system in a single class, delegating to grinder, boiler, and brewer to make coffee.
Explore when the facade pattern solves rampant dependencies and overwhelming complexity by hiding inner workings and providing a simplified, layered interface for complex subsystems.
Discover how the facade pattern simplifies a complex home theater system by coordinating the amplifier, DVD player, projector, and lights with a single watch movie method.
Discover how the facade pattern delivers a simplified interface, decouples subsystems, and reduces dependencies by coordinating a home theater's components with a single watch movie method.
Explore the caveats of the facade design pattern, including overabstraction, limited flexibility, and hiding useful information, illustrated by home theater subsystems.
Explore use cases of the facade pattern, from an order facade coordinating inventory, payment, and shipping in e-commerce, to a gaming engine facade simplifying initialize, render, and update.
Discover the bridge design pattern, splitting abstraction and implementation to decouple client code, with a Windows and Mac OS media player example for audio and video.
Use the bridge pattern to hide implementation details and enable platform-specific behavior, switching runtime between audio and video players on Windows and Mac OS.
Decouple abstraction from implementation to change the database without affecting the interface, enabling addition of new implementations like MySQL while improving readability and enabling runtime binding between PostgreSQL and MongoDB.
Explore caveats and criticisms of the bridge pattern, a widely used design, noting overengineering risks and design difficulty when abstraction and implementation may change.
Explore bridge pattern use cases in graphics libraries, cross-platform apps, and databases. See how to decouple abstractions from implementations and decide rendering APIs such as OpenGL or DirectX at runtime.
Explore the composite design pattern by modeling a tree-like structure with components, leaves, and composites, enabling uniform treatment of individual objects and groups.
Apply the composite pattern to tree-like hierarchies of objects, such as managers and employees, and to perform uniform operations on both collections and individuals.
Demonstrates a real-world composite design pattern in a file system with folders and files, where each component exposes getName and getSize, and folders support add, remove, and getComponents.
Explore how the composite pattern simplifies client code and enables a tree-like structure with files, folders, and links. Add new component types without modifying existing classes.
Explore the four major caveats of the composite design pattern, including single responsibility principle violations, registering components, indirect coupling, and type checking, with code examples.
Explore how the composite pattern enables uniform treatment of leaf and composite GUI components within tree-like structures, enabling easier rendering and input handling.
Explore the decorator pattern, a structural and behavioral design that dynamically adds or overrides behavior in an object without changing its implementation. Learn via a coffee example with milk decorators.
Apply the decorator pattern to modify an instantiated object, such as a coffee, with customizations like milk or caramel. Decorators enable customer-specific variations without extending base classes.
Explore a real-world decorator pattern implementation that uses middleware to augment a base server request, with auth and logging decorators controlling access and behavior in a TypeScript-inspired setup.
Explore the decorator pattern as a flexible alternative to subclassing by composing middleware. It enables runtime addition or removal of functionality, promotes code reuse, and upholds the single responsibility principle.
Explore caveats of the decorator pattern, including dispersed functionality across many small objects, interface compatibility when adding new methods, and the critical importance of decorator ordering in real-world middleware.
Explore real-world use cases of the decorator pattern in GUI toolkits, Java i/o streams, and middleware, showing how to add features like scroll bars, menus, buffering, and validation without subclassing.
Explore the adapter pattern, which lets an existing class interface be used by another without modifying code, focusing on the object adapter approach in TypeScript with square and rectangle.
Use the adapter pattern to translate between incompatible interfaces, bridging two classes like square and rectangle, and to support legacy code, backward compatibility, and scenarios where TypeScript lacks multiple inheritance.
Demonstrates a real-world adapter pattern that lets PostgreSQL adapt to a MySQL interface, enabling seamless database switching without altering the rest of the application.
The adapter pattern boosts code reuse and flexibility by enabling existing code to work with new interfaces, with minimal changes. It also decouples components and enables interoperability across mismatched interfaces.
Explore caveats of the adapter pattern, including hiding the adapter’s extra capabilities, tight coupling with the underlying class, and potential confusion, with guidance for clear documentation.
Explore how the observer pattern lets a subject notify multiple observers of state changes through a subscription mechanism. See a TypeScript example with a concrete subject and concrete observers.
Observe a subject's state and react to its changes with the observer pattern. Spot design smells like polling and high coupling to decide its fit.
Implement the observer pattern in TypeScript by modeling a weather data subject that notifies observers—the current conditions display, statistics display, and forecast display—when temperature, humidity, or pressure change.
Learn how the observer pattern decouples subject and observers, enabling dynamic registration and removal, broadcast updates on state changes, and open ended systems for adding observers.
Explore the caveats of the observer pattern, such as unexpected updates, debugging difficulties, memory leaks from lingering observers, lack of update ordering, and over notification, with code examples.
Explore observer pattern use cases in graphical user interfaces, stock market dashboards, and social networks, illustrating how subjects notify observers like character counters, validators, trader dashboards, and investment algorithms.
Explore the iterator pattern, a behavioral design pattern, by implementing a generic array iterator in TypeScript that traverses a collection with next and hasNext methods, usable for numbers and strings.
Identify when to apply the iterator pattern to navigate complex objects sequentially, encapsulating traversal logic with iterator classes for arrays, trees, or mixed collections, without exposing structure.
Explore a real-world TypeScript iterator pattern using generic interfaces, including a collection interface with create iterator, a user collection and user iterator, and runtime iterator creation for any collection.
Discover how the iterator pattern simplifies client code with a common traversal interface, enables diverse and concurrent traversals, and hides internal collection details.
Assess the caveats of the iterator pattern, including increased complexity, modification during iteration of a collection, performance concerns, stateful iterators, and memory consumption, with TypeScript considerations.
Explore how the iterator pattern abstracts traversal for file systems, database results, rest API collections, and social media feeds with a uniform interface.
Master the strategy design pattern by organizing a family of interchangeable payment algorithms into separate classes, enabling runtime behavior changes in a shopping cart.
Identify when to apply the strategy pattern to replace multiple conditionals and prepare for future algorithm changes, encapsulating strategies like PayPal, credit card, and Bitcoin strategies.
Demonstrates real world use of the strategy pattern in image processing, with a filter strategy interface and grayscale, sepia, and negative strategies applied by an image processor.
The strategy pattern adheres to the open/closed principle, lets you switch strategies at runtime, and separates algorithms into dedicated classes to avoid complex conditionals and spaghetti code.
Examine the caveats of the strategy pattern, including inconsistent strategies, dependency management, and discoverability, and learn how to manage them in real code.
Explore strategy pattern use cases across sorting, compression, and image rendering, with concrete implementations like quicksort, mergesort, bubble sort, zip, tar, and rendering strategies for SVG, bitmap, and WebGL.
Teaches the template method pattern, a behavioral design pattern that defines an algorithm in a base class and lets subclasses customize steps, illustrated by baking a cake.
Explore when to use the template method pattern, where a master algorithm coordinates tasks and base algorithms inherit and modify, reducing duplicate code and handling optional parts in sequence.
Real-world template method pattern implementation for data parsing using json and xml. A base abstract data parser orchestrates load, validate, and use data, while json and xml parsers implement parse.
Explore the advantages of the template method pattern, including code reusability, interface segregation, dependency inversion, encapsulation, and extensibility through a shared abstract base with subclass-specific steps.
Explore the caveats of the template method pattern, including inheritance complexity, rigidity of algorithm steps, risk of breaking the algorithm, limited runtime flexibility, and potential overuse creating many small classes.
Explore real-world use cases of the template method pattern, including data parsing, back-end frameworks' request handling with pre, handle, post steps, and game enemy lifecycles with a common loop.
Explore the command design pattern, a behavioral design pattern that turns a request into a standalone object and enables delaying, queuing, and undoing commands with a light receiver.
Identify when to use the command pattern for complex commands, runtime decision making, deferred execution, undo/redo, and transactional behavior, illustrated by turn on/off commands and a remote control.
demonstrates a real-world command pattern implementation for file system operations by encapsulating create, read, update, and delete as commands with execute and undo, managed by an invoker and command queue.
Demonstrate clean decoupling between the invoker and commands in the command pattern, highlight extensibility and encapsulation of complex commands, and show undo/redo and deferring execution via a command queue.
Demonstrate how the command design pattern enables undo and redo in graphic editors and word processors, supports transactional database commands, and manages job queues.
Examine the state design pattern, a behavioral pattern that lets an object change its behavior with internal state, demonstrated by a light switch delegating to on and off state classes.
Apply the state design pattern to manage an object's on and off state, reducing conditional logic and highlighting transitions, state-specific behavior, and clean architecture.
Explore a real-world state design pattern implementation in a document editing app. Observe selection, brush, and eraser tools as distinct states on a canvas.
Explore how the state design pattern encapsulates state-specific behavior in separate classes, aligning with the single responsibility principle and the open closed principle, and enabling dynamic runtime state transitions.
Explore caveats of the state design pattern, including complexity overhead for simple transitions, maintainability and state consistency challenges, and potential runtime costs, with a practical tool implementation context.
Explore real-world uses of the state design pattern by modeling game character states, tcp connection states, and button states, with each state encapsulating behavior and enabling clean transitions.
Explore the chain of responsibility pattern, a behavioral design pattern that passes requests along a chain of handlers, with concrete monkey, squirrel, and dog handlers linked in code.
Explore when to apply the chain of responsibility pattern by examining runtime-determined handlers, code smells, and sequential processing across multiple objects.
Explore a real world chain of responsibility for e-commerce orders, linking validation, discount, payment, and shipping via an order class and abstract handler.
Discover the advantages of the chain of responsibility pattern: decoupling senders and receivers, runtime-configurable chains, easy addition or removal of handlers, and sequential processing of validation, discount, payment, and shipping.
Explore caveats of the chain of responsibility: improper handling, excessive responsibilities, and dependency on handler order, and learn to enforce the single responsibility principle and correct sequencing in client code.
Explore real-world chain of responsibility use cases across GUI event propagation, Express.js middleware, game input handling, and hierarchical logging with console, file, and database loggers.
Welcome to this one-of-a-kind course specifically designed to transform your TypeScript programming skills by diving deep into the world of Gang Of Four Design Patterns, SOLID Design principles, and Object-Oriented Programming (OOP) concepts. Are you an aspiring or intermediate programmer looking to level up your game? Or are you an advanced programmer and need a refresher on the Gang Of Four Design Patterns and SOLID Design Principles? Do you have a grasp of TypeScript and now want to focus on architectural excellence and code reusability? If so, you've come to the right place!
This course isn't just another tutorial; it's your passport to becoming an advanced TypeScript developer. Throughout more than 140 high-definition videos, totaling over 10 hours of content, we'll delve into the nuances of effective software design and programming. We go beyond theory by providing practical, hands-on coding exercises and quizzes that reinforce your learning and provide the skills you need for the real world. With this course, you don't just learn; you practice, implement, and master the art of writing clean, efficient, and robust TypeScript code using the SOLID Design Principles and Gang Of For Design Patterns using TypeScript.
Uniquely, this course covers all three key areas you need for excellence in modern software development:
Design Patterns: Master the Gang Of Four Design Patterns like Singleton, Builder, Strategy, and many more to solve specific problems efficiently.
SOLID Design Principles: Understand and implement the SOLID principles that serve as the foundation for writing maintainable and scalable code.
Object-Oriented Programming Concepts: Learn and apply the four pillars of OOP—Inheritance, Encapsulation, Polymorphism, and Abstraction—in TypeScript, enabling you to write code that is both functional and elegant.
Design Patterns You Will Learn In This Course:
Creational Design Patterns
Factory
Abstract Factory
Builder
Prototype
Singleton
Structural Design Patterns
Decorator
Adapter
Facade
Bridge
Composite
Behavioral Design Patterns
Command
Chain of Responsibility
Observer Pattern
Interpreter
Iterator
State
Strategy
Template
By the end of this course, you'll not only have a deep understanding of Software Design Patterns, SOLID principles, and OOP in TypeScript but also be equipped with the practical skills to apply these concepts in your future projects. Whether you are developing enterprise-level applications or working on freelance gigs, the skills you acquire here will make you stand out in the TypeScript development community.