Java Getter Setter methods: Encapsulation හරියටම ඉගෙනගමු! | SC Guide

Java Getter Setter methods: Encapsulation හරියටම ඉගෙනගමු! | SC Guide

හෙලෝ යාලුවනේ! කොහොමද ඉතින්, වැඩ එහෙම සාර්ථකව කරගෙන යනවද? අද අපි කතා කරන්න යන්නේ Java Programming වලදී නිතරම අහන්න ලැබෙන, ඒ වගේම ගොඩක් වැදගත් Concepts දෙකක් ගැන: ඒ තමයි Getter Methods සහ Setter Methods. ඇත්තටම මේ දෙක තියෙන්නේ Encapsulation කියන OOP Concept එකත් එක්ක. Java වලින් code ලියනකොට කී පාරක් නම් Getter Setter Methods ගැන අහලා ඇද්ද? සමහරවිට ඒවා Generate කරලා ඇති, හැබැයි ඒවා හරියටම මොකටද, කොහොමද use කරන්නේ කියන එක පැහැදිලි නැතුව ඇති නේද?

අද මේ Guide එකෙන් අපි බලමු Getters සහ Setters මොනවද, ඒවා ඇයි එච්චරටම වැදගත් වෙන්නේ, ඒ වගේම ඒවා පාවිච්චි කරනකොට අපි අනිවාර්යයෙන්ම අවධානය යොමු කරන්න ඕන Best Practices මොනවද කියලා. Code ටිකක් ලස්සනට, Secure විදියට, Maintain කරන්න පුලුවන් විදියට ලියන්න නම් මේවා දැනගෙන ඉන්න එක අනිවාර්යයි!

Getter Setter Methods කියන්නේ මොනවාද?

සරලවම කිව්වොත්, Getter Methods කියන්නේ Class එකක Private variables වල අගයන් (values) කියවන්න (read) පාවිච්චි කරන Methods. ඒවාට “Accessors” කියලත් කියනවා. ඒ වගේම Setter Methods කියන්නේ Private variables වල අගයන් වෙනස් කරන්න (modify) නැත්නම් අලුත් අගයක් දෙන්න (set) පාවිච්චි කරන Methods. ඒවාට “Mutators” කියලත් කියනවා.

දැන් ඔයාට හිතෙන්න පුලුවන් ඇයි මේ Private variables වලට කෙලින්ම access කරන්නේ නැතුව methods වලින් යන්න ඕන කියලා. ඒකට තමයි Encapsulation කියන Concept එක එන්නේ. ඒ ගැන අපි තව ටිකකින් කතා කරමු.

දැන් අපි පොඩි Example එකක් බලමු. හිතන්නකෝ අපිට Person කියන Class එකක් තියෙනවා කියලා, ඒකේ name සහ age කියන attributes දෙක තියෙනවා.

public class Person {
    private String name;
    private int age;

    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Getter for name
    public String getName() {
        return name;
    }

    // Setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Getter for age
    public int getAge() {
        return age;
    }

    // Setter for age
    public void setAge(int age) {
        this.age = age;
    }
}

මේ Example එකේදී, name සහ age කියන fields දෙක private විදියට declare කරලා තියෙනවා. ඒ කියන්නේ Person Class එකෙන් පිට ඉඳන් මේ fields වලට කෙලින්ම access කරන්න බැහැ. ඒවාට access කරන්න පුලුවන් වෙන්නේ getName(), setName(), getAge(), setAge() කියන Public Methods හරහා විතරයි. මේක තමයි Getter Setter Methods වල මූලිකම ක්‍රියාකාරිත්වය.

Encapsulation කියන්නේ මොකක්ද?

Getter Setter Methods ගැන කතා කරනකොට Encapsulation ගැන කතා නොකරම බෑ. Encapsulation කියන්නේ Object-Oriented Programming (OOP) වල තියෙන fundamental concept එකක්. සරලවම කිව්වොත්, ඒකෙන් වෙන්නේ Class එකක Data (variables) සහ ඒ Data manipulate කරන Methods එකට බැඳලා (bundle) තියන එක, ඒ වගේම Class එකෙන් පිටත ලෝකයට ඒ Data වලට කෙලින්ම access කරන්න නොදී, Methods හරහා විතරක් access කරන්න දෙන එක. මේකට අපි Data Hiding කියලත් කියනවා.

තව සරලව කියනවා නම්, ඔයාගේ පෝන් එකේ ඇතුලේ Circuit, Wires, Chips කොච්චර සංකීර්ණද කියලා ඔයාට පේන්නේ නෑ. ඔයාට පේන්නේ Screen එක, Buttons ටික විතරයි. ඔයාට අවශ්‍ය දේවල් කරන්න ඔයා Buttons press කරනවා, Screen එක Tap කරනවා විතරයි. ඇතුලේ මොකක්ද වෙන්නේ කියලා ඔයාට දැනගන්න අවශ්‍ය නෑ. මේක තමයි Encapsulation.

Encapsulation වල වාසි

  • Security (ආරක්ෂාව): Data එකට කෙලින්ම access කරන්න නොදී, Methods හරහා access කරන නිසා, වැරදි විදියට Data එක modify කරන එක වළක්වන්න පුලුවන්. උදාහරණයක් විදියට, age එක negative අගයක් වෙන්න බැරි වෙන්න Setters වලදී Validation දාන්න පුලුවන්.
  • Maintainability (නඩත්තු කිරීමේ හැකියාව): Class එකක Internal Implementation එක වෙනස් කළත්, External Users ලට ඒක බලපාන්නේ නැහැ, මොකද ඔවුන් Methods හරහා තමයි Data වලට access කරන්නේ. System එකේ එක තැනක වෙනසක් කරනකොට අනිත් තැන් වලට බලපාන එක අඩු වෙනවා.
  • Flexibility (නම්‍යශීලී බව): අනාගතයේදී Data Structure එක වෙනස් කරන්න අවශ්‍ය වුණොත්, අපිට Setters and Getters ඇතුලේ විතරක් වෙනස්කම් කරලා External Interface එක එහෙම්මම තියාගන්න පුලුවන්.

ඉතින්, Getter Setter Methods කියන්නේ Java වල Encapsulation achieve කරන්න තියෙන ප්‍රධානම ක්‍රමය.

Getter Setter Methods වල Best Practices

දැන් අපි බලමු, Getter Setter Methods පාවිච්චි කරනකොට අපි අනිවාර්යයෙන්ම අවධානය යොමු කරන්න ඕන Best Practices මොනවද කියලා. මේවා follow කරන එකෙන් ඔයාගේ code එක ගොඩක් Clean, Secure සහ Maintainable වෙයි.

1. Always Keep Fields private (Fields හැමවිටම private තියන්න)

මේක තමයි Encapsulation වල මූලිකම රීතිය. Class එකක fields public විදියට දාන එකෙන් Data Hiding නැති වෙනවා. ඒ කියන්නේ ඕනෑම තැනකින් ඒ fields වලට කෙලින්ම access කරන්න පුලුවන් වෙනවා, ඒකෙන් අනිසි විදියට data modify වෙන්න පුලුවන්, Security issues එන්න පුලුවන්.

// Bad Practice: Field is public
public class Product {
    public String name; // Anyone can change this directly
    public double price;
}

// Good Practice: Fields are private
public class Product {
    private String name;
    private double price;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
}

2. Follow Naming Conventions (නම් කිරීමේ සම්මුති අනුගමනය කරන්න)

Java වලදී Getter Setter Methods වලට Standard Naming Conventions තියෙනවා.

  • Non-boolean fields වලට: get<FieldName>() සහ set<FieldName>()
  • Boolean fields වලට: is<FieldName>() සහ set<FieldName>()

මේවා follow කරන එකෙන් code එක කියවන්න පහසු වෙනවා, IDEs (IntelliJ IDEA, Eclipse) වල Auto-generation features හරියට වැඩ කරනවා.

public class User {
    private String username;
    private boolean isActive;

    // Correct naming for String field
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

    // Correct naming for boolean field (is-prefix for getter)
    public boolean isActive() { return isActive; }
    public void setActive(boolean active) { isActive = active; }
}

3. Add Validation Logic in Setters (Setters වල Validation Logic එකතු කරන්න)

Setters කියන්නේ Data එක Class එකට ඇතුල් වෙන තැන. ඒ නිසා මේ තැනදී Data Validation කරන එක ගොඩක් වැදගත්. වැරදි, අසම්පූර්ණ හෝ අගයයන් Data එකට ඇතුල් වීම වළක්වන්න මේක උදව් වෙනවා.

public class Account {
    private double balance;

    public double getBalance() {
        return balance;
    }

    // Validate balance before setting
    public void setBalance(double balance) {
        if (balance < 0) {
            throw new IllegalArgumentException("Balance cannot be negative.");
        }
        this.balance = balance;
    }
}

4. Getters Should Simply Return Data (Getters නිකන්ම Data Return කරන්න ඕන)

Getters වල ප්‍රධානම කාර්යය තමයි field එකක අගය return කරන එක. Getters ඇතුලේ Business Logic හෝ Complex Operations දාන එකෙන් code එක කියවන්න අපහසු වෙනවා, ඒ වගේම unexpected side effects ඇති වෙන්න පුලුවන්.

public class Order {
    private double amount;
    private double discountPercentage;

    // Good: Simple getter
    public double getAmount() {
        return amount;
    }

    // Bad: Getter performs complex calculation (should be a separate method)
    // public double getTotalAmount() {
    //     return amount - (amount * discountPercentage / 100);
    // }

    // Good: Have a separate method for calculations
    public double calculateNetTotal() {
        return amount - (amount * discountPercentage / 100);
    }
}

5. Return Copies of Mutable Objects (Mutable Objects වල පිටපත් Return කරන්න)

මේක ගොඩක් වැදගත් Best Practice එකක්, හැබැයි ගොඩක් අය මේක මග අරිනවා. Class එකක field එකක් Mutable Object එකක් නම් (උදා: Date, List, Map, custom objects), ඒකේ Getter එකෙන් කෙලින්ම ඒ object එක return කරන එකෙන් Encapsulation break වෙන්න පුලුවන්. මොකද එතකොට, Class එකෙන් පිට ඉඳන් ඒ return කරපු object එක modify කරලා Class එකේ Internal State එක වෙනස් කරන්න පුලුවන්.

ඒ වෙනුවට, Getter එකෙන් ඒ Object එකේ copy එකක් return කරන්න ඕන.

import java.util.ArrayList;
import java.util.List;

public class ShoppingCart {
    private List<String> items; // Mutable object

    public ShoppingCart() {
        this.items = new ArrayList<>();
    }

    public void addItem(String item) {
        this.items.add(item);
    }

    // Bad: Returns a direct reference to the internal list
    // public List<String> getItems() {
    //     return items;
    // }

    // Good: Returns a copy of the list to protect internal state
    public List<String> getItems() {
        return new ArrayList<>(this.items);
    }

    // Good: If you want to make it truly immutable, return unmodifiable list
    // public List<String> getItemsImmutable() {
    //     return Collections.unmodifiableList(this.items);
    // }
}

මේ විදියට copy එකක් return කරන එකෙන්, ShoppingCart එකේ items list එකට පිටතින් access කරලා වෙනස් කරන්න බැරි වෙනවා.

6. Consider Immutability (වෙනස් නොවන බව ගැන සලකා බලන්න)

සමහර වෙලාවට Class එකක Data object එකක් හැදුවට පස්සේ වෙනස් වෙන්න අවශ්‍ය නැහැ. එවැනි අවස්ථාවලදී Setters අවශ්‍ය වෙන්නේ නැහැ. ඔයාට පුලුවන් Constructor එක හරහා Data initialize කරලා, Getters විතරක් provide කරන්න. මේ වගේ objects වලට අපි Immutable Objects කියනවා. ඒක Data Consistency සහ Thread Safety වලට ගොඩක් වැදගත්.

public final class ImmutablePoint {
    private final int x;
    private final int y;

    public ImmutablePoint(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
    // No setters as the object is immutable
}

Getter Setter Methods නැතුව බැරිද?

දැන් ඔයාට හිතෙන්න පුලුවන්, “මොනවාද මේ හැමදාම Getter Setter ලිය ලිය ඉන්නේ, මහ කරදරයක්නේ!” කියලා. සිරාවටම, විශාල project වලදී මේ Getter Setter Methods දහස් ගණන් ලියන්න වෙනවා. හැබැයි අද කාලේ මේකට විසඳුම් තියෙනවා.

Java Records (Java 16+): Java 16 වල ඉඳන් Records කියන feature එක ආවා. මේක Data Classes වලට ගොඩක්ම පහසුයි. Records කියන්නේ Immutability simplify කරන්න සහ boilerplate code අඩු කරන්න හදපු feature එකක්. ඒවා automatically Getters, equals(), hashCode(), toString() methods provide කරනවා.

public record Car(String make, String model, int year) {
    // Getters for make, model, year are automatically generated
    // No setters, as records are immutable by default
}

Car car = new Car("Toyota", "Corolla", 2020);String make = car.make(); // Access like a getter, but no 'get' prefix

Lombok Library: Project Lombok කියන්නේ Java code වල boilerplate code (නිතරම ලියන ඒත් එච්චරටම වැදගත් නැති code) අඩු කරන Library එකක්. ඔයාට @Getter, @Setter, @Data වගේ Annotations පාවිච්චි කරලා Automatic Getter Setter Methods generate කරගන්න පුලුවන්. හැබැයි Lombok පාවිච්චි කරනවා නම්, ඒකේ වාසි වගේම අවාසිත් ගැන පොඩ්ඩක් research කරලා බලන්න.

import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class Employee {
    private String id;
    private String name;
    private double salary;
}

මේ Employee class එක compile කරනකොට, Lombok automatically getId(), setId(), getName(), setName(), getSalary(), setSalary() methods generate කරනවා.

මේවා තිබ්බත්, Getter Setter Methods වල Concept එක, ඒවයින් achieve කරන Encapsulation එක ගැන හොඳ අවබෝධයක් තියෙන එක අනිවාර්යයි. මොකද මේ Libraries සහ Features වැඩ කරන්නේ ඒ මූලික Concepts මත තමයි.

අවසන් වචන

ඉතින් යාලුවනේ, ඔන්න අපි අද Java Getter Setter Methods සහ Encapsulation ගැන හොඳටම කතා කළා. මේවා Programming වලදී කෝකටත් තෛලය වගේ වැදගත්. Security, Maintainability, Flexibility කියන තුනම හොඳටම ආරක්ෂා කරගන්න මේවා අත්‍යවශ්‍යයි. විශේෂයෙන්ම Best Practices හරියටම follow කරන එකෙන් ඔයාගේ code එකේ quality එක ගොඩක් වැඩි කරගන්න පුලුවන්.

මේවා පොඩ්ඩක් ඔයාගේ project වලට apply කරලා බලන්න. පොඩි පොඩි දේවල් වලින් පටන් අරන්, මේ Concepts තව තවත් ගැඹුරින් ඉගෙන ගන්න. මොකද අපි හැමදාම අලුත් දේවල් ඉගෙන ගන්න ඕනනේ! අදම ඔයාගේ project එකක private fields දාලා, Getters Setters වලින් access කරලා, validation දාලා බලන්න.

මේ guide එක ඔයාලට වැදගත් වුණා නම්, අනිවාර්යයෙන්ම share කරන්න. ඔයාලට මේ ගැන ප්‍රශ්න තියෙනවා නම්, පහලින් comment එකක් දාන්න. අපි උත්තර දෙන්නම්! එහෙනම් තවත් අලුත් Technical Guide එකකින් හමුවෙමු, හැමෝටම ජය!