JavaRush /جاوا بلاگ /Random-UR /جاوا میں ایک سے زیادہ وراثت۔ ساخت اور وراثت کا موازنہ
HonyaSaar
سطح
Москва

جاوا میں ایک سے زیادہ وراثت۔ ساخت اور وراثت کا موازنہ

گروپ میں شائع ہوا۔
کچھ عرصہ پہلے میں نے جاوا میں وراثت، انٹرفیس اور کمپوزیشن کے بارے میں کئی پوسٹس لکھی تھیں۔ اس مضمون میں، ہم ایک سے زیادہ وراثت کو دیکھیں گے اور پھر وراثت پر مرکب کے فوائد کے بارے میں جانیں گے۔
جاوا میں ایک سے زیادہ وراثت۔  ترکیب اور وراثت کا موازنہ - 1

جاوا میں ایک سے زیادہ وراثت

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

"ہیرے کا مسئلہ"

ہیرے کے مسئلے کو زیادہ آسانی سے سمجھنے کے لیے، آئیے فرض کریں کہ جاوا میں ایک سے زیادہ وراثت کی حمایت کی گئی ہے۔ اس صورت میں، ہم ذیل کے اعداد و شمار میں دکھائے گئے درجہ بندی کے ساتھ کلاسز حاصل کر سکتے ہیں۔ ڈائمنڈ کلاس کا درجہ بندیآئیے فرض کریں کہ یہ SuperClassایک تجریدی کلاس ہے جو ایک مخصوص طریقہ کو بیان کرتی ہے، اور کلاسز ClassAاور ClassBحقیقی کلاسز ہیں۔ SuperClass.java
package com.journaldev.inheritance;
public abstract class SuperClass {
   	public abstract void doSomething();
}
ClassA.java
package com.journaldev.inheritance;
public class ClassA extends SuperClass{
    @Override
 public void doSomething(){
        System.out.println("Какая-то реализация класса A");
    }
  //собственный метод класса  ClassA
    public void methodA(){
    }
}
اب، فرض کرتے ہیں کہ کلاس ایک ہی وقت سے اور ایک ہی وقت میں ClassCوراثت میں ملتی ہے ، اور ایک ہی وقت میں مندرجہ ذیل عمل درآمد ہوتا ہے: ClassA ClassB
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
    public void test(){
        //вызов метода родительского класса
        doSomething();
    }
}
نوٹ کریں کہ طریقہ پیرنٹ کلاس کا test()ایک طریقہ کہتا ہے ، جو ابہام کا باعث بنے گا کیونکہ مرتب کرنے والا نہیں جانتا کہ کس سپر کلاس طریقہ کو بلایا جائے۔ doSomething()اس صورت حال میں طبقاتی وراثت کے خاکے کی شکل کی وجہ سے، جو کہ ایک پہلو والے ہیرے کے خاکہ سے مشابہ ہے، اس مسئلے کو "ڈائمنڈ پرابلم" کہا جاتا ہے۔ یہ بنیادی وجہ ہے کہ جاوا متعدد طبقاتی وراثت کی حمایت نہیں کرتا ہے۔ نوٹ کریں کہ ایک سے زیادہ کلاس وراثت کے ساتھ یہ مسئلہ تین کلاسوں کے ساتھ بھی ہوسکتا ہے جن میں کم از کم ایک مشترکہ طریقہ ہے۔

متعدد وراثت اور انٹرفیس

آپ نے محسوس کیا ہوگا کہ میں ہمیشہ کہتا ہوں کہ "متعدد وراثت کلاسوں کے درمیان تعاون یافتہ نہیں ہے"، لیکن یہ انٹرفیس کے درمیان تعاون یافتہ ہے۔ ایک سادہ مثال ذیل میں دکھایا گیا ہے: InterfaceA.java
package com.journaldev.inheritance;
public interface InterfaceA {

    public void doSomething();
}
InterfaceB.java
package com.journaldev.inheritance;

public interface InterfaceB {

