Observer Design Pattern Java | සිංහලෙන් | SC Guide

Observer Design Pattern Java | සිංහලෙන් | SC Guide

ආයුබෝවන් යාළුවනේ! කොහොමද ඉතින් ඔයාලට? Tech ලෝකේ අළුත්ම දේවල් හොයන, අළුත් දේවල් ඉගෙනගන්න ආස ඔයාලව අදත් මම මේ ලිපියට සාදරයෙන් පිලිගන්නවා.

ඔයාලා Java වලට ආස නම්, ඒ වගේම Design Patterns ගැන ඉගෙනගන්න ආස නම්, Observer Design Pattern එක කියන්නේ ඔයාලා අනිවාර්යයෙන්ම දැනගෙන ඉන්න ඕන දෙයක්. මොකද මේක ගොඩක් applications වල, විශේෂයෙන්ම event-driven systems වල, බහුලවම පාවිච්චි වෙන pattern එකක්. හිතන්නකෝ, Facebook එකේ Post එකකට කවුරුහරි like එකක් දැම්මාම, ඒ Post එක දාපු කෙනාටයි, ඒකට කලින් comment කරපු අයටයි notification එකක් එනවා. එහෙම නැත්නම්, ක්‍රිකට් මැච් එකක් live බලද්දි score එක update වෙනවා. මේ වගේ scenarios වලදි, එක සිද්ධියක් (event එකක්) නිසා ගොඩක් දේවල් (ඔබ්ජෙක්ට්ස්) update වෙන්න ඕන වෙනවා.

අද අපි බලමු මේ Observer Design Pattern එක හරියටම මොකක්ද කියලා, කොහොමද අපේ Java applications වලට මේක add කරගන්නේ කියලා. තව, Java වල inbuilt Observer/Observable ගැනත්, අපිටම අපේ custom Observer Pattern එකක් හදාගන්න විදිය ගැනත් කතා කරමු.


Observer Design Pattern එක කියන්නේ මොකක්ද?

සරලවම කිව්වොත්, Observer Pattern එක කියන්නේ "Publish-Subscribe" (Pub/Sub) model එකක්. මෙතනදී ප්‍රධාන Obect වර්ග දෙකක් ඉන්නවා:

  • Subject (Publisher / Observable): මේ තමයි සිද්ධිය (event එක) ඇතිවෙන object එක. මේ Subject එකේ මොකක් හරි වෙනසක් වුණාම, තමන්ට "Subscribe" වෙලා ඉන්න හැම Observer කෙනෙක්ටම ඒ ගැන දැනුම් දෙනවා.
  • Observer (Subscriber): මේ තමයි Subject එකේ වෙනස්කම් ගැන දැනගන්න ඕන object එක. Observer කෙනෙක් Subject එකට "register" වෙනවා, එතකොට Subject එකේ update එකක් ආවම Observer ට ඒ update එක ලැබෙනවා.

හිතන්නකෝ පත්තර කන්තෝරුවක් (Subject) ගැන. අළුත් පත්තරයක් (event එකක්) මුද්‍රණය කළාම, ඒ පත්තරේ ගන්න subscribe වෙලා ඉන්න හැම කෙනෙක්ටම (Observers) පත්තරේ ගිහින් දෙනවා. කන්තෝරුව දන්නේ නැහැ පත්තරේ ගෙනියන්නේ කවුද, කොහාටද කියලා. ඒ වගේම, පත්තරේ subscribe වෙන අයටත් කන්තෝරුව ගැන වැඩි විස්තර දැනගන්න ඕන නැහැ. මේකෙන් වෙන්නේ Subject එකයි Observer ලයි අතර තියෙන සම්බන්ධය ගොඩක් ලිහිල් (loosely coupled) වෙන එක. ඒ කියන්නේ, එකක් වෙනස් කළාම අනිත් එකට ඒකෙන් ලොකු බලපෑමක් වෙන්නේ නැහැ.


Java වල Inbuilt Observable සහ Observer

Java වල Observer Pattern එක implement කරන්න java.util.Observable class එකයි java.util.Observer interface එකයි තියෙනවා. මේවා Java 1.0 ඉඳන්ම තිබුණු features. හැබැයි මේවා දැන් Deprecated වෙලා තියෙන්නේ, මොකද ඒවාට පොඩි පොඩි අඩුපාඩු ටිකක් තියෙනවා. ඒත් මේවා ගැන දැනගෙන ඉන්න එක වැදගත්, මොකද Observer Pattern එකේ core concept එක තේරුම් ගන්න මේවා උදව් වෙනවා.

Observable Class එක

Observable class එක extends කරලා තමයි අපේ Subject එක හදන්නේ. මේකේ ප්‍රධාන method කිහිපයක් තියෙනවා:

  • addObserver(Observer o): Observer කෙනෙක්ව register කරන්න.
  • deleteObserver(Observer o): Observer කෙනෙක්ව unregister කරන්න.
  • notifyObservers(Object arg): register වෙලා ඉන්න හැම Observer කෙනෙක්ටම update එක notify කරන්න. arg කියන්නේ Observer එකට යවන්න ඕන data එක.
  • setChanged(): මේක තමයි ටිකක් වැදගත් method එක. notifyObservers() call කරන්න කලින් අනිවාර්යයෙන්ම මේ setChanged() method එක call කරන්න ඕන. එතකොට තමයි Observable එක තේරුම් ගන්නේ state එක වෙනස් වෙලා කියලා.

Observer Interface එක

Observer interface එකේ තියෙන්නේ එකම method එකයි:

  • update(Observable o, Object arg): Subject එකෙන් (Observable o) update එකක් ආවම මේ method එක call වෙනවා. arg කියන්නේ Subject එකෙන් එවන data එක.

ප්‍රායෝගික උදාහරණයක් (Inbuilt Observer/Observable)

අපි හිතමු News Agency එකක් (Observable) තියෙනවා කියලා, ඒක අළුත් News (String) publish කරනවා. News Readers (Observer) ලා ඒ News ගැන දැනගන්න ඕන.


import java.util.Observable;
import java.util.Observer;

// Subject / Observable
class NewsAgency extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        setChanged(); // Indicate that the state has changed
        notifyObservers(news); // Notify all registered observers with the new news
    }

    public String getNews() {
        return news;
    }
}

// Observer
class NewsReader implements Observer {
    private String name;

    public NewsReader(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof NewsAgency) {
            System.out.println(name + " received news: " + arg);
        }
    }
}

// Main class to run the example
public class InbuiltObserverDemo {
    public static void main(String[] args) {
        NewsAgency agency = new NewsAgency();

        NewsReader reader1 = new NewsReader("Kamal");
        NewsReader reader2 = new NewsReader("Nimal");
        NewsReader reader3 = new NewsReader("Sunil");

        // Register observers
        agency.addObserver(reader1);
        agency.addObserver(reader2);
        
        System.out.println("First news update:");
        agency.setNews("Sri Lanka wins Cricket Match!");

        // Add another reader later
        agency.addObserver(reader3);
        
        System.out.println("\nSecond news update:");
        agency.setNews("New technology launched in Sri Lanka.");

        // Unregister an observer
        agency.deleteObserver(reader1);

        System.out.println("\nThird news update (Kamal won't receive):");
        agency.setNews("Economic growth predicted for next quarter.");
    }
}

මේ code එක run කරලා බැලුවොත් ඔයාලට පෙනෙයි NewsAgency එක news publish කරද්දි NewsReader ලා කොහොමද update වෙන්නේ කියලා. Deprecated වුණත්, මේක තමා basic idea එක.

java.util.Observable එකේ සීමාවන් (Limitations)

Observable class එක Deprecated වෙන්න ප්‍රධාන හේතු ටිකක් තියෙනවා:

  • එය class එකක් මිස interface එකක් නොවීම: Java වලදී class එකක් extend කරන්න පුළුවන් එක පාරයි. ඒ නිසා ඔයාලගේ Subject class එකට වෙන class එකක් extends කරන්න ඕන වුණොත්, මේ Observable class එක use කරන්න බැරි වෙනවා.
  • setChanged() call කරන්න අමතක වීම: notifyObservers() call කරන්න කලින් setChanged() call කරන්න අමතක වුණොත් කිසිම update එකක් Observer ලට යන්නේ නැහැ. මේක common mistake එකක්.
  • Thread Safety නොවීම: Concurrency ගැන හිතද්දි, මේ Observable class එක thread-safe වෙන්නේ නැහැ. ඒ කියන්නේ එකම වෙලාවේ thread ගොඩකින් access කරද්දි ගැටළු ඇතිවෙන්න පුළුවන්.

Custom Observer Implementation එකක් හදමු

දැන් අපි බලමු java.util.Observable එකේ සීමාවන් මඟහරවලා අපිටම අපේ Observer Pattern එකක් implement කරගන්නේ කොහොමද කියලා. මේකෙන් අපිට ගොඩක් flexibility එකක් ලැබෙනවා.

Interfaces නිර්මාණය කිරීම

මුලින්ම අපි Interfaces දෙකක් හදාගමු. එකක් Subject (Observable) එකට, අනිත් එක Observer එකට.


// Observer Interface
interface MyObserver {
    void update(String eventDetails);
}

// Subject Interface
interface MySubject {
    void registerObserver(MyObserver observer);
    void removeObserver(MyObserver observer);
    void notifyObservers(String eventDetails);
}

මෙහිදී MyObserver හි update method එකට අපි String eventDetails එකක් යැව්වා. මේක generic type එකක් (<T>) විදියටත් හදන්න පුළුවන්, එතකොට ඕනම data type එකක් යවන්න පුළුවන්.

Custom Subject Class එක

දැන් අපි MySubject interface එක implement කරන class එකක් හදමු.


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

class StockMarket implements MySubject {
    private List<MyObserver> observers = new ArrayList<>();
    private double stockPrice; // State of the subject

    @Override
    public void registerObserver(MyObserver observer) {
        observers.add(observer);
        System.out.println("Observer registered: " + observer.getClass().getSimpleName());
    }

    @Override
    public void removeObserver(MyObserver observer) {
        observers.remove(observer);
        System.out.println("Observer removed: " + observer.getClass().getSimpleName());
    }

    @Override
    public void notifyObservers(String eventDetails) {
        // We can iterate through a copy to avoid ConcurrentModificationException
        // if observers modify the list during notification.
        // For simplicity, we directly iterate here.
        for (MyObserver observer : observers) {
            observer.update(eventDetails);
        }
        System.out.println("Notified " + observers.size() + " observers.");
    }

    // Method to change the state and notify
    public void setStockPrice(double newPrice) {
        System.out.println("\nStock price changed from " + this.stockPrice + " to " + newPrice);
        this.stockPrice = newPrice;
        notifyObservers("Stock price updated to " + newPrice);
    }
}

Custom Observer Classes

ඊළඟට, MyObserver interface එක implement කරන Observer Classes කිහිපයක් හදමු.


class StockDisplay implements MyObserver {
    private String name;

    public StockDisplay(String name) {
        this.name = name;
    }

    @Override
    public void update(String eventDetails) {
        System.out.println(name + " received stock update: " + eventDetails);
    }
}

class TradingBot implements MyObserver {
    @Override
    public void update(String eventDetails) {
        if (eventDetails.contains("updated to 150.0")) { // Example condition
            System.out.println("TradingBot: Stock price is 150.0! Executing a buy order...");
        } else {
            System.out.println("TradingBot: Received update - " + eventDetails + ". Monitoring...");
        }
    }
}

Custom Observer Example (Main)


public class CustomObserverDemo {
    public static void main(String[] args) {
        StockMarket market = new StockMarket();

        MyObserver display1 = new StockDisplay("User Dashboard");
        MyObserver display2 = new StockDisplay("Mobile App");
        MyObserver tradingBot = new TradingBot();

        // Register observers
        market.registerObserver(display1);
        market.registerObserver(display2);
        market.registerObserver(tradingBot);

        // Simulate stock price changes
        market.setStockPrice(100.50);
        market.setStockPrice(101.25);
        
        market.removeObserver(display1); // Unregister one observer

        market.setStockPrice(150.00); // This will trigger the trading bot action
    }
}

මේකේදී ඔයාලට පෙනෙයි අපිට තව Observers ලා ඕන තරම් එකතු කරන්නත්, අයින් කරන්නත් පුළුවන්. ඒ වගේම Subject එකට Observer ලා ගැන කිසිම විස්තරයක් දැනගන්න ඕන වෙන්නේ නැහැ. මේක තමයි Observer Pattern එකේ ලොකුම වාසිය.


Observer Pattern එකේ වාසි සහ අවාසි

වාසි (Pros)

  • Decoupling: Subject එකයි Observer ලයි අතර තියෙන සම්බන්ධය ගොඩක් ලිහිල් වෙනවා. Subject එකට Observer ලා ගැන දැනගන්න ඕන නැහැ, Observer ලටත් Subject එකේ අභ්‍යන්තර ක්‍රියාකාරිත්වය ගැන දැනගන්න ඕන නැහැ.
  • Scalability and Flexibility: අළුත් Observer කෙනෙක්ව එකතු කරන්න හරි, ඉවත් කරන්න හරි ගොඩක් ලේසියි. Subject class එකේ කිසිම වෙනසක් කරන්න ඕන වෙන්නේ නැහැ.
  • Reusability: Observer සහ Subject classes වෙන වෙනමම reuse කරන්න පුළුවන්.
  • Supports broadcast communication: එක event එකක් නිසා Observer ලා ගොඩකට notification යවන්න පුළුවන්.

අවාසි (Cons)

  • Notification Order: Observer ලාට notifications යන order එක ගැන සහතිකයක් නැහැ (Java's inbuilt Observable doesn't guarantee order, and our custom one depends on the List's iteration order).
  • Memory Leaks: Observer කෙනෙක්ව Subject එකෙන් unregister කරන්න අමතක වුණොත්, ඒ Observer object එක memory එකේ අනවශ්‍ය විදියට රඳා පැවතීම (memory leak) වෙන්න පුළුවන්, විශේෂයෙන්ම Short-lived Observers ලා ඉන්න applications වල.
  • Overhead for small applications: ගොඩක් පොඩි applications වලට මේ pattern එක ටිකක් සංකීර්ණ වෙන්න පුළුවන්.
  • Potential for performance issues: Observers ලා ගොඩක් ඉන්නකොට, notification process එකට performance overhead එකක් එන්න පුළුවන්.

නූතන Java වල Observer Pattern

දැන් කාලේ Java applications වල Observer Pattern එකේ concept එක විවිධ විදියට implement කරලා තියෙනවා. උදාහරණයක් විදියට:

  • PropertyChangeSupport: Java Swing / AWT applications වල event handling වලට බහුලව පාවිච්චි වෙනවා.
  • Event Bus Libraries: Guava's EventBus වගේ libraries වලින් publish-subscribe model එක පහසුවෙන් implement කරන්න පුළුවන්.
  • Reactive Programming Frameworks (RxJava, Project Reactor): මේවා Observer Pattern එකේ advanced form එකක්. මෙතනදී Observer ලා streams of data/events වලට subscribe වෙනවා. මේවා ගොඩක් complex asynchronous applications වලට පාවිච්චි වෙනවා.
  • Lambda Expressions: Custom Observer Pattern එකක් හදනකොට, Java 8 වල introduced වුණු Lambda expressions පාවිච්චි කරලා Observer implement කරන්න පුළුවන්. ඒකෙන් code එක තව ලස්සනට ලියන්න පුළුවන්.

කොහොම වුණත්, මේ හැම එකකම යටින් තියෙන්නේ මේ Observer Design Pattern එකේ මූලික සංකල්පයමයි. ඒ නිසා මේක තේරුම් ගන්න එකෙන් ඔයාලට ගොඩක් දේවල් තේරුම් ගන්න ලේසි වෙනවා.


අවසාන වශයෙන් (Conclusion)

හරි යාළුවනේ, මම හිතනවා ඔයාලට Observer Design Pattern එක ගැන හොඳ අවබෝධයක් ලැබෙන්න ඇති කියලා. මේක Java වල event-driven systems වලට නැතුවම බැරි Design Pattern එකක්. අපි මේකෙන් බැලුවේ Subject එකක වෙනස්කම් Observer ලා ගොඩකට notification කරන්න කොහොමද කියලා.

මේ pattern එක තේරුම් ගත්තම ඔයාලට Frameworks, Libraries සහ වෙනත් Design Patterns තේරුම් ගන්න ගොඩක් ලේසි වෙයි. මොකද ගොඩක් තැන් වල මේකේ variation එකක් පාවිච්චි කරනවා.

ඉතින් අනිවාර්යයෙන්ම මේ code examples ටික ඔයාලගේ IDE එකේ run කරලා බලන්න. පොඩි පොඩි වෙනස්කම් කරලා practice කරන්න. එතකොට තමා මේ concepts ඔලුවට හරියටම යන්නේ.

මේ ලිපිය ගැන ඔයාලට තියෙන අදහස්, ප්‍රශ්න පහළින් comment කරන්න. තව මොනවා ගැනද ඔයාලට දැනගන්න ඕන කියලා කියන්න. අපි ඊළඟ ලිපියකින් හමුවෙමු! Java වලට ජයවේවා!