Repo Link: https://codeberg.org/amadeus404/lld-patterns

Basics

  • Abstraction
  • Encapsulation
  • Polymorphism
  • Inheritance

Composition

In object-oriented programming, composition is a design principle where a larger, more complex object is built by combining smaller, simpler objects.

Instead of a class inheriting behavior from a parent class (the “is-a” relationship), an object takes ownership of other objects to get its behavior (the “has-a” relationship).

Strategy Pattern

Identify the aspects of your application that vary and separate them from what stays the same

  • Take the parts that vary and encapsulate them so that later I can extend the parts that vary without affecting those that don’t. Program to an interface, not an implementation
  • Create an interface for the behavior that keeps changing implement the various behaviors using that interface.
  • The actual class that needs those things is just using that interface and is not worried about the actual implementation, it will pull whatever is necessary.
  • Programming to an interface just means programming to a supertype I don’t actually have to use the interface Favor composition over inheritance
  • Instead of inheriting their behavior, the classes get their behavior by being composed with the right behavior object

Strategy Pattern - Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it

Observer Pattern

Observer Pattern - Defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically

TODO - Read about Publish-Subscribe Pattern and how it is different from observer pattern

Strive for loosely coupled designs between objects that interact

TODO - Implement something using the Observer pattern in the Java Swing Library TODO - What is Java Beans? What is it used for?

Push vs Pull Model

Push Model

Subject sends data to observers via update(data). Benefits:

  • Observers don’t need a reference to the subject
  • Decoupled — observer only depends on the data object/type
  • Simpler observer interface

Downsides:

  • Subject decides what data is important (might send too much or too little)
  • All observers get everything, even if they only need a subset
  • If data changes shape, every observer’s update() signature breaks

Pull Model

Subject just says “I changed!” and observers call getters to fetch what they need. Benefits:

  • Each observer pulls only what it needs — efficient for selective consumers
  • Subject doesn’t need to anticipate what observers want
  • Adding new fields to subject doesn’t break observers

Downsides:

  • Observer needs a reference to the concrete subject (coupling)
  • More complex observer interface (or stored subject reference)
  • Observer needs to know what to ask for and when

Which one to use?

  • Push when all observers need essentially the same data and data shape is stable
  • Pull when observers need different slices of data, or the subject’s state is complex and evolving

Decorator Pattern

Open Close Principle: Classes should be open for extension, but closed for modification

The decorator adds its own behavior before and/or after delegating to the object it decorates to do the rest of the job.

*Decorator Pattern - Attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

TODO - Do something with the Java IO Library

Decision - Strategy vs Observer vs Decorator