# Classes, Objects & Data Containers

<figure><img src="/files/havRzwg8UkVhIFQDSXQs" alt="" width="375"><figcaption></figcaption></figure>

#### Objects vs Data Containers

This is one of the most important distinctions in clean code. Understanding when to use each will dramatically improve your code quality.

**Data Containers (Data Structures)**

**Purpose:** Hold data with no behavior

**Characteristics:**

* All properties are public
* No methods (or only getters/setters)
* Like a struct or record

**Example:**

<figure><img src="/files/oipw6F87paxfzb4aKLTR" alt="" width="375"><figcaption></figcaption></figure>

**When to Use:**

* Transferring data between systems
* Configuration objects
* API request/response payloads
* Database query results

**Objects (With Behavior)**

**Purpose:** Hide internal data and expose behavior through methods

**Characteristics:**

* Private properties
* Public methods (API)
* Encapsulation of logic

**Example:**

<figure><img src="/files/DlsSUrDzog1qQm3xR4bc" alt="" width="563"><figcaption></figcaption></figure>

**When to Use:**

* Business logic
* Domain models
* Services and utilities
* Anything that "does" something

**Why This Matters**

**❌ Bad Practice:**

<figure><img src="/files/WrAroIsLAd6Eu2WrOZ1g" alt="" width="563"><figcaption></figcaption></figure>

**✅ Good Practice:**

<figure><img src="/files/BoiqTyMKrqmaCxFmNPmW" alt="" width="563"><figcaption></figcaption></figure>

**Benefits:**

* If the object's internals change, your code doesn't break
* Code is more readable (method names explain intent)
* Easier to maintain and test

**When Data Containers Are Perfect**

<figure><img src="/files/0hpeK0JJkOSR8WZ1hbWX" alt="" width="563"><figcaption></figcaption></figure>

### Core Principles

#### Classes Should Be Small

Just like functions, classes should be small. But what does "small" mean?

**Small ≠ Few Lines of Code**

Size is measured by **responsibilities**, not lines.

**The Single Responsibility Test**

Ask yourself: "What is this class responsible for?"

**❌ Too Large:**

<figure><img src="/files/K5o0DOYPF4LzpsCnNkA5" alt="" width="563"><figcaption></figcaption></figure>

**Problem:** This class handles user authentication, profile management, shopping, AND payments. That's at least 4 responsibilities!

**✅ Better:**

<figure><img src="/files/ABf6vvpIbyxD4MpBGjeU" alt="" width="563"><figcaption></figcaption></figure>

**Benefits:**

* Each class is easier to understand
* Changes to payments don't affect user authentication
* Easier to test each part independently
* Team members can work on different classes without conflicts

#### High Cohesion

**Cohesion** measures how much the methods in a class use the class's properties.

**High Cohesion Example**

<figure><img src="/files/re5p02ge0yYA9LencQlJ" alt="" width="563"><figcaption></figcaption></figure>

**High cohesion**: Every method uses both properties. The class is focused.

**Low Cohesion Example**

<figure><img src="/files/l5TNjLHjaaUXR4dBn3QK" alt="" width="563"><figcaption></figcaption></figure>

**Low cohesion**: Each method uses different properties. This should be 3 separate classes!

**✅ Refactored:**

<figure><img src="/files/8hvf3l2ThI2ijgPwq21H" alt="" width="563"><figcaption></figcaption></figure>

#### The Law of Demeter

**Also known as:** The Principle of Least Knowledge

**The Rule:** Don't access the internals of an object through another object.

**What You Can Access**

A method can access:

1. **Its own class properties and methods**
2. **Objects stored in its properties**
3. **Objects passed as parameters**
4. **Objects it creates**

**The Problem: Chaining**

**❌ Violates Law of Demeter:**

<figure><img src="/files/TPg7pZ3YUQvgbYoFpYg4" alt="" width="563"><figcaption></figcaption></figure>

**Problems:**

* Long chains create fragile code
* Changes deep in the structure break everything
* Hard to read and understand
* Creates tight coupling

**✅ Better:**

<figure><img src="/files/icZaOfKQuEQJNGY3VqVG" alt="" width="563"><figcaption></figcaption></figure>

**Even Better: Tell, Don't Ask**

Instead of asking for data and then acting on it, tell the object what to do.

<figure><img src="/files/2VOEb83tOw1jtTsEtTT8" alt="" width="563"><figcaption></figcaption></figure>

**Important Exception**

The Law of Demeter doesn't apply to:

**Method chaining (fluent interfaces):**

<figure><img src="/files/32ZDWNqsKC3Sm0M9MmRl" alt="" width="563"><figcaption></figcaption></figure>

**Data containers:**

<figure><img src="/files/uaj9FVkJJANOp8DfALLE" alt="" width="563"><figcaption></figcaption></figure>

### Polymorphism

**Polymorphism** means "many forms." It allows you to use the same interface for different types.

#### The Problem It Solves

**❌ Without Polymorphism:**

<figure><img src="/files/jQuCMfRvXsvyaY4nrqLt" alt="" width="563"><figcaption></figcaption></figure>

**Problems:**

* Same `if` Checks are repeated in every method
* Adding a new delivery type requires changing multiple methods
* Easy to forget to update all places
* Violates Open-Closed Principle (more on this later)

#### The Solution: Polymorphism

**✅ With Polymorphism:**

<figure><img src="/files/gGiw2GnSFdta6EJXj5o0" alt="" width="563"><figcaption></figcaption></figure>

#### Using a Factory

The `if` Check only appears once now:

<figure><img src="/files/lPE2sELhvpd37ja9KFcc" alt="" width="563"><figcaption></figcaption></figure>

#### Benefits

1. **Easy to extend**: Add new delivery types without changing existing code
2. **No code duplication**: The `if` Logic exists in one place
3. **Type safety**: Each class handles its own logic
4. **Testable**: Test each delivery type independently

### SOLID Principles

SOLID is an acronym for five principles that help you write clean, maintainable classes.

#### Single Responsibility Principle (SRP)

**Rule:** A class should have only one reason to change.

**In Practice:** Each class should do one thing and do it well.

**Example: Violation**

**❌ Multiple Responsibilities:**

<figure><img src="/files/akIbzrbx7W2LAv5lTQk3" alt="" width="563"><figcaption></figcaption></figure>

**Problems:**

* Changes to report generation affect PDF creation
* Changes to the PDF format affect report logic
* Two different teams might need to modify the same class
* Hard to test each part independently

**Solution: Separate Responsibilities**

**✅ Single Responsibility:**

<figure><img src="/files/nhykrWcTautoxhy3xXHW" alt="" width="563"><figcaption></figcaption></figure>

**Benefits**

* **Easier to understand**: Each class has a clear purpose
* **Easier to test**: Test report generation separately from PDF creation
* **Easier to maintain**: Changes are isolated
* **Better team collaboration**: Different developers can work on different classes

#### Open-Closed Principle (OCP)

**Rule:** Classes should be open for extension but closed for modification.

**Translation:** You should be able to add new functionality without changing existing code.

**Example: Violation**

**❌ Requires Modification:**

<figure><img src="/files/n0b7Y67gy87TqJIjMhC9" alt="" width="563"><figcaption></figcaption></figure>

**Problems:**

* Every new document type requires modifying the Printer class
* Risk of breaking existing functionality
* Code duplication across similar methods

**Solution: Extension Through Inheritance**

**✅ Open for Extension:**

<figure><img src="/files/R9hxsbcl3z5ppDkYiFhL" alt="" width="563"><figcaption></figcaption></figure>

**Usage**

<figure><img src="/files/cSV5ESaIniMOArEW47oa" alt="" width="563"><figcaption></figcaption></figure>

#### Liskov Substitution Principle (LSP)

**Rule:** Objects should be replaceable with instances of their subtypes without breaking the program.

**Translation:** If class B extends class A, you should be able to use B anywhere you use A.

**Example: Violation**

**❌ Subtype Breaks Contract:**

<figure><img src="/files/F6fTelxldoXwuaTSxHz9" alt="" width="563"><figcaption></figcaption></figure>

**Problem:** Penguin violates the contract that all Birds can fly.

**Solution: Proper Hierarchy**

**✅ Correct Modeling:**

<figure><img src="/files/I644f7RocTRbdkDtNMvB" alt="" width="563"><figcaption></figcaption></figure>

**Real-World Example**

**❌ Violates LSP:**

<figure><img src="/files/fk6WL9GBjIOgTUfehleA" alt="" width="563"><figcaption></figcaption></figure>

**✅ Better Design:**

<figure><img src="/files/oPZwEox6KydsACxrqvBa" alt="" width="563"><figcaption></figcaption></figure>

#### Interface Segregation Principle (ISP)

**Rule:** Many small, specific interfaces are better than one large, general interface.

**Translation:** Don't force classes to implement methods they don't need.

**Example: Violation**

**❌ General Interface:**

<figure><img src="/files/qZYOJVjJFx0xw25pAocW" alt="" width="563"><figcaption></figcaption></figure>

**Problem:** InMemoryDatabase is forced to implement `connect()` even though it doesn't need it.

**Solution: Segregate Interfaces**

**✅ Specific Interfaces:**

<figure><img src="/files/EySk5TaNscycBnOvPLYQ" alt="" width="563"><figcaption></figcaption></figure>

**Real-World Example**

**❌ Fat Interface:**

<figure><img src="/files/3LvXPptcPsxm4Z7So57A" alt="" width="563"><figcaption></figcaption></figure>

**✅ Segregated Interfaces:**

<figure><img src="/files/GomOo7V9wTOhaPnaobjy" alt="" width="563"><figcaption></figcaption></figure>

#### Dependency Inversion Principle (DIP)

**Rule:** Depend on abstractions, not on concrete implementations.

**Translation:** High-level modules shouldn't depend on low-level modules. Both should depend on abstractions.

**Example: Violation**

**❌ Depends on Concretions:**

<figure><img src="/files/B8ZnGdl59NNhPMF6s4sh" alt="" width="563"><figcaption></figcaption></figure>

**Problems:**

* App knows too much about database types
* Hard to add new database types
* The app must change when database implementations change

**Solution: Depend on Abstractions**

**✅ Depends on Abstractions:**

<figure><img src="/files/fb5UsNK7PrYbyf6Ld0VD" alt="" width="563"><figcaption></figcaption></figure>

**Benefits:**

* The app is simpler and more focused
* Easy to swap database implementations
* Better testability (can mock Database)

**The "Inversion" Part**

The dependency is **inverted**:

<figure><img src="/files/eV2uePDQyFr7Ny3lpq3G" alt="" width="563"><figcaption></figcaption></figure>

The concrete class now depends on the abstraction, not the other way around!

**Advanced Example: Dependency Injection**

<figure><img src="/files/0LVlfVRy5nNIGyDSwCuH" alt="" width="563"><figcaption></figcaption></figure>

### Common Patterns and Best Practices

#### Composition Over Inheritance

**Principle:** Favor object composition over class inheritance.

<figure><img src="/files/iHcziUweZIwsrLR5T4dN" alt="" width="563"><figcaption></figcaption></figure>

#### Factory Pattern

Centralize object creation logic.

<figure><img src="/files/YXJqYLIABfzjDnBhGKbf" alt="" width="563"><figcaption></figcaption></figure>

#### Strategy Pattern

Define a family of algorithms and make them interchangeable

<figure><img src="/files/w9tJfAFwZFcCq8ve8W2Q" alt="" width="563"><figcaption></figcaption></figure>

### Practical Guidelines

#### Use Common Sense

**Remember:** The goal is readable, maintainable code, not following rules blindly.

<figure><img src="/files/v9B9sGf4koVNXafP69AT" alt="" width="563"><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dipghosh.gitbook.io/dip-ghosh/coding-practices/code-best-practices/programming-principles/clean-code/classes-objects-and-data-containers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