    public void doSomething();
}
نوٹ کریں کہ دونوں انٹرفیس کا ایک ہی نام کا طریقہ ہے۔ اب ہم کہتے ہیں کہ ہمارے پاس ایک انٹرفیس ہے جو دونوں انٹرفیس سے وراثت میں ملتا ہے۔ InterfaceC.java
package com.journaldev.inheritance;

public interface InterfaceC extends InterfaceA, InterfaceB {

    //метод, с тем же названием описан в  InterfaceA и InterfaceB
    public void doSomething();
یہاں، سب کچھ مثالی ہے، کیونکہ انٹرفیسز صرف ایک طریقہ کی ریزرویشن/تفصیل ہیں، اور طریقہ کار کا نفاذ خود اس کنکریٹ کلاس میں ہوگا جو ان انٹرفیس کو لاگو کرتا ہے، لہذا انٹرفیس کی متعدد وراثت کے ساتھ ابہام کا سامنا کرنے کا کوئی امکان نہیں ہے۔ یہی وجہ ہے کہ جاوا میں کلاسیں متعدد انٹرفیس سے وراثت میں مل سکتی ہیں۔ آئیے اسے ذیل کی مثال کے ساتھ دکھائیں۔ InterfacesImpl.java
package com.journaldev.inheritance;

public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {

    @Override
    public void doSomething() {
        System.out.println("doSomething реализация реального класса ");
    }

    public static void main(String[] args) {
        InterfaceA objA = new InterfacesImpl();
        InterfaceB objB = new InterfacesImpl();
        InterfaceC objC = new InterfacesImpl();

        //все вызываемые ниже методы получат одинаковую реализацию конкретного класса

        objA.doSomething();
        objB.doSomething();
        objC.doSomething();
    }
}
آپ نے دیکھا ہوگا کہ جب بھی میں سپر کلاس یا انٹرفیس میں بیان کردہ طریقہ کو اوور رائیڈ کرتا ہوں، میں @Override تشریح استعمال کرتا ہوں۔ یہ تین بلٹ ان جاوا تشریحات میں سے ایک ہے اور طریقوں کو اوور رائیڈ کرتے وقت آپ کو اسے ہمیشہ استعمال کرنا چاہیے۔

نجات کے طور پر مرکب

methodA()تو کیا ہوگا اگر ہم کلاس ClassAاور methodB()کلاس فنکشن ClassBکو استعمال کرنا چاہتے ہیں ClassС؟ اس کا حل کمپوزیشن ہو سکتا ہے - ایک دوبارہ لکھا ہوا ورژن ClassCجو دونوں طبقاتی طریقوں کو نافذ کرتا ہے ClassAاور اس میں کسی ایک چیز کے لیے ClassBبھی عمل درآمد ہوتا ہے ۔ doSomething() ClassC.java
package com.journaldev.inheritance;

public class ClassC{

    ClassA objA = new ClassA();
    ClassB objB = new ClassB();

    public void test(){
        objA.doSomething();
    }

    public void methodA(){
        objA.methodA();
    }

    public void methodB(){
        objB.methodB();
    }
}

ساخت یا وراثت؟

وراثت پر کمپوزیشن سے فائدہ اٹھانا جاوا پروگرامنگ کی اچھی پریکٹس ہے۔ ہم اس نقطہ نظر کے حق میں کچھ پہلوؤں کا جائزہ لیں گے۔
  1. فرض کریں کہ ہمارے پاس والدین کے وارث کی کلاسوں کا مندرجہ ذیل مجموعہ ہے:

    ClassC.java

    package com.journaldev.inheritance;
    
    public class ClassC{
    
    public void methodC(){
      	}
    
    }

    ClassD.java

    package com.journaldev.inheritance;
    
    public class ClassD extends ClassC{
    
        public int test(){
            return 0;
        }
    }

    مندرجہ بالا کوڈ مرتب کرتا ہے اور ٹھیک کام کرتا ہے، لیکن کیا ہوگا اگر ClassCاسے مختلف طریقے سے لاگو کیا جائے:

    package com.journaldev.inheritance;
    
    public class ClassC{
    
        public void methodC(){
        }
    
        public void test(){
        }
    }

    نوٹ کریں کہ طریقہ test()ڈیسنڈنٹ کلاس میں پہلے سے موجود ہے، لیکن ایک مختلف قسم کا نتیجہ لوٹاتا ہے۔ اب ClassD، اگر آپ IDE استعمال کر رہے ہیں، تو یہ مرتب نہیں ہوگا۔ آپ کو ڈیسنڈنٹ یا سپر کلاس میں واپسی کی قسم کو تبدیل کرنے کا مشورہ دیا جائے گا۔

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

    اوپر بیان کیا گیا مسئلہ مرکب کے معاملے میں کبھی نہیں ہوتا ہے، اور اس وجہ سے مؤخر الذکر کو وراثت پر ترجیح دیتا ہے۔

  2. وراثت کا اگلا مسئلہ یہ ہے کہ ہم والدین کے تمام طریقوں کو کلائنٹ کے سامنے بے نقاب کرتے ہیں۔ اور اگر سپر کلاس کو بہت درست طریقے سے ڈیزائن نہیں کیا گیا ہے اور اس میں حفاظتی سوراخ ہیں۔ پھر، اگرچہ ہم اپنے ذیلی طبقے کے نفاذ میں سیکیورٹی کا پورا خیال رکھتے ہیں، پھر بھی ہم پیرنٹ کلاس کے ناقص نفاذ پر انحصار کریں گے۔

    کمپوزیشن ہمیں سپر کلاس کے طریقوں تک کنٹرول شدہ رسائی فراہم کرنے میں مدد کرتی ہے، جبکہ وراثت اس کے طریقوں پر کوئی کنٹرول برقرار نہیں رکھتی ہے۔ یہ بھی وراثت سے زیادہ ساخت کے اہم فوائد میں سے ایک ہے۔

  3. کمپوزیشن کا ایک اور فائدہ یہ ہے کہ طریقوں کو کال کرتے وقت یہ لچک میں اضافہ کرتا ہے۔ اوپر بیان کی گئی کلاس کا نفاذ ClassCزیادہ سے زیادہ نہیں ہے اور کہلائے گئے طریقہ پر ابتدائی پابندی کا استعمال کرتا ہے۔ کم سے کم تبدیلیاں ہمیں میتھڈ کالنگ کو لچکدار بنانے اور دیر سے بائنڈنگ (رن ٹائم پر بائنڈنگ) کی اجازت دیں گی۔

    ClassC.java

    package com.journaldev.inheritance;
    public class ClassC{
        SuperClass obj = null;
        public ClassC(SuperClass o){
            this.obj = o;
        }
        public void test(){
            obj.doSomething();
        }
    
        public static void main(String args[]){
            ClassC obj1 = new ClassC(new ClassA());
            ClassC obj2 = new ClassC(new ClassB());
    
            obj1.test();
            obj2.test();
        }
    }

    مندرجہ بالا پروگرام دکھائے گا:

    doSomething implementation of A
    doSomething implementation of B

    میتھڈ کالنگ میں یہ لچک وراثت کے ساتھ نہیں دیکھی جاتی ہے، جو کمپوزیشن کو بہترین طریقہ بناتی ہے۔

  4. کمپوزیشن کے معاملے میں یونٹ ٹیسٹنگ آسان ہے کیونکہ ہم جانتے ہیں کہ سپر کلاس میں استعمال ہونے والے تمام طریقوں کے لیے ہم ٹیسٹ کو روک سکتے ہیں، جبکہ وراثت میں ہم سپر کلاس پر بہت زیادہ انحصار کرتے ہیں اور یہ نہیں جانتے کہ پیرنٹ کلاس کے طریقے کیسے ہوتے ہیں۔ استعمال کیا جائے گا. لہذا، وراثت کی وجہ سے، ہمیں سپر کلاس کے تمام طریقوں کو جانچنا پڑے گا، جو کہ غیر ضروری کام ہے.

    مثالی طور پر، وراثت کا استعمال صرف اس صورت میں کیا جانا چاہیے جب والدین اور بچوں کی کلاسوں کے لیے " is-a " رشتہ درست ہو، بصورت دیگر مرکب کو ترجیح دی جانی چاہیے۔

اصل آرٹیکل
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION