JavaRush /جاوا بلاگ /Random-UR /ڈیزائننگ کلاسز اور انٹرفیس (مضمون کا ترجمہ)
fatesha
سطح

ڈیزائننگ کلاسز اور انٹرفیس (مضمون کا ترجمہ)

گروپ میں شائع ہوا۔
ڈیزائننگ کلاسز اور انٹرفیس (مضمون کا ترجمہ) - 1

مواد

  1. تعارف
  2. انٹرفیس
  3. انٹرفیس مارکر
  4. فنکشنل انٹرفیس، جامد طریقے اور پہلے سے طے شدہ طریقے
  5. خلاصہ کلاسز
  6. ناقابل تغیر (مستقل) کلاسز
  7. گمنام کلاسز
  8. مرئیت
  9. وراثت
  10. کثیر وراثت
  11. وراثت اور ترکیب
  12. انکیپسولیشن
  13. آخری کلاسز اور طریقے
  14. اس کے بعد کیا ہے
  15. سورس کوڈ ڈاؤن لوڈ کریں۔

1. تعارف

اس سے کوئی فرق نہیں پڑتا ہے کہ آپ کونسی پروگرامنگ زبان استعمال کرتے ہیں (اور جاوا کوئی استثنا نہیں ہے)، اچھے ڈیزائن کے اصولوں پر عمل کرنا صاف، قابل فہم، اور قابل تصدیق کوڈ لکھنے کی کلید ہے۔ اور اسے دیرپا اور آسانی سے مسئلہ حل کرنے میں مدد کرنے کے لیے بھی بنائیں۔ ٹیوٹوریل کے اس حصے میں، ہم ان بنیادی تعمیراتی بلاکس پر بات کرنے جا رہے ہیں جو جاوا زبان فراہم کرتی ہے اور آپ کو ڈیزائن کے بہتر فیصلے کرنے میں مدد کرنے کے لیے ڈیزائن کے چند اصول متعارف کرائیں گے۔ مزید خاص طور پر، ہم پہلے سے طے شدہ طریقوں (جاوا 8 میں ایک نئی خصوصیت) کا استعمال کرتے ہوئے انٹرفیس اور انٹرفیس پر تبادلہ خیال کرنے جا رہے ہیں، خلاصہ اور آخری کلاسز، ناقابل تغیر کلاسز، وراثت، ساخت، اور مرئیت (یا رسائی) کے اصولوں پر نظر ثانی کرنے جا رہے ہیں جن پر ہم نے مختصراً چھوا۔ حصہ 1 سبق "آجیکٹس کو بنانے اور تباہ کرنے کا طریقہ" ۔

2. انٹرفیسز

آبجیکٹ پر مبنی پروگرامنگ میں، انٹرفیس کا تصور معاہدوں کی ترقی کی بنیاد بناتا ہے ۔ مختصر طور پر، انٹرفیس طریقوں (معاہدوں) کے ایک سیٹ کی وضاحت کرتے ہیں اور ہر ایک طبقے کو جو اس مخصوص انٹرفیس کے لیے سپورٹ کی ضرورت ہوتی ہے ان طریقوں کا نفاذ فراہم کرنا چاہیے: کافی آسان لیکن طاقتور خیال۔ بہت سی پروگرامنگ زبانوں کے انٹرفیس کسی نہ کسی شکل میں ہوتے ہیں، لیکن جاوا خاص طور پر اس کے لیے زبان کی مدد فراہم کرتا ہے۔ آئیے جاوا میں انٹرفیس کی ایک سادہ تعریف پر ایک نظر ڈالتے ہیں۔
package com.javacodegeeks.advanced.design;

public interface SimpleInterface {
void performAction();
}
اوپر کے ٹکڑوں میں، جس انٹرفیس کو ہم نے کال کیا ہے SimpleInterface، صرف ایک طریقہ کا اعلان کرتا ہے جسے کہتے ہیں performAction۔ انٹرفیس اور کلاسز کے درمیان بنیادی فرق یہ ہے کہ انٹرفیس اس بات کا خاکہ پیش کرتے ہیں کہ رابطہ کیا ہونا چاہیے (وہ ایک طریقہ کا اعلان کرتے ہیں)، لیکن ان کا نفاذ فراہم نہیں کرتے۔ تاہم، جاوا میں انٹرفیس زیادہ پیچیدہ ہو سکتے ہیں: ان میں نیسٹڈ انٹرفیس، کلاسز، شمار، تشریحات اور مستقل شامل ہو سکتے ہیں۔ مثال کے طور پر:
package com.javacodegeeks.advanced.design;

public interface InterfaceWithDefinitions {
    String CONSTANT = "CONSTANT";

    enum InnerEnum {
        E1, E2;
    }

    class InnerClass {
    }

    interface InnerInterface {
        void performInnerAction();
    }

    void performAction();
}
اس زیادہ پیچیدہ مثال میں، کئی پابندیاں ہیں جو انٹرفیس غیر مشروط طور پر گھوںسلا کی تعمیرات اور طریقہ کار کے اعلانات پر عائد کرتی ہیں، اور یہ جاوا کمپائلر کے ذریعے نافذ کی جاتی ہیں۔ سب سے پہلے، یہاں تک کہ اگر واضح طور پر اعلان نہ کیا گیا ہو، انٹرفیس میں ہر طریقہ کا اعلان عوامی ہے (اور صرف عوامی ہوسکتا ہے)۔ اس طرح مندرجہ ذیل طریقہ کے اعلانات برابر ہیں:
public void performAction();
void performAction();
یہ بات قابل ذکر ہے کہ انٹرفیس میں ہر ایک طریقہ کو واضح طور پر قرار دیا جاتا ہے abstract ، اور یہاں تک کہ یہ طریقہ کے اعلانات برابر ہیں:
public abstract void performAction();
public void performAction();
void performAction();
جہاں تک اعلان کردہ مستقل فیلڈز کا تعلق ہے، عوامی ہونے کے علاوہ ، وہ واضح طور پر جامد اور حتمی نشان زد بھی ہیں ۔ اس لیے درج ذیل اعلانات بھی مساوی ہیں:
String CONSTANT = "CONSTANT";
public static final String CONSTANT = "CONSTANT";
آخر میں، نیسٹڈ کلاسز، انٹرفیس، یا شمار، عوامی ہونے کے علاوہ ، بھی واضح طور پر جامد قرار دیے جاتے ہیں ۔ مثال کے طور پر، یہ اعلانات بھی اس کے برابر ہیں:
class InnerClass {
}

static class InnerClass {
}
آپ جو انداز منتخب کرتے ہیں وہ ذاتی ترجیح ہے، لیکن انٹرفیس کی ان سادہ خصوصیات کو جاننا آپ کو غیر ضروری ٹائپنگ سے بچا سکتا ہے۔

3. انٹرفیس مارکر

مارکر انٹرفیس ایک خاص قسم کا انٹرفیس ہے جس میں طریقے یا دیگر گھریلو تعمیرات نہیں ہوتے ہیں۔ جاوا لائبریری اس کی وضاحت کیسے کرتی ہے:
public interface Cloneable {
}
انٹرفیس مارکرز فی کس معاہدے نہیں ہیں، لیکن کلاس کے ساتھ کچھ مخصوص خصلتوں کو "منسلک کرنے" یا "وابستگی" کے لیے کسی حد تک مفید تکنیک ہیں۔ مثال کے طور پر، Cloneable کے حوالے سے ، کلاس کو کلون ایبل کے طور پر نشان زد کیا گیا ہے، لیکن جس طریقے سے اسے لاگو کیا جا سکتا ہے یا ہونا چاہیے وہ انٹرفیس کا حصہ نہیں ہے۔ انٹرفیس مارکر کی ایک اور بہت مشہور اور وسیع پیمانے پر استعمال ہونے والی مثال ہے Serializable:
public interface Serializable {
}
یہ انٹرفیس کلاس کو سیریلائزیشن اور ڈی سیریلائزیشن کے لیے موزوں قرار دیتا ہے، اور ایک بار پھر، یہ اس بات کی وضاحت نہیں کرتا ہے کہ اسے کیسے نافذ کیا جا سکتا ہے یا کیا جانا چاہیے۔ انٹرفیس مارکر آبجیکٹ اورینٹڈ پروگرامنگ میں اپنی جگہ رکھتے ہیں، حالانکہ وہ انٹرفیس کا معاہدہ ہونے کے بنیادی مقصد کو پورا نہیں کرتے ہیں۔ 

4. فنکشنل انٹرفیسز، ڈیفالٹ طریقے اور جامد طریقے

جاوا 8 کی ریلیز کے بعد سے، انٹرفیس نے کچھ بہت ہی دلچسپ نئی خصوصیات حاصل کی ہیں: جامد طریقے، طے شدہ طریقے، اور lambdas (فنکشنل انٹرفیس) سے خودکار تبدیلی۔ انٹرفیس سیکشن میں، ہم نے اس حقیقت پر زور دیا کہ جاوا میں انٹرفیس صرف طریقوں کا اعلان کر سکتے ہیں، لیکن ان کا نفاذ فراہم نہیں کرتے۔ پہلے سے طے شدہ طریقہ کے ساتھ، چیزیں مختلف ہوتی ہیں: ایک انٹرفیس پہلے سے طے شدہ مطلوبہ الفاظ کے ساتھ ایک طریقہ کو نشان زد کر سکتا ہے اور اس کے لیے ایک نفاذ فراہم کر سکتا ہے۔ مثال کے طور پر:
package com.javacodegeeks.advanced.design;

public interface InterfaceWithDefaultMethods {
    void performAction();

    default void performDefaulAction() {
        // Implementation here
    }
}
مثال کی سطح پر ہونے کی وجہ سے، ہر انٹرفیس کے نفاذ کے ذریعے پہلے سے طے شدہ طریقوں کو اوور رائیڈ کیا جا سکتا ہے، لیکن انٹرفیس میں اب جامد طریقے بھی شامل ہو سکتے ہیں، مثال کے طور پر: پیکیج com.javacodegeeks.advanced.design;
public interface InterfaceWithDefaultMethods {
    static void createAction() {
        // Implementation here
    }
}
یہ کہا جا سکتا ہے کہ انٹرفیس میں نفاذ فراہم کرنا معاہدہ پروگرامنگ کے پورے مقصد کو ناکام بنا دیتا ہے۔ لیکن اس کی بہت سی وجوہات ہیں جن کی وجہ سے یہ خصوصیات جاوا زبان میں متعارف کرائی گئیں اور اس سے کوئی فرق نہیں پڑتا ہے کہ وہ کتنے ہی مفید یا الجھے ہوئے ہیں، وہ آپ کے اور آپ کے استعمال کے لیے موجود ہیں۔ فنکشنل انٹرفیس ایک الگ کہانی ہیں اور زبان میں بہت مفید اضافہ ثابت ہوئے ہیں۔ بنیادی طور پر، ایک فنکشنل انٹرفیس ایک انٹرفیس ہے جس میں صرف ایک تجریدی طریقہ کا اعلان کیا گیا ہے۔ Runnableمعیاری لائبریری انٹرفیس اس تصور کی ایک بہت اچھی مثال ہے۔
@FunctionalInterface
public interface Runnable {
    void run();
}
جاوا کمپائلر فنکشنل انٹرفیس کے ساتھ مختلف طریقے سے برتاؤ کرتا ہے اور لیمبڈا فنکشن کو فنکشنل انٹرفیس کے نفاذ میں تبدیل کر سکتا ہے جہاں یہ سمجھ میں آتا ہے۔ آئیے درج ذیل فنکشن کی تفصیل پر غور کریں: 
public void runMe( final Runnable r ) {
    r.run();
}
اس فنکشن کو جاوا 7 اور اس سے نیچے میں کال کرنے کے لیے، انٹرفیس کا نفاذ فراہم کرنا ضروری ہے Runnable(مثال کے طور پر، گمنام کلاسز کا استعمال کرتے ہوئے)، لیکن جاوا 8 میں یہ کافی ہے کہ lambda نحو کا استعمال کرتے ہوئے run() طریقہ کا نفاذ فراہم کیا جائے:
runMe( () -> System.out.println( "Run!" ) );
مزید برآں، @FunctionalInterface تشریح (تشریحات کو ٹیوٹوریل کے حصہ 5 میں تفصیل سے شامل کیا جائے گا) اشارہ کرتا ہے کہ مرتب کرنے والا یہ جانچ سکتا ہے کہ آیا انٹرفیس میں صرف ایک تجریدی طریقہ ہے، لہذا مستقبل میں انٹرفیس میں کی جانے والی کوئی بھی تبدیلی اس مفروضے کی خلاف ورزی نہیں کرے گی۔ .

5. خلاصہ کلاسز

جاوا زبان کے ذریعہ تعاون یافتہ ایک اور دلچسپ تصور خلاصہ کلاسوں کا تصور ہے۔ خلاصہ کلاسیں کچھ حد تک جاوا 7 میں انٹرفیس سے ملتی جلتی ہیں اور جاوا 8 میں پہلے سے طے شدہ میتھڈ انٹرفیس کے بہت قریب ہیں۔ ریگولر کلاسز کے برعکس، ایک خلاصہ کلاس کو فوری طور پر نہیں بنایا جا سکتا، لیکن اسے ذیلی کلاس کیا جا سکتا ہے (مزید تفصیلات کے لیے وراثت کے سیکشن سے رجوع کریں)۔ مزید اہم بات یہ ہے کہ تجریدی کلاسوں میں تجریدی طریقے شامل ہو سکتے ہیں: ایک خاص قسم کا طریقہ جس پر عمل درآمد کے بغیر، بالکل ایک انٹرفیس کی طرح۔ مثال کے طور پر:
package com.javacodegeeks.advanced.design;

public abstract class SimpleAbstractClass {
    public void performAction() {
        // Implementation here
    }

    public abstract void performAnotherAction();
}
اس مثال میں، کلاس کو تجریدیSimpleAbstractClass قرار دیا گیا ہے اور اس میں ایک اعلان کردہ تجریدی طریقہ ہے۔ خلاصہ کلاسز بہت کارآمد ہیں؛ عمل درآمد کی تفصیلات کے زیادہ تر یا کچھ حصوں کو بہت سے ذیلی طبقات میں شیئر کیا جا سکتا ہے۔ چاہے جیسا بھی ہو، وہ اب بھی دروازے کو چھوڑ دیتے ہیں اور آپ کو تجریدی طریقوں کا استعمال کرتے ہوئے ہر ذیلی طبقے میں موروثی رویے کو اپنی مرضی کے مطابق کرنے کی اجازت دیتے ہیں۔ یہ بات قابل ذکر ہے کہ انٹرفیس کے برعکس، جو صرف عوامی اعلانات پر مشتمل ہو سکتا ہے، تجریدی کلاسز کسی تجریدی طریقہ کی مرئیت کو کنٹرول کرنے کے لیے رسائی کے قواعد کی پوری طاقت کا استعمال کر سکتی ہیں۔

6. فوری کلاسز

آج کل سافٹ ویئر ڈویلپمنٹ میں تغیر پذیری زیادہ سے زیادہ اہم ہوتی جارہی ہے۔ ملٹی کور سسٹمز کے عروج نے ڈیٹا شیئرنگ اور ہم آہنگی سے متعلق بہت سے مسائل کو جنم دیا ہے۔ لیکن ایک مسئلہ ضرور پیدا ہوا ہے: بہت کم (یا یہاں تک کہ کوئی بھی) متغیر حالت کا ہونا بہتر توسیع پذیری (اسکیل ایبلٹی) اور سسٹم کے بارے میں آسان استدلال کا باعث بنتا ہے۔ بدقسمتی سے، جاوا زبان طبقاتی تبدیلی کے لیے معقول مدد فراہم نہیں کرتی ہے۔ تاہم، تکنیکوں کے امتزاج کا استعمال کرتے ہوئے، ایسی کلاسوں کو ڈیزائن کرنا ممکن ہو جاتا ہے جو ناقابل تغیر ہوں۔ سب سے پہلے، کلاس کے تمام فیلڈز فائنل ہونے چاہئیں ( فائنل کے بطور نشان زد )۔ یہ ایک اچھی شروعات ہے، لیکن اس کی کوئی ضمانت نہیں ہے۔ 
package com.javacodegeeks.advanced.design;

import java.util.Collection;

public class ImmutableClass {
    private final long id;
    private final String[] arrayOfStrings;
    private final Collection<String> collectionOfString;
}
دوم، مناسب ابتداء کو یقینی بنائیں: اگر کوئی فیلڈ کسی مجموعہ یا صف کا حوالہ ہے، تو ان فیلڈز کو کنسٹرکٹر آرگیومنٹس سے براہ راست تفویض نہ کریں، اس کے بجائے کاپیاں بنائیں۔ یہ اس بات کو یقینی بنائے گا کہ مجموعہ یا صف کی حالت اس سے باہر تبدیل نہیں ہوئی ہے۔
public ImmutableClass( final long id, final String[] arrayOfStrings,
        final Collection<String> collectionOfString) {
    this.id = id;
    this.arrayOfStrings = Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
    this.collectionOfString = new ArrayList<>( collectionOfString );
}
اور آخر کار، مناسب رسائی (گیٹرز) کو یقینی بنانا۔ مجموعوں کے لیے، ناقابل تغیر کو ایک ریپر کے طور پر فراہم کیا جانا چاہیے  Collections.unmodifiableXxx: صفوں کے ساتھ، حقیقی تغیر پذیری فراہم کرنے کا واحد طریقہ یہ ہے کہ صف کا حوالہ واپس کرنے کے بجائے ایک کاپی فراہم کی جائے۔ یہ عملی نقطہ نظر سے قابل قبول نہیں ہوسکتا ہے، کیونکہ یہ صف کے سائز پر بہت زیادہ منحصر ہے اور کوڑا اٹھانے والے پر بہت زیادہ دباؤ ڈال سکتا ہے۔
public String[] getArrayOfStrings() {
    return Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
}
یہاں تک کہ اس چھوٹی سی مثال سے بھی ایک اچھا اندازہ ہوتا ہے کہ جاوا میں ابھی تک ناقابل تبدیلی پہلی کلاس کا شہری نہیں ہے۔ چیزیں پیچیدہ ہو سکتی ہیں اگر کسی غیر متغیر کلاس میں کوئی فیلڈ ہو جو کسی دوسرے طبقے کی چیز کا حوالہ دیتی ہو۔ ان کلاسوں کو بھی ناقابل تغیر ہونا چاہئے، لیکن اس کو یقینی بنانے کا کوئی طریقہ نہیں ہے۔ جاوا کے کئی اچھے سورس کوڈ تجزیہ کار ہیں، جیسے FindBugs اور PMD، جو آپ کے کوڈ کو چیک کرکے اور جاوا پروگرامنگ کی عام خامیوں کی نشاندہی کرکے بہت مدد کرسکتے ہیں۔ یہ ٹولز کسی بھی جاوا ڈویلپر کے بہترین دوست ہیں۔

7. گمنام کلاسز

جاوا 8 سے پہلے کے دور میں، گمنام کلاسز ہی اس بات کو یقینی بنانے کا واحد طریقہ تھا کہ کلاسز کی فلائی پر تعریف کی گئی تھی اور فوری طور پر ان کو شروع کیا گیا تھا۔ گمنام کلاسز کا مقصد بوائلر پلیٹ کو کم کرنا اور ریکارڈ کے طور پر کلاسز کی نمائندگی کا مختصر اور آسان طریقہ فراہم کرنا تھا۔ آئیے جاوا میں ایک نیا دھاگہ پیدا کرنے کے عام پرانے زمانے کے طریقے پر ایک نظر ڈالتے ہیں:
package com.javacodegeeks.advanced.design;

public class AnonymousClass {
    public static void main( String[] args ) {
        new Thread(
            // Example of creating anonymous class which implements
            // Runnable interface
            new Runnable() {
                @Override
                public void run() {
                    // Implementation here
                }
            }
        ).start();
    }
}
اس مثال میں، انٹرفیس کا نفاذ Runnableفوری طور پر ایک گمنام کلاس کے طور پر فراہم کیا جاتا ہے۔ اگرچہ گمنام کلاسز کے ساتھ کچھ حدود وابستہ ہیں، لیکن ان کے استعمال کے بنیادی نقصانات انتہائی لفظی ساختی نحو ہیں جس کا جاوا بطور زبان پابند ہے۔ یہاں تک کہ صرف ایک گمنام کلاس جو کچھ نہیں کرتی ہے ہر بار لکھنے پر کم از کم 5 لائنوں کوڈ کی ضرورت ہوتی ہے۔
new Runnable() {
   @Override
   public void run() {
   }
}
خوش قسمتی سے، جاوا 8، لیمبڈا اور فنکشنل انٹرفیس کے ساتھ، یہ تمام دقیانوسی تصورات جلد ہی ختم ہو جائیں گے، آخر میں جاوا کوڈ لکھنا واقعی جامع نظر آئے گا۔
package com.javacodegeeks.advanced.design;

public class AnonymousClass {
    public static void main( String[] args ) {
        new Thread( () -> { /* Implementation here */ } ).start();
    }
}

8. مرئیت

ہم پہلے ہی سبق کے حصہ 1 میں جاوا میں مرئیت اور رسائی کے قواعد کے بارے میں تھوڑی بات کر چکے ہیں۔ اس حصے میں، ہم اس موضوع پر دوبارہ غور کرنے جا رہے ہیں، لیکن ذیلی طبقے کے تناظر میں۔ ڈیزائننگ کلاسز اور انٹرفیس (مضمون کا ترجمہ) - 2مختلف سطحوں پر مرئیت کلاسوں کو دوسری کلاسز یا انٹرفیس دیکھنے سے روکتی ہے یا روکتی ہے (مثال کے طور پر، اگر وہ مختلف پیکجوں میں ہیں یا ایک دوسرے کے اندر اندر ہیں) یا ذیلی کلاسوں کو اپنے والدین کے طریقوں، تعمیر کنندگان اور فیلڈز کو دیکھنے اور ان تک رسائی حاصل کرنے سے روکتی ہے۔ اگلے حصے میں، وراثت، ہم اسے عمل میں دیکھیں گے۔

9. وراثت

وراثت آبجیکٹ اورینٹڈ پروگرامنگ کے کلیدی تصورات میں سے ایک ہے، جو کہ رشتوں کے طبقے کی تعمیر کی بنیاد کے طور پر کام کرتا ہے۔ مرئیت اور رسائی کے قواعد کے ساتھ مل کر، وراثت کلاسوں کو ایک درجہ بندی میں ڈیزائن کرنے کی اجازت دیتی ہے جسے بڑھایا اور برقرار رکھا جا سکتا ہے۔ تصوراتی سطح پر، جاوا میں وراثت کو پیرنٹ کلاس کے ساتھ ذیلی کلاسنگ اور توسیعی مطلوبہ الفاظ کا استعمال کرتے ہوئے لاگو کیا جاتا ہے۔ ذیلی طبقے کو پیرنٹ کلاس کے تمام عوامی اور محفوظ عناصر وراثت میں ملتا ہے۔ مزید برآں، اگر دونوں (ذیلی طبقے اور کلاس) ایک ہی پیکج میں ہوں تو ذیلی طبقے کو اس کے پیرنٹ کلاس کے پیکیج-پرائیویٹ عناصر کا وراثت ملتا ہے۔ یہ کہا جا رہا ہے، یہ بہت اہم ہے، چاہے آپ جو بھی ڈیزائن کرنے کی کوشش کر رہے ہوں، ان طریقوں کے کم از کم سیٹ پر قائم رہنا جن کو ایک طبقہ عوامی طور پر یا اس کے ذیلی طبقات کے سامنے لاتا ہے۔ مثال کے طور پر، آئیے مرئیت کی سطحوں اور ان کے اثرات میں فرق کو ظاہر کرنے کے لیے کلاس Parentاور اس کے ذیلی طبقے کو دیکھیں۔Child
package com.javacodegeeks.advanced.design;

public class Parent {
    // Everyone can see it
    public static final String CONSTANT = "Constant";

    // No one can access it
    private String privateField;
    // Only subclasses can access it
    protected String protectedField;

    // No one can see it
    private class PrivateClass {
    }

    // Only visible to subclasses
    protected interface ProtectedInterface {
    }

    // Everyone can call it
    public void publicAction() {
    }

    // Only subclass can call it
    protected void protectedAction() {
    }

    // No one can call it
    private void privateAction() {
    }

    // Only subclasses in the same package can call it
    void packageAction() {
    }
}
package com.javacodegeeks.advanced.design;

// Resides in the same package as parent class
public class Child extends Parent implements Parent.ProtectedInterface {
    @Override
    protected void protectedAction() {
        // Calls parent's method implementation
        super.protectedAction();
    }

    @Override
    void packageAction() {
        // Do nothing, no call to parent's method implementation
    }

    public void childAction() {
        this.protectedField = "value";
    }
}
وراثت اپنے آپ میں ایک بہت بڑا موضوع ہے، جس میں جاوا سے متعلق بہت سی باریک تفصیلات ہیں۔ تاہم، کچھ اصول ایسے ہیں جن پر عمل کرنا آسان ہے اور طبقاتی درجہ بندی کے اختصار کو برقرار رکھنے میں بہت آگے جا سکتے ہیں۔ جاوا میں، ہر ذیلی طبقہ اپنے والدین کے وراثتی طریقوں کو اوور رائیڈ کر سکتا ہے جب تک کہ اسے حتمی قرار نہ دیا جائے۔ تاہم، کسی طریقہ کو اوور رائیڈڈ کے بطور نشان زد کرنے کے لیے کوئی خاص نحو یا کلیدی لفظ نہیں ہے، جو الجھن کا باعث بن سکتا ہے۔ اسی لیے @Override تشریح متعارف کرائی گئی : جب بھی آپ کا مقصد وراثتی طریقہ کو اوور رائیڈ کرنا ہو، براہ کرم @Override تشریح کو مختصر طور پر اس کی نشاندہی کرنے کے لیے استعمال کریں۔ ایک اور مخمصہ جس کا جاوا ڈویلپرز کو ڈیزائن میں مسلسل سامنا کرنا پڑتا ہے وہ ہے انٹرفیس کے نفاذ کے مقابلے میں طبقاتی درجہ بندی (کنکریٹ یا تجریدی کلاسوں کے ساتھ) کی تعمیر۔ ہم پرزور مشورہ دیتے ہیں کہ جب بھی ممکن ہو کلاسوں یا تجریدی کلاسوں پر انٹرفیس کی حمایت کریں۔ انٹرفیس ہلکے ہیں، جانچنے اور برقرار رکھنے میں آسان ہیں، اور نفاذ کی تبدیلیوں کے ضمنی اثرات کو بھی کم کرتے ہیں۔ پروگرامنگ کی بہت سی جدید تکنیکیں، جیسے جاوا معیاری لائبریری میں پراکسی کلاسز بنانا، انٹرفیس پر بہت زیادہ انحصار کرتے ہیں۔

10. متعدد وراثت

C++ اور کچھ دوسری زبانوں کے برعکس، جاوا ایک سے زیادہ وراثت کی حمایت نہیں کرتا: جاوا میں، ہر کلاس کا صرف ایک براہ راست والدین ہو سکتا ہے (کلاس کے ساتھ Objectدرجہ بندی کے اوپری حصے میں)۔ تاہم، ایک کلاس ایک سے زیادہ انٹرفیس کو نافذ کر سکتی ہے، اور اس طرح جاوا میں ایک سے زیادہ وراثت کو حاصل کرنے (یا نقلی) کرنے کا واحد طریقہ انٹرفیس اسٹیکنگ ہے۔
package com.javacodegeeks.advanced.design;

public class MultipleInterfaces implements Runnable, AutoCloseable {
    @Override
    public void run() {
        // Some implementation here
    }

    @Override
    public void close() throws Exception {
       // Some implementation here
    }
}
ایک سے زیادہ انٹرفیس کو نافذ کرنا دراصل کافی طاقتور ہے، لیکن اکثر اس عمل کو بار بار استعمال کرنے کی ضرورت جاوا کے متعدد وراثت کے لیے حمایت کی کمی کو دور کرنے کے لیے گہری طبقاتی درجہ بندی کی طرف لے جاتی ہے۔ 
public class A implements Runnable {
    @Override
    public void run() {
        // Some implementation here
    }
}
// Class B wants to inherit the implementation of run() method from class A.
public class B extends A implements AutoCloseable {
    @Override
    public void close() throws Exception {
       // Some implementation here
    }
}
// Class C wants to inherit the implementation of run() method from class A
// and the implementation of close() method from class B.
public class C extends B implements Readable {
    @Override
    public int read(java.nio.CharBuffer cb) throws IOException {
       // Some implementation here
    }
}
اور اسی طرح... جاوا 8 کی حالیہ ریلیز کسی حد تک پہلے سے طے شدہ طریقہ انجیکشن کے مسئلے کو حل کرتی ہے۔ پہلے سے طے شدہ طریقوں کی وجہ سے، انٹرفیس دراصل نہ صرف ایک معاہدہ فراہم کرتے ہیں، بلکہ عمل درآمد بھی کرتے ہیں۔ لہذا، ان انٹرفیس کو لاگو کرنے والی کلاسیں بھی خود بخود ان نافذ شدہ طریقوں کی وارث ہوں گی۔ مثال کے طور پر:
package com.javacodegeeks.advanced.design;

public interface DefaultMethods extends Runnable, AutoCloseable {
    @Override
    default void run() {
        // Some implementation here
    }

    @Override
    default void close() throws Exception {
       // Some implementation here
    }
}

// Class C inherits the implementation of run() and close() methods from the
// DefaultMethods interface.
public class C implements DefaultMethods, Readable {
    @Override
    public int read(java.nio.CharBuffer cb) throws IOException {
       // Some implementation here
    }
}
ذہن میں رکھیں کہ ایک سے زیادہ وراثت ایک بہت طاقتور ہے، لیکن ایک ہی وقت میں خطرناک آلہ ہے. معروف ڈائمنڈ آف ڈیتھ کے مسئلے کو اکثر متعدد وراثت کے نفاذ میں ایک بڑی خامی کے طور پر پیش کیا جاتا ہے، جس سے ڈویلپرز کو طبقاتی درجہ بندی کو بہت احتیاط سے ڈیزائن کرنے پر مجبور کیا جاتا ہے۔ بدقسمتی سے، پہلے سے طے شدہ طریقوں کے ساتھ Java 8 انٹرفیس بھی ان نقائص کا شکار ہوتے ہیں۔
interface A {
    default void performAction() {
    }
}

interface B extends A {
    @Override
    default void performAction() {
    }
}

interface C extends A {
    @Override
    default void performAction() {
    }
}
مثال کے طور پر، درج ذیل کوڈ کا ٹکڑا مرتب کرنے میں ناکام ہو جائے گا:
// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}
اس مقام پر، یہ کہنا مناسب ہے کہ جاوا نے بطور زبان ہمیشہ آبجیکٹ اورینٹڈ پروگرامنگ کے کونے کے معاملات سے بچنے کی کوشش کی ہے، لیکن جیسے جیسے زبان تیار ہوتی ہے، ان میں سے کچھ معاملات اچانک ظاہر ہونا شروع ہو گئے ہیں۔ 

11. وراثت اور تشکیل

خوش قسمتی سے، وراثت ہی آپ کی کلاس کو ڈیزائن کرنے کا واحد طریقہ نہیں ہے۔ ایک اور متبادل جس کے بارے میں بہت سے ڈویلپرز کا خیال ہے کہ وراثت سے بہت بہتر ہے وہ ہے ساخت۔ خیال بہت آسان ہے: کلاسوں کا درجہ بندی بنانے کے بجائے، انہیں دوسری کلاسوں پر مشتمل ہونے کی ضرورت ہے۔ آئیے اس مثال کو دیکھتے ہیں:
// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}
کلاس Vehicleایک انجن اور پہیوں پر مشتمل ہے (علاوہ بہت سے دوسرے حصے جو سادگی کے لیے ایک طرف رہ گئے ہیں)۔ تاہم، یہ کہا جا سکتا ہے کہ کلاس Vehicleبھی ایک انجن ہے، لہذا اسے وراثت کا استعمال کرتے ہوئے ڈیزائن کیا جا سکتا ہے. 
public class Vehicle extends Engine {
    private Wheels[] wheels;
    // ...
}
کون سا ڈیزائن حل درست ہوگا؟ عمومی بنیادی ہدایات کو IS-A (is) اور HAS-A (مشتمل) اصولوں کے نام سے جانا جاتا ہے۔ IS-A ایک وراثت کا رشتہ ہے: ایک ذیلی طبقہ پیرنٹ کلاس کی کلاس کی تفصیلات اور پیرنٹ کلاس کے تغیر کو بھی پورا کرتا ہے۔ ذیلی کلاس) اپنے پیرنٹ کو بڑھاتا ہے۔ اگر آپ جاننا چاہتے ہیں کہ آیا ایک ہستی دوسری کو بڑھاتی ہے، تو میچ ٹیسٹ کریں - IS -A (ہے)۔") لہذا، HAS-A ایک مرکب رشتہ ہے: ایک طبقہ ایک ایسی چیز کا مالک ہے (یا اس پر مشتمل ہے) جو زیادہ تر معاملات میں، HAS-A اصول متعدد وجوہات کی بناء پر IS-A سے بہتر کام کرتا ہے: 
  • ڈیزائن زیادہ لچکدار ہے؛
  • ماڈل زیادہ مستحکم ہے کیونکہ تبدیلی طبقاتی درجہ بندی کے ذریعے نہیں پھیلتی ہے۔
  • ایک کلاس اور اس کی ساخت کو کمپوزیشن کے مقابلے میں ڈھیلے طریقے سے جوڑا جاتا ہے، جو والدین اور اس کے ذیلی طبقے کو مضبوطی سے جوڑتا ہے۔
  • کلاس میں سوچ کی منطقی ٹرین آسان ہے، کیونکہ اس کے تمام انحصار اس میں ایک جگہ شامل ہیں۔ 
قطع نظر، وراثت اپنی جگہ ہے اور مختلف طریقوں سے موجودہ ڈیزائن کے متعدد مسائل کو حل کرتی ہے، اس لیے اسے نظرانداز نہیں کیا جانا چاہیے۔ اپنے آبجیکٹ پر مبنی ماڈل کو ڈیزائن کرتے وقت براہ کرم ان دو متبادلات کو ذہن میں رکھیں۔

12. انکیپسولیشن۔

آبجیکٹ اورینٹڈ پروگرامنگ میں انکیپسولیشن کا تصور تمام نفاذ کی تفصیلات (جیسے آپریٹنگ موڈ، اندرونی طریقے وغیرہ) کو بیرونی دنیا سے چھپانا ہے۔ انکیپسولیشن کے فوائد برقرار رکھنے اور تبدیلی میں آسانی ہیں۔ کلاس کا اندرونی نفاذ پوشیدہ ہے، کلاس ڈیٹا کے ساتھ کام کرنا خاص طور پر کلاس کے عوامی طریقوں سے ہوتا ہے (ایک حقیقی مسئلہ اگر آپ لائبریری یا فریم ورک تیار کر رہے ہیں جسے بہت سے لوگ استعمال کرتے ہیں)۔ جاوا میں انکیپسولیشن مرئیت اور رسائی کے قواعد کے ذریعے حاصل کی جاتی ہے۔ جاوا میں، یہ بہترین عمل سمجھا جاتا ہے کہ کبھی بھی فیلڈز کو براہ راست ظاہر نہ کریں، صرف گیٹرز اور سیٹرز کے ذریعے (جب تک کہ فیلڈز کو حتمی نشان زد نہ کیا جائے)۔ مثال کے طور پر:
package com.javacodegeeks.advanced.design;

public class Encapsulation {
    private final String email;
    private String address;

    public Encapsulation( final String email ) {
        this.email = email;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }
}
یہ مثال اس کی یاد تازہ کرتی ہے جسے جاوا زبان میں JavaBeans کہا جاتا ہے: معیاری جاوا کلاسز کنونشنوں کے ایک سیٹ کے مطابق لکھی جاتی ہیں، جن میں سے ایک فیلڈز تک رسائی حاصل کرنے کی اجازت دیتا ہے صرف گیٹر اور سیٹٹر طریقوں سے۔ جیسا کہ ہم نے وراثت کے سیکشن میں پہلے ہی زور دیا ہے، براہ کرم ہمیشہ انکیپسولیشن کے اصولوں کا استعمال کرتے ہوئے کلاس میں کم از کم پبلسٹی کنٹریکٹ پر عمل کریں۔ ہر وہ چیز جو عوامی نہیں ہونی چاہیے وہ پرائیویٹ ہو جائے (یا محفوظ/پیکیج پرائیویٹ، اس مسئلے پر منحصر ہے جسے آپ حل کر رہے ہیں)۔ یہ آپ کو بغیر کسی تبدیلی کے (یا کم از کم کم سے کم) ڈیزائن کرنے کی آزادی دے کر طویل مدت میں ادائیگی کرے گا۔ 

13. فائنل کلاسز اور طریقے

جاوا میں، ایک کلاس کو دوسری کلاس کی ذیلی کلاس بننے سے روکنے کا ایک طریقہ ہے: دوسری کلاس کو حتمی قرار دیا جانا چاہیے۔ 
package com.javacodegeeks.advanced.design;

public final class FinalClass {
}
میتھڈ ڈیکلریشن میں  وہی حتمی کلیدی لفظ ذیلی طبقات کو طریقہ کو اوور رائیڈ کرنے سے روکتا ہے۔
package com.javacodegeeks.advanced.design;

public class FinalMethod {
    public final void performAction() {
    }
}
یہ فیصلہ کرنے کے لیے کوئی عمومی اصول نہیں ہیں کہ آیا کوئی کلاس یا طریقہ حتمی ہونا چاہیے یا نہیں۔ آخری کلاسز اور طریقے توسیع پذیری کو محدود کرتے ہیں اور آگے یہ سوچنا بہت مشکل ہے کہ آیا کسی طبقے کو وراثت میں ملنا چاہیے یا نہیں، یا مستقبل میں کسی طریقہ کو اوور رائڈ کیا جانا چاہیے یا نہیں۔ یہ خاص طور پر لائبریری ڈویلپرز کے لیے اہم ہے، کیونکہ اس طرح کے ڈیزائن کے فیصلے لائبریری کے قابل اطلاق کو نمایاں طور پر محدود کر سکتے ہیں۔ جاوا اسٹینڈرڈ لائبریری میں فائنل کلاسز کی کئی مثالیں ہیں، جن میں سب سے مشہور سٹرنگ کلاس ہے۔ ابتدائی مرحلے میں، یہ فیصلہ ڈویلپرز کی جانب سے سٹرنگ کو لاگو کرنے کے لیے اپنے، "بہتر" حل کے ساتھ آنے کی کسی بھی کوشش کو روکنے کے لیے کیا گیا تھا۔ 

14. آگے کیا ہے۔

سبق کے اس حصے میں، ہم نے جاوا میں آبجیکٹ پر مبنی پروگرامنگ کے تصورات کا احاطہ کیا۔ ہم نے کنٹریکٹ پروگرامنگ پر بھی ایک سرسری نظر ڈالی، کچھ عملی تصورات کو چھوتے ہوئے اور یہ دیکھتے ہوئے کہ وقت کے ساتھ ساتھ زبان کیسے تیار ہوئی ہے۔ اسباق کے اگلے حصے میں، ہم جنرک سے ملنے جا رہے ہیں اور یہ کہ وہ پروگرامنگ میں ٹائپ سیفٹی تک پہنچنے کے طریقے کو کیسے بدلتے ہیں۔ 

15. سورس کوڈ ڈاؤن لوڈ کریں۔

آپ ماخذ کو یہاں سے ڈاؤن لوڈ کر سکتے ہیں - Advanced-java-part-3 ماخذ: کلاسز کو کیسے ڈیزائن کریں۔
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION