DEV Community

Cover image for OOP Fundamentals: Tell ๐Ÿ“ฃ, don't ask ๐Ÿšซ
Thomas Heniart
Thomas Heniart

Posted on

OOP Fundamentals: Tell ๐Ÿ“ฃ, don't ask ๐Ÿšซ

Are you still stuck in the habit of using getters and setters in your code? Well, you've landed on the right page to
grasp one of the most fundamental concepts of Object-Oriented Programming!


Rethinking Object-Oriented Development

Often, developers mistakenly believe they are practicing Object-Oriented Programming (OOP) simply by employing
service-like classes. The example below is a common scenario encountered across various projects:

class IncreaseBankAccountBalance {
    constructor(private readonly _bankAccountRepository: BankAccountRepository) {
    }

    execute({id, increase}: { id: string, increase: number }) {
        const account = this._bankAccountRepository.findById(id)
        const currentBalance = account.getBalance()
        const newBalance = currentBalance + increase
        account.setBalance(newBalance)
        this._bankAccountRepository.save(account)
    }
}

class BankAccount {
    constructor(
        private readonly _id: number,
        private _balance: number
    ) {
    }

    getBalance() {
        return this._balance
    }

    setBalance(value: number) {
        this._balance = value;
    }
}
Enter fullscreen mode Exit fullscreen mode

In this scenario, we fetch an account from a repository and then proceed to call getters and setters to update it. It's
akin to treating a private property like a public one, exposing its value and providing a method to modify it at the
user's discretion.


Unveiling the Object-Oriented Approach

The core principle of OOP is to tell instances to perform work rather than manipulating their properties directly.
This encapsulation of logic within domain entities, rather than imperative services, defines true OOP.

Refining our example, we can shift the increase logic from the IncreaseBankAccountBalance service to the BankAccount
class through a well-named instance method:

class IncreaseBankAccountBalance {
    constructor(private readonly _bankAccountRepository: BankAccountRepository) {
    }

    execute({id, increase}: { id: string, increase: number }) {
        const account = this._bankAccountRepository.findById(id)
        account.increaseBalance(increase)
        this._bankAccountRepository.save(account)
    }
}

class BankAccount {
    constructor(
        private readonly _id: number,
        private _balance: number
    ) {
    }

    increaseBalance(increase: number) {
        this._balance += increase;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, notice that we no longer expose the private balance property. Any user of the BankAccount class must go through
the
increaseBalance instance method, effectively encapsulating the logic of balance increase.


Elevating Immutability for Code Integrity

As a bonus, we can take it a step further by introducing immutability to our code. This minimizes side effects by
returning a new instance of BankAccount with the updated balance, instead of modifying its private property directly:

class IncreaseBankAccountBalance {
    constructor(private readonly _bankAccountRepository: BankAccountRepository) {
    }

    execute({id, increase}: { id: string, increase: number }) {
        const account = this._bankAccountRepository.findById(id)
        this._bankAccountRepository.save(account.withIncreasedBalance(increase))
    }
}

class BankAccount {
    constructor(
        private readonly _id: number,
        private readonly _balance: number
    ) {
    }

    withIncreasedBalance(increase: number) {
        return new BankAccount(this._id, this._balance + increase)
    }
}
Enter fullscreen mode Exit fullscreen mode

In summary, here are some key takeaways for your future coding sessions:

  1. Be cautious when exposing getters and especially when exposing a setter.
  2. Objects should be the sole entities allowed to modify their properties.
  3. Every method must be well-named, clearly expressing its intent.

Stay tuned for more insights! Free to follow me on this platform
and LinkedIn. I share insights every week about software
design, OOP practices, and some personal project discoveries! ๐Ÿ’ป๐Ÿ„

Top comments (0)