पाठ 24 / 38

कम्पोज़िशन व अपरिवर्तनीय क्लास

कोड पुनः उपयोग के लिए कम्पोज़िशन बनाम इनहेरिटेंस तौलें, फिर एक सच में अपरिवर्तनीय क्लास डिज़ाइन करें जो थ्रेड्स में साझा करने के लिए सुरक्षित हो।

इनहेरिटेंस से अधिक कम्पोज़िशन

इनहेरिटेंस सबक्लास को पैरेंट के implementation से कसकर जोड़ता है — पैरेंट में बदलाव चुपचाप हर चाइल्ड को तोड़ सकता है। कम्पोज़िशन (दूसरे ऑब्जेक्ट को फ़ील्ड के रूप में रखना और उसे सौंपना) रिश्ते को स्पष्ट व बदलने योग्य रखता है, और सच्चे "is-a" न होने पर कोड पुनः उपयोग के लिए बेहतर डिफ़ॉल्ट है।

व्यवहार में डेलिगेशन

Playlist, ArrayList के स्टोरेज का पुनः उपयोग करता है बिना उसका पूरा (विशाल) पब्लिक API इनहेरिट किए — कॉलर को सिर्फ़ वही छोटा हिस्सा दिखता है जो Playlist उजागर करना चुनता है।

class Playlist {
    private final List<String> tracks = new ArrayList<>();  // composition

    void add(String track) { tracks.add(track); }
    String get(int i) { return tracks.get(i); }
    int size() { return tracks.size(); }
}

एक सच में अपरिवर्तनीय क्लास

क्लास को final बनाएँ, सभी फ़ील्ड private final रखें, इन्हें सिर्फ़ कंस्ट्रक्टर में सेट करें, कोई mutable फ़ील्ड सीधे उजागर न करें (कलेक्शन/array को अंदर-बाहर डिफ़ेंसिवली कॉपी करें), और कोई सेटर न दें।

public final class Point {
    private final int x, y;

    public Point(int x, int y) { this.x = x; this.y = y; }
    public int getX() { return x; }
    public int getY() { return y; }

    public Point translated(int dx, int dy) {
        return new Point(x + dx, y + dy);   // return a NEW instance
    }
}

अपरिवर्तनीयता क्यों फ़ायदेमंद है

अपरिवर्तनीय ऑब्जेक्ट अपने-आप थ्रेड-सुरक्षित होते हैं (कोई लॉक नहीं चाहिए — स्टेट कभी नहीं बदलता), HashMap की-key के रूप में सुरक्षित होते हैं, और समझने में आसान होते हैं। Java के अपने String, Integer, LocalDate इन्हीं कारणों से अपरिवर्तनीय हैं।