Object-Oriented Programming Foundations

Encapsulation, Access Control, and Object Invariants

ReadingPreview

You are viewing a free preview lesson.

Lesson Overview

আগের lesson-এ constructor ব্যবহার করে একটি object-কে valid state-এ তৈরি করেছি।

Enrollment enrollment =
        new Enrollment(
                "Nur",
                "Java and OOP Foundation",
                20
        );

Constructor নিশ্চিত করেছে:

Learner name blank নয়
Course title blank নয়
Total lessons zero-এর বেশি
Completed lessons শুরু হয়েছে zero থেকে

কিন্তু fields direct accessible থাকলে caller constructor-এর validation bypass করতে পারে।

enrollment.completedLessons = -10;
enrollment.totalLessons = 0;

Object valid state-এ তৈরি হলেও পরে invalid হয়ে গেল।

Encapsulation এই সমস্যা সমাধান করে।

এর উদ্দেশ্য:

  • Internal state hide করা
  • State পরিবর্তনের পথ control করা
  • Business rules enforce করা
  • Object-এর public API meaningful রাখা
  • Implementation future-এ পরিবর্তন করার freedom রাখা

এই lesson-এ আমরা শিখব:

  • Encapsulation কী
  • private fields কেন প্রয়োজন
  • Java access modifiers
  • Public object API
  • Getters এবং setters
  • কেন every field-এর setter থাকা উচিত নয়
  • Object invariants
  • Behavior-focused methods
  • Constructor এবং methods কীভাবে একসঙ্গে object validity রক্ষা করে

Learning Objectives

এই lesson শেষ করার পর আপনি পারবেন:

  • Encapsulation-এর purpose ব্যাখ্যা করতে
  • Fields private করতে
  • public, private, package-private এবং protected-এর basic difference বুঝতে
  • Controlled getters এবং methods expose করতে
  • Unnecessary setters avoid করতে
  • Object invariant define করতে
  • Invalid state transitions prevent করতে
  • Constructor validation এবং method validation-এর relationship বুঝতে
  • Behavior-focused object API design করতে

The Problem with Direct Field Access

Current class:

public class Enrollment {

    String learnerName;
    String courseTitle;

    int completedLessons;
    int totalLessons;
}

Caller যেকোনো field direct change করতে পারে।

enrollment.completedLessons = 500;
enrollment.totalLessons = 20;

এখন progress:

2500%

আরও invalid states:

enrollment.learnerName = null;
enrollment.courseTitle = "";
enrollment.completedLessons = -5;
enrollment.totalLessons = -1;

Class-এর methods যত ভালো validationই করুক, direct field access caller-কে সব rules bypass করতে দেয়।


What Is Encapsulation?

Encapsulation হলো:

  1. Object-এর internal state এবং related behavior একসঙ্গে রাখা
  2. সেই state কীভাবে read এবং change করা যাবে তা control করা

Fields সাধারণত private রাখা হয়।

public class Enrollment {

    private String learnerName;
    private String courseTitle;

    private int completedLessons;
    private int totalLessons;
}

এখন অন্য class direct field access করতে পারবে না।

Wrong:

enrollment.completedLessons = 10;

Compiler error হবে।

Caller-কে object-এর public methods ব্যবহার করতে হবে।

enrollment.completeLessons(10);

এখানে object নিজেই state transition validate করতে পারে।


private Fields

private member শুধু একই class-এর ভেতরে accessible।

public class Enrollment {

    private int completedLessons;

    public boolean completeLesson() {
        completedLessons++;

        return true;
    }
}

Enrollment class-এর methods field access করতে পারে।

External caller direct access করতে পারে না।


Encapsulation Is More Than private

শুধু field private করলেই good encapsulation complete হয় না।

Example:

private int completedLessons;

public void setCompletedLessons(
        int completedLessons
) {
    this.completedLessons =
            completedLessons;
}

Caller এখনো লিখতে পারে:

enrollment.setCompletedLessons(
        -500
);

Field technically private, কিন্তু state effectively uncontrolled।

Better question:

Caller-এর কি completed lesson count arbitrary value-তে set করার প্রয়োজন আছে?

Usually no।

Meaningful operation:

enrollment.completeLesson();

অথবা:

enrollment.completeLessons(3);

এগুলো domain behavior express করে এবং rules enforce করতে পারে।


Behavior-Focused API

Weak API:

enrollment.setCompletedLessons(5);
enrollment.setActive(false);

Caller low-level state manipulate করছে।

Stronger API:

enrollment.completeLessons(5);
enrollment.cancel();

এই methods intent প্রকাশ করে।

Object decide করতে পারে:

  • Operation valid কি না
  • কোন fields change হবে
  • কোন state transition allowed
  • Additional rules apply হবে কি না

Object Invariants

Object invariant হলো এমন rule, যা valid object-এর lifetime জুড়ে true থাকা উচিত।

Enrollment invariants:

Learner name blank নয়
Course title blank নয়
Total lessons zero-এর বেশি
Completed lessons negative নয়
Completed lessons total lessons-এর বেশি নয়
Cancelled enrollment-এর progress update করা যাবে না

Constructor initial invariants establish করে।

Public methods future changes-এর সময় invariants preserve করে।


Constructor and Encapsulation Work Together

Constructor:

Object-কে valid state-এ তৈরি করে

Encapsulation:

Object তৈরির পরে invalid state তৈরি হওয়া prevent করে

একটি ছাড়া অন্যটি incomplete protection দেয়।


A Properly Encapsulated Enrollment

public class Enrollment {

    private String learnerName;
    private String courseTitle;

    private int completedLessons;
    private int totalLessons;

    private boolean active;

    public Enrollment(
            String learnerName,
            String courseTitle,
            int totalLessons
    ) {
        if (
                learnerName == null
                || learnerName.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Learner name is required."
            );
        }

        if (
                courseTitle == null
                || courseTitle.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Course title is required."
            );
        }

        if (totalLessons <= 0) {
            throw new IllegalArgumentException(
                    "Total lessons must be greater than zero."
            );
        }

        this.learnerName =
                learnerName.strip();

        this.courseTitle =
                courseTitle.strip();

        this.completedLessons = 0;
        this.totalLessons =
                totalLessons;

        this.active = true;
    }
}

External code এখন fields direct modify করতে পারবে না।

Object-এর public methods define করবে কোন operations allowed।


Public Behavior

public boolean completeLessons(
        int lessonCount
) {
    if (!active) {
        return false;
    }

    if (lessonCount <= 0) {
        return false;
    }

    int updatedCount =
            completedLessons
            + lessonCount;

    if (
            updatedCount
            > totalLessons
    ) {
        return false;
    }

    completedLessons =
            updatedCount;

    return true;
}

Method invariants protect করছে:

Inactive enrollment change হবে না
Negative বা zero lesson count accepted নয়
Completed count total exceed করবে না

State Transition Methods

Enrollment cancel করার জন্য:

public boolean cancel() {
    if (!active) {
        return false;
    }

    if (isCompleted()) {
        return false;
    }

    active = false;

    return true;
}

Possible contract:

Already inactive enrollment cancel করা যাবে না
Completed enrollment cancel করা যাবে না
Successful cancellation active state false করবে

Caller শুধু লিখবে:

enrollment.cancel();

Internal fields কীভাবে change হচ্ছে, তা caller-এর জানা দরকার নেই।


Query Methods

Query methods object state সম্পর্কে information return করে।

public double calculateProgress() {
    return completedLessons
            * 100.0
            / totalLessons;
}
public boolean isCompleted() {
    return completedLessons
            == totalLessons;
}
public boolean isActive() {
    return active;
}

Queries ideally state change করবে না।


Getters

Getter একটি field-এর value caller-এর কাছে expose করে।

public String getLearnerName() {
    return learnerName;
}
public int getCompletedLessons() {
    return completedLessons;
}

Usage:

System.out.println(
        enrollment.getLearnerName()
);

Boolean Getter Naming

Boolean query সাধারণত is বা has দিয়ে শুরু হয়।

public boolean isActive() {
    return active;
}
public boolean isCompleted() {
    return completedLessons
            == totalLessons;
}

getActive() technically possible হলেও isActive() বেশি natural।


Not Every Field Needs a Getter

Private field মানেই automatic getter তৈরি করতে হবে—এমন নয়।

Ask:

Caller-এর কি raw field value জানা প্রয়োজন?

Example:

private boolean internalReviewRequired;

এটি object implementation detail হতে পারে।

Caller-এর প্রয়োজন হতে পারে শুধু:

public boolean canPublish() {
    return !internalReviewRequired
            && totalLessons > 0;
}

Raw internal flag expose না করেও useful business answer দেওয়া যায়।


Setters

Traditional setter:

public void setCourseTitle(
        String courseTitle
) {
    this.courseTitle =
            courseTitle;
}

এটি validation ছাড়া weak।

Validated setter:

public boolean setCourseTitle(
        String courseTitle
) {
    if (
            courseTitle == null
            || courseTitle.isBlank()
    ) {
        return false;
    }

    this.courseTitle =
            courseTitle.strip();

    return true;
}

Technically better, কিন্তু naming আরও meaningful হতে পারে।

public boolean changeCourseTitle(
        String newTitle
) {
    if (
            newTitle == null
            || newTitle.isBlank()
    ) {
        return false;
    }

    courseTitle =
            newTitle.strip();

    return true;
}

changeCourseTitle() একটি domain operation-এর মতো পড়ে।


Why Blind Setters Are Dangerous

Consider:

public void setActive(
        boolean active
) {
    this.active = active;
}

Caller লিখতে পারে:

enrollment.setActive(false);
enrollment.setActive(true);

কিন্তু enrollment reactivation-এর business rules কী?

  • Cancelled enrollment reactivate করা যাবে?
  • Payment required?
  • Course enrollment open?
  • Admin permission required?

Generic setter এসব প্রশ্ন bypass করে।

Better methods:

cancel();
reactivate();

প্রতিটি method নিজের rules enforce করবে।


Getters and Setters Are Not Encapsulation by Themselves

এই class:

public class Enrollment {

    private int completedLessons;

    public int getCompletedLessons() {
        return completedLessons;
    }

    public void setCompletedLessons(
            int completedLessons
    ) {
        this.completedLessons =
                completedLessons;
    }
}

ক্ষেত্রটিকে syntax-level private করেছে, কিন্তু caller এখনও arbitrary state assign করতে পারে।

Strong encapsulation asks:

  • Which state should be visible?
  • Which state should be mutable?
  • Through which operations?
  • Under which rules?

Java Access Modifiers

Java-তে commonly used access levels:

  • public
  • private
  • package-private
  • protected

public

সব accessible context থেকে member use করা যায়, যদি class নিজেও accessible হয়।

public boolean completeLesson() {
}

Public methods object-এর external API-এর অংশ।

Public API carefully design করা উচিত, কারণ callers এর ওপর depend করে।


private

শুধু একই class-এর ভেতরে accessible।

private int completedLessons;

Internal implementation details-এর জন্য commonly used।


Package-Private

কোনো modifier না দিলে member package-private।

int completedLessons;

Same package-এর classes access করতে পারে।

Other packages পারে না।

এটি accidental omission হিসেবে ব্যবহার করা উচিত নয়।

Package-level collaboration deliberately প্রয়োজন হলে ব্যবহার করুন।


protected

protected member:

  • Same package থেকে accessible
  • Subclasses থেকে accessible
protected int completedLessons;

Inheritance-related code-এ ব্যবহৃত হয়।

Beginner domain classes-এ fields protected করা সাধারণত প্রয়োজন হয় না।

Inheritance module-এ এটি বিস্তারিত শেখানো হবে।


Access Modifier Summary

ModifierSame ClassSame PackageSubclassOther Packages
privateYesNoNoNo
Package-privateYesYesSame package rulesNo
protectedYesYesYes, with rulesNo direct general access
publicYesYesYesYes

এই table conceptual overview।

protected access-এর exact cross-package rules inheritance শেখার সময় বিস্তারিত বোঝা হবে।


Minimize Public Surface Area

Class-এর যত বেশি public methods থাকবে, callers-এর সঙ্গে coupling তত বাড়তে পারে।

Public API-তে শুধু meaningful operations রাখা ভালো।

Weak API:

setLearnerName()
setCourseTitle()
setCompletedLessons()
setTotalLessons()
setActive()
setCancelled()
setProgress()

Focused API:

completeLessons()
cancel()
changeCourseTitle()
calculateProgress()
isCompleted()
isActive()

Small public API:

  • Understand করা সহজ
  • Test করা সহজ
  • Misuse করা কঠিন
  • Future-এ change করা সহজ

Derived State Should Usually Be Queried

Progress percentage fields থেকে calculate করা যায়।

private int completedLessons;
private int totalLessons;

Avoid storing:

private double progressPercentage;

কারণ source fields change হলে value stale হতে পারে।

Query:

public double calculateProgress() {
    return completedLessons
            * 100.0
            / totalLessons;
}

এতে result always current state থেকে আসে।


Avoid Exposing Mutable Internal Objects

Primitive এবং String getters relatively safe, কারণ caller returned value ব্যবহার করে internal object mutate করতে পারে না।

কিন্তু mutable object বা collection return করলে সমস্যা হতে পারে।

Conceptual example:

private List<String> completedLessonIds;

public List<String> getCompletedLessonIds() {
    return completedLessonIds;
}

Caller লিখতে পারে:

enrollment
        .getCompletedLessonIds()
        .clear();

এতে internal state bypass হয়ে change হলো।

Safer options:

return List.copyOf(
        completedLessonIds
);

Collections পরে শেখানো হবে।

এখানে principle:

Getter যেন caller-কে internal mutable state uncontrolledভাবে change করার সুযোগ না দেয়।


Validation Belongs Near the Rule

ধরা যাক:

Completed lessons cannot exceed total lessons.

এটি enrollment invariant।

এই rule Enrollment class-এর কাছেই থাকা উচিত।

public boolean completeLessons(
        int lessonCount
) {
    // Validate invariant
}

কিন্তু একটি rule যদি external information require করে:

Learner may enroll only if payment was confirmed by payment provider.

তাহলে শুধু Enrollment object যথেষ্ট নাও হতে পারে।

Application service বা domain service external collaboration handle করতে পারে।


Engineering Note: Not All Validation Belongs in One Place

Validation broadly তিন ধরনের হতে পারে।

Input Format Validation

Email format valid?
Request field present?
Number parse করা গেছে?

Usually boundary layer handle করতে পারে।

Object Invariant Validation

Total lessons greater than zero
Completed count cannot exceed total
Price cannot be negative

Domain object-এর কাছে থাকা উচিত।

External Rule Validation

Payment provider confirmed?
Database-এ email unique?
Course enrollment currently open?

External dependency প্রয়োজন হতে পারে।

Encapsulation মানে সব application logic একটি class-এর মধ্যে ঢুকিয়ে দেওয়া নয়।


A Complete Encapsulated Enrollment

Enrollment.java

public class Enrollment {

    private final String learnerName;
    private final String courseTitle;

    private final int totalLessons;

    private int completedLessons;
    private boolean active;

    public Enrollment(
            String learnerName,
            String courseTitle,
            int totalLessons
    ) {
        if (
                learnerName == null
                || learnerName.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Learner name is required."
            );
        }

        if (
                courseTitle == null
                || courseTitle.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Course title is required."
            );
        }

        if (totalLessons <= 0) {
            throw new IllegalArgumentException(
                    "Total lessons must be greater than zero."
            );
        }

        this.learnerName =
                learnerName.strip();

        this.courseTitle =
                courseTitle.strip();

        this.totalLessons =
                totalLessons;

        this.completedLessons = 0;
        this.active = true;
    }

    public boolean completeLessons(
            int lessonCount
    ) {
        if (!active) {
            return false;
        }

        if (lessonCount <= 0) {
            return false;
        }

        int updatedCount =
                completedLessons
                + lessonCount;

        if (
                updatedCount
                > totalLessons
        ) {
            return false;
        }

        completedLessons =
                updatedCount;

        return true;
    }

    public boolean cancel() {
        if (!active) {
            return false;
        }

        if (isCompleted()) {
            return false;
        }

        active = false;

        return true;
    }

    public String getLearnerName() {
        return learnerName;
    }

    public String getCourseTitle() {
        return courseTitle;
    }

    public int getCompletedLessons() {
        return completedLessons;
    }

    public int getTotalLessons() {
        return totalLessons;
    }

    public int calculateRemainingLessons() {
        return totalLessons
                - completedLessons;
    }

    public double calculateProgress() {
        return completedLessons
                * 100.0
                / totalLessons;
    }

    public boolean isCompleted() {
        return completedLessons
                == totalLessons;
    }

    public boolean isActive() {
        return active;
    }
}

Why Some Fields Are final

private final String learnerName;
private final String courseTitle;
private final int totalLessons;

final means field reference বা primitive value constructor assignment-এর পরে reassign করা যাবে না।

এই design ধরে নিচ্ছে:

  • Enrollment অন্য learner-এর কাছে transfer হবে না
  • Enrollment অন্য course-এ move হবে না
  • Course lesson count snapshot enrollment creation-এর সময় fixed

এটি সব system-এর জন্য correct নাও হতে পারে।

Design decision domain rules-এর ওপর নির্ভর করে।

Immutability lesson-এ final বিস্তারিত শেখানো হবে।


Using the Encapsulated Object

Main.java

public class Main {

    public static void main(String[] args) {
        Enrollment nurEnrollment =
                new Enrollment(
                        "Nur",
                        "Java and OOP Foundation",
                        20
                );

        boolean progressUpdated =
                nurEnrollment
                        .completeLessons(8);

        if (!progressUpdated) {
            System.out.println(
                    "Progress update failed."
            );

            return;
        }

        System.out.println(
                "Learner: "
                + nurEnrollment
                        .getLearnerName()
        );

        System.out.println(
                "Course: "
                + nurEnrollment
                        .getCourseTitle()
        );

        System.out.println(
                "Progress: "
                + "%.2f%%".formatted(
                        nurEnrollment
                                .calculateProgress()
                )
        );

        System.out.println(
                "Remaining lessons: "
                + nurEnrollment
                        .calculateRemainingLessons()
        );

        System.out.println(
                "Active: "
                + nurEnrollment.isActive()
        );
    }
}

Output:

Learner: Nur
Course: Java and OOP Foundation
Progress: 40.00%
Remaining lessons: 12
Active: true

External code cannot do:

nurEnrollment.completedLessons = -100;

Compiler prevents direct access।


Design Trade-Off: Returning boolean

Current commands return boolean:

boolean completeLessons(
        int lessonCount
)

This keeps the example simple।

Limitation:

false

does not explain why operation failed।

Possible reasons:

  • Enrollment inactive
  • Count not positive
  • Total exceeded

Production design alternatives:

  • Throw domain-specific exception
  • Return an enum
  • Return a result object
  • Use different application-layer error handling

Example concept:

ProgressUpdateResult result =
        enrollment.completeLessons(3);

Result could distinguish:

UPDATED
INACTIVE_ENROLLMENT
INVALID_LESSON_COUNT
TOTAL_EXCEEDED

For beginner code, boolean is enough।

The important point হলো failure contract intentional হওয়া উচিত।


Common Mistakes

Making Fields Public

public int completedLessons;

Caller invariants bypass করতে পারে।


Creating Setters for Every Field

setCompletedLessons()
setTotalLessons()
setActive()

এগুলো object state uncontrolled করে দিতে পারে।


Performing No Validation in Setters

public void setTotalLessons(
        int totalLessons
) {
    this.totalLessons =
            totalLessons;
}

Negative এবং zero values accepted হয়।


Exposing Internal Implementation

Caller-এর শুধু canEnroll() প্রয়োজন, কিন্তু class অনেক internal flags expose করছে।

Public API domain questions answer করা উচিত।


Returning Mutable Internal State

Getter দিয়ে internal collection return করলে caller state bypass করে modify করতে পারে।


Putting External Work Inside the Domain Object

public void cancel() {
    active = false;

    database.save(this);
    emailService.sendEmail();
}

এটি state transition, persistence এবং communication mix করে।

Domain object state rule enforce করতে পারে।

Application layer persistence এবং notifications coordinate করতে পারে।


Believing private Makes an Object Immutable

private শুধু access restrict করে।

Class-এর own methods state change করতে পারে।

private int completedLessons;

public void completeLesson() {
    completedLessons++;
}

Object এখনও mutable।


Practice Exercises

Exercise 1: Encapsulate Course

Fields:

title
priceInPaisa
totalLessons
published

Requirements:

  • Fields private
  • Constructor required values validate করবে
  • Negative price reject করবে
  • Blank title reject করবে
  • publish() method থাকবে
  • Direct setPublished() থাকবে না

Exercise 2: Design Meaningful Methods

Replace these setters:

setCompletedLessons
setActive
setPublished
setPrice

with meaningful operations for:

Enrollment
Course

Exercise 3: Define Invariants

একটি Course object-এর জন্য অন্তত চারটি invariants লিখুন।

Example fields:

title
priceInPaisa
totalLessons
published

Exercise 4: Getter or Query?

Decide which API is clearer:

getCompletedLessons()

or:

isCompleted()

Explain why both may be useful but answer different questions।


Exercise 5: Access Modifiers

Choose an appropriate modifier:

  1. Enrollment internal progress count
  2. Public completeLesson() operation
  3. Internal validation helper used only by the same class
  4. A member intentionally shared only within the same package

Exercise 6: Identify Weak Encapsulation

public class Course {

    private long priceInPaisa;

    public void setPriceInPaisa(
            long priceInPaisa
    ) {
        this.priceInPaisa =
                priceInPaisa;
    }
}

Explain why this is not enough।

Improve the method।


Exercise 7: Separate Responsibilities

Review:

public boolean publish() {
    published = true;

    database.save(this);
    emailService.notifyLearners();

    return true;
}

Identify which responsibilities should remain in the object and which should move elsewhere।


Predict the Result

Question 1

public class Enrollment {

    private int completedLessons;
}

Can Main do this?

enrollment.completedLessons = 5;

Question 2

public boolean completeLessons(
        int count
) {
    if (count <= 0) {
        return false;
    }

    completedLessons +=
            count;

    return true;
}

What invariant is still unprotected?


Question 3

public boolean isCompleted() {
    return completedLessons
            == totalLessons;
}

Does this method need a setter?


Question 4

Can a class with only private fields still be mutable?


Predict the Result Answers

Answer 1

না।

completedLessons শুধু Enrollment class-এর ভেতরে accessible।

Answer 2

Completed lesson count total lessons exceed করতে পারে।

Updated state commit করার আগে total validate করতে হবে।

Answer 3

না।

isCompleted() existing state থেকে derived answer return করে।

Answer 4

হ্যাঁ।

Public বা private methods fields change করলে object mutable।


Knowledge Check

Question 1

Encapsulation কী?

Question 2

Fields private রাখার benefit কী?

Question 3

private field কি same class-এর method access করতে পারে?

Question 4

Every private field-এর getter এবং setter প্রয়োজন কি?

Question 5

Blind setter কেন risky?

Question 6

Object invariant কী?

Question 7

Constructor এবং public methods invariants কীভাবে protect করে?

Question 8

public methods কী represent করে?

Question 9

Package-private access কী?

Question 10

protected সাধারণত কোন context-এ useful?

Question 11

Derived progress আলাদা field হিসেবে store না করাই ভালো কেন?

Question 12

Mutable internal collection direct return করা risky কেন?

Question 13

Validation-এর সব ধরনের rule কি domain object-এর মধ্যে থাকা উচিত?

Question 14

private fields কি object-কে automatically immutable করে?


Knowledge Check Answers

Answer 1

Object-এর internal state hide করা এবং সেই state read ও change করার controlled API expose করা।

Answer 2

Caller direct mutation করে invariants ভাঙতে পারে না।

Answer 3

হ্যাঁ।

Answer 4

না। শুধু caller-এর প্রয়োজনীয় information এবং operations expose করা উচিত।

Answer 5

Caller arbitrary value assign করে invalid state তৈরি করতে পারে।

Answer 6

Object-এর valid lifetime জুড়ে true থাকা উচিত এমন rule।

Answer 7

Constructor valid initial state তৈরি করে। Public methods valid state transitions enforce করে।

Answer 8

Object-এর external contract বা API।

Answer 9

কোনো modifier না দিলে member same package-এর classes থেকে accessible হয়।

Answer 10

Inheritance এবং subclass access-এর ক্ষেত্রে।

Answer 11

Source fields change হলে stored derived value stale হতে পারে।

Answer 12

Caller object-এর controlled methods bypass করে internal state modify করতে পারে।

Answer 13

না। Input format, domain invariants এবং external dependency rules আলাদা layers-এ থাকতে পারে।

Answer 14

না। Class methods state change করলে object mutable থাকে।


Lesson Summary

এই lesson-এ আমরা শিখেছি:

  • Constructor valid object তৈরি করে
  • Encapsulation সেই validity object lifetime জুড়ে protect করে
  • Direct field access caller-কে rules bypass করতে দেয়
  • private fields internal state hide করে
  • Public methods object-এর external API তৈরি করে
  • Encapsulation শুধু private fields এবং getters/setters নয়
  • Blind setters invalid state allow করতে পারে
  • Meaningful methods domain intent এবং rules প্রকাশ করে
  • Object invariants valid state define করে
  • Constructor initial invariants establish করে
  • Commands valid state transitions enforce করে
  • Queries state read করে এবং ideally mutation করে না
  • Every field-এর getter প্রয়োজন নেই
  • Every field-এর setter থাকা উচিত নয়
  • Public API যত ছোট এবং focused হয়, misuse তত কমে
  • public, private, package-private এবং protected different visibility দেয়
  • Derived state সাধারণত calculate করা safer
  • Mutable internal objects direct expose করা উচিত নয়
  • Core domain validation object-এর কাছে রাখা যায়
  • External rules application বা service layer require করতে পারে
  • private object-কে automatically immutable করে না
  • Strong encapsulation object-কে নিজের rules protect করার ক্ষমতা দেয়

Next Lesson

পরবর্তী lesson:

Static and Instance Members

আমরা শিখব:

  • Instance fields এবং methods
  • Static fields এবং methods
  • Per-object state এবং class-level state
  • Shared counters
  • static final constants
  • Static context-এর limitations
  • Why utility methods may be static
  • Why domain state usually should not be global