java شرح الفرق بين الميراث والتكوين




what are packages in java (14)

في تجميع كلمة بسيط يعني وجود علاقة ..

التركيب هو حالة خاصة من التجميع . بطريقة أكثر تحديدًا ، يطلق على التجميع المحظور اسم التركيب. عندما يحتوي كائن على الكائن الآخر ، إذا كان الكائن المتواجد لا يمكن أن يوجد بدون وجود كائن حاوية ، فإنه يسمى التركيب. مثال: يحتوي الفصل على الطلاب. لا يمكن أن يوجد طالب بدون فصل دراسي. يوجد تكوين بين الفصل والطلاب.

لماذا استخدام التجميع

قانون إعادة الاستخدام

عند استخدام التجميع

كما يتم تحقيق إعادة استخدام الكود بشكل أفضل من خلال التجميع عندما لا تكون هناك سفينة علاقة

ميراث

الميراث هو الميراث العلاقة الوالدية للطفل هو علاقة

الوراثة في java هي آلية يحصل فيها كائن واحد على كل خصائص وسلوكيات الكائن الرئيسي.

استخدام الوراثة في Java 1 Code Reusability. 2 إضافة ميزة إضافية في فئة الطفل وكذلك تجاوز الأسلوب (لذلك يمكن أن يتحقق تعدد الأشكال وقت التشغيل).

هل التركيب والوراثة متماثلان؟ إذا كنت أرغب في تنفيذ نمط التكوين ، كيف يمكنني القيام بذلك في Java؟


وكمثال آخر ، فكر في فئة السيارات ، وهذا سيكون استخدامًا جيدًا للتكوين ، فالسيارة قد "تملك" محركًا ، وناقل حركة ، وإطارات ، ومقاعد ، إلخ. ولن تمد أيًا من هذه الفئات.


يكون التكوين كما يبدو - تقوم بإنشاء كائن من خلال توصيل الأجزاء.

EDIT يستند الجزء المتبقي من هذه الإجابة بشكل خاطئ إلى الفرضية التالية.
يتم إنجاز ذلك مع واجهات.
على سبيل المثال ، باستخدام مثال Car أعلاه ،

Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel

حتى مع بعض المكونات النظرية القياسية يمكنك بناء الكائن الخاص بك. ومن ثم مهمتك هي ملء الكيفية التي يحمي بها House سكانه ، وكيف تحمي Car ركابها.

الميراث هو مثل العكس. يمكنك البدء باستخدام كائن كامل (أو شبه كامل) واستبدال أو تجاوز البتات المختلفة التي تريد تغييرها.

على سبيل المثال ، قد يأتي Fuelable مع طريقة Fuelable وطريقة Drive . يمكنك ترك طريقة الوقود كما هي لأنها نفس الشيء لملء دراجة نارية وسيارة ، ولكن يمكنك تجاوز طريقة Drive لأن Drive الدراجة النارية يقود Car بشكل مختلف جدًا.

مع الميراث ، يتم بالفعل تنفيذ بعض الفئات بالفعل ، وبعضها الآخر لديه طرق تضطر إلى تجاوزها. مع تكوين شيء أعطيت لك. (ولكن يمكنك تنفيذ الواجهات عن طريق استدعاء الأساليب في الفصول الدراسية الأخرى إذا كان لديك شيء يدور حوله).

يُنظر إلى التركيب على أنه أكثر مرونة ، لأنه إذا كان لديك طريقة مثل iUsesFuel ، فيمكنك استخدام طريقة أخرى في مكان آخر (فصل آخر ، مشروع آخر) تقلق فقط بشأن التعامل مع الكائنات التي يمكن تغذيتها ، بغض النظر عما إذا كانت سيارة ، واجهات ، موقد ، الشواء ، وما إلى ذلك واجهات أن الطبقات التي يقولون أنها تنفذ هذه الواجهة في الواقع لديها الأساليب التي كل ذلك هو واجهة. فمثلا،

iFuelable Interface:
   void AddSomeFuel()
   void UseSomeFuel()
   int  percentageFull()

عندها يمكن أن يكون لديك طريقة في مكان آخر

private void FillHerUp(iFuelable : objectToFill) {

   Do while (objectToFill.percentageFull() <= 100)  {

        objectToFill.AddSomeFuel();
   }

مثال غريب ، لكنه يدل على أن هذه الطريقة لا تهتم ما هو ملء ، لأن الكائن بتنفيذ iUsesFuel ، يمكن ملؤها. نهاية القصة.

إذا كنت تستخدم الوراثة بدلاً من ذلك ، FillHerUp إلى أساليب FillHerUp مختلفة للتعامل مع MotorVehicles Barbecues ، إلا إذا كان لديك كائن أساسي "ObjectThatUsesFuel" غريبًا من الذي ترث.


التركيب هو المكان الذي يتكون فيه شيء من أجزاء متميزة وله علاقة قوية مع تلك الأجزاء. إذا توفي الجزء الرئيسي حتى يفعل الآخرون ، فلا يمكن أن يكون لهم حياة خاصة بهم. مثال تقريبي هو جسم الإنسان. خذ القلب وجميع الأجزاء الأخرى تموت بعيدا.

الوراثة هي المكان الذي تأخذ فيه شيئًا موجودًا بالفعل ويستخدمه. لا توجد علاقة قوية. يمكن لأي شخص أن يرث حوزة آباءه ، لكن بإمكانه الاستغناء عنها.

لا أعرف جافا لذا لا يمكنني تقديم مثال لكن يمكنني تقديم شرح للمفاهيم.


هل التركيب والوراثة متماثلان؟

هم ليسوا نفس.

Composition : إنه يمكّن من التعامل مع مجموعة من الكائنات بنفس طريقة التعامل مع مثيل واحد من كائن ما. الغرض من المركب هو "تأليف" الكائنات في هياكل الأشجار لتمثل التسلسلات الهرمية جزئية كاملة

Inheritance : فئة ترث الحقول والأساليب من جميع فئاتها الفوقية ، سواء المباشرة أو غير المباشرة. يمكن للفئة الفرعية أن تلغي الأساليب التي تراثها ، أو يمكنها إخفاء الحقول أو الأساليب التي ترثها.

إذا كنت أرغب في تنفيذ نمط التكوين ، كيف يمكنني القيام بذلك في Java؟

مقالة Composition جيدة بما فيه الكفاية لتنفيذ نمط مركب في جافا.

المشاركون الرئيسيون:

المكون :

  1. هو التجريد لجميع المكونات ، بما في ذلك المكونات المركبة
  2. تعلن واجهة للكائنات في التكوين

ورقة :

  1. يمثل كائنات ورقة في التكوين
  2. يطبق جميع أساليب المكونات

مركب :

  1. يمثل مكون مركب (مكون له أطفال)
  2. تطبق أساليب للتلاعب بالأطفال
  3. تنفذ جميع أساليب المكونات ، عادة عن طريق تفويضها لأطفالها

مثال على الرمز لفهم النمط المركب :

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

interface Part{
    public double getPrice();
    public String getName();
}
class Engine implements Part{
    String name;
    double price;
    public Engine(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Trunk implements Part{
    String name;
    double price;
    public Trunk(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Body implements Part{
    String name;
    double price;
    public Body(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Car implements Part{
    List<Part> parts;
    String name;

    public Car(String name){
        this.name = name;
        parts = new ArrayList<Part>();
    }
    public void addPart(Part part){
        parts.add(part);
    }
    public String getName(){
        return name;
    }
    public String getPartNames(){
        StringBuilder sb = new StringBuilder();
        for ( Part part: parts){
            sb.append(part.getName()).append(" ");
        }
        return sb.toString();
    }
    public double getPrice(){
        double price = 0;
        for ( Part part: parts){
            price += part.getPrice();
        }
        return price;
    }   
}

public class CompositeDemo{
    public static void main(String args[]){
        Part engine = new Engine("DiselEngine",15000);
        Part trunk = new Trunk("Trunk",10000);
        Part body = new Body("Body",12000);

        Car car = new Car("Innova");
        car.addPart(engine);
        car.addPart(trunk);
        car.addPart(body);

        double price = car.getPrice();

        System.out.println("Car name:"+car.getName());
        System.out.println("Car parts:"+car.getPartNames());
        System.out.println("Car price:"+car.getPrice());
    }

}

انتاج:

Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0

تفسير:

  1. الجزء هو ورقة
  2. سيارة تحتوي على أجزاء كثيرة
  3. تم إضافة أجزاء مختلفة من السيارة إلى السيارة
  4. سعر السيارة = مجموع (سعر كل جزء )

الرجوع إلى السؤال أدناه لمزاعم وعيوب التركيب والميراث.

تفضل تكوين على الميراث؟


التركيب يعني HAS A
الميراث يعني IS A

Example : السيارة لديها محرك وسيارة هي سيارة

في البرمجة يتم تمثيل ذلك على النحو التالي:

class Engine {} // The Engine class.

class Automobile {} // Automobile class which is parent to Car class.

class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
  private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}

كيف يمكن أن يكون الميراث خطيراً؟

دعونا نأخذ على سبيل المثال

public class X{    
   public void do(){    
   }    
}    
Public Class Y extends X{
   public void work(){    
       do();    
   }
}

1) كما هو واضح في التعليمات البرمجية أعلاه ، فإن الفئة Y بها اقتران قوي جدًا مع الفئة X. إذا تغير أي شيء في الطبقة الفائقة X ، فقد ينكسر Y بشكل كبير. افترض في الفئة X X المستقبلية تعمل أسلوب العمل مع أدناه التوقيع

public int work(){
}

يتم التغيير في الفئة X ولكنه سيجعل الطبقة Y غير قابلة للتكرار. هذا النوع من التبعية يمكن أن يصل إلى أي مستوى ويمكن أن يكون خطيرا. في كل مرة قد لا يكون لدى الطبقة المتفوقة رؤية كاملة للرمز داخل جميع الفئات الفرعية الخاصة بها ، وقد يستمر التصنيف الفرعي في ملاحظة ما يحدث في الرُّقْع طوال الوقت. لذلك نحن بحاجة إلى تجنب هذا الاقتران القوي وغير الضروري.

كيف يحل التكوين هذه القضية؟

دعونا نرى من خلال مراجعة نفس المثال

public class X{
    public void do(){
    }
}

Public Class Y{
    X x=new X();    
    public void work(){    
        x.do();
    }
}

هنا نقوم بإنشاء مرجع للفئة X في فئة Y واستدعاء طريقة فئة X عن طريق إنشاء مثيل لفئة X. الآن ذهب كل هذا اقتران قوي. الطبقة المتفوقة والفئة الفرعية مستقلة بدرجة كبيرة عن بعضها البعض الآن. يمكن للفصول إجراء تغييرات بحرية والتي كانت خطيرة في حالة الميراث.

2) ميزة ثانية جيدة جدا من التكوين في أنه يوفر مرونة استدعاء الأسلوب على سبيل المثال

class X implements R
{}
class Y implements R
{}

public class Test{    
    R r;    
}

في فئة الاختبار باستخدام مرجع r ، يمكنني استدعاء أساليب فئة X بالإضافة إلى صنف Y. هذه المرونة لم تكن موجودة أبداً في الميراث

3) ميزة أخرى كبيرة: اختبار وحدة

public class X{
    public void do(){
    }
}

Public Class Y{
    X x=new X();    
    public void work(){    
        x.do();    
    }    
}

في المثال أعلاه إذا كانت حالة x غير معروفة ، يمكن بسهولة استهزائها باستخدام بعض بيانات الاختبار ويمكن اختبار جميع الطرق بسهولة. لم يكن هذا ممكنا على الإطلاق في الميراث كما كنت تعتمد بشكل كبير على الطبقة المتفوقة للحصول على حالة المثال وتنفيذ أي طريقة.

4) سبب وجيه آخر لماذا يجب علينا تجنب الوراثة هو أن جافا لا تدعم الميراث المتعدد.

لنأخذ مثالاً لفهم هذا:

Public class Transaction {
    Banking b;
    public static void main(String a[])    
    {    
        b=new Deposit();    
        if(b.deposit()){    
            b=new Credit();
            c.credit();    
        }
    }
}

جيد ان تعلم :

  1. يتم تحقيق التكوين بسهولة في وقت التشغيل في حين يوفر الميراث ميزاته في وقت التحويل البرمجي

  2. يعرف التكوين أيضا باسم HAS-A العلاقة والميراث هو المعروف أيضا باسم IS-A العلاقة

لذا اجعله عادة تفضيل التكوين على الميراث لمختلف الأسباب المذكورة أعلاه.


على الرغم من أن كل من الوراثة والتكوين يوفر إمكانية إعادة كتابة الكود ، فإن الفرق الرئيسي بين التركيب والوراثة في Java هو أن التركيب يسمح بإعادة استخدام الكود بدون تمديده ، ولكن بالنسبة إلى الوراثة ، يجب عليك توسيع الفصل لأي إعادة استخدام للشفرة أو الوظيفة. فرق آخر الذي يأتي من هذه الحقيقة هو أنه باستخدام Composition يمكنك إعادة استخدام التعليمات البرمجية للفئة النهائية حتى غير القابلة للتوسعة ولكن لا يمكن إعادة التوريث استخدام التعليمات البرمجية في مثل هذه الحالات. أيضًا باستخدام Composition ، يمكنك إعادة استخدام الكود من العديد من الطبقات حيث يتم الإعلان عنها كمتغير عضو فقط ، ولكن مع الوراثة يمكنك إعادة استخدام الكود من فئة واحدة فقط لأنه في Java يمكنك توسيع فئة واحدة فقط ، لأن Inheritance متعددة غير مدعومة في Java . يمكنك القيام بذلك في C ++ بالرغم من أن هناك فئة واحدة يمكنها توسيع أكثر من فئة واحدة. راجع للشغل ، يجب عليك دائمًا تفضيل التركيب على الوراثة في Java ، ليس فقط أنا بل حتى اقترحها جوشوا بلوخ في كتابه


الوراثة بين فئتين ، حيث طبقة واحدة تمتد إلى فصل آخر تؤسس علاقة " IS A ".

يحتوي التركيب على الطرف الآخر على مثيل لفئة أخرى في الفصل الدراسي يؤسس علاقة " Has A ". التكوين في java مفيد لأنه يسهّل تقنيًا عدة ميراث.


وراثة تكوين Vs.

تستخدم كل من الميراث والتكوين لإعادة قابلية الاستخدام وامتداد السلوك الطبقي.

إن الميراث المستخدم بشكل أساسي في نموذج برمجة خوارزمية العائلة مثل نوع علاقة IS-A يعني نوعًا مماثلاً من الكائنات. مثال.

  1. دستر هي سيارة
  2. سفاري هي سيارة

هذه ملك لعائلة السيارة.

يمثل التركيب HAS-A علاقة Type.It يعرض قدرة كائن مثل Duster has Five Gears ، يحتوي Safari على أربعة Gears إلخ. كلما احتجنا إلى توسيع قدرة فئة موجودة ثم استخدم التركيب. على سبيل المثال ، نحتاج إلى إضافة جهاز تروس إضافي في كائن Duster ، ومن ثم يتعين علينا إنشاء كائن ترس واحد آخر وإنشاءه إلى كائن المنفضة.

لا ينبغي لنا إجراء التغييرات في الصف الأساسي حتى / ما لم تكن جميع الفئات المشتقة بحاجة إلى هذه الوظائف.لهذا السيناريو يجب أن نستخدم Composition.Such مثل

الفئة أ المشتقة حسب الفئة ب

الفئة أ المشتقة حسب الفئة جيم

الفئة أ المشتقة حسب الفئة د.

عندما نضيف أي وظائف في الفئة A ، فإنه متاح لجميع الفئات الفرعية حتى عندما لا تتطلب الفئة C و D هذه الوظائف.ولذلك يحتاج هذا السيناريو إلى إنشاء فصل منفصل لهذه الوظائف وتكوينه للفئة المطلوبة ( هنا هو الفئة ب).

أدناه هو المثال:

          // This is a base class
                 public abstract class Car
                    {
                       //Define prototype
                       public abstract void color();
                       public void Gear() {
                           Console.WriteLine("Car has a four Gear");
                       }
                    }


           // Here is the use of inheritence
           // This Desire class have four gears.
          //  But we need to add one more gear that is Neutral gear.

          public class Desire : Car
                   {
                       Neutral obj = null;
                       public Desire()
                       {
     // Here we are incorporating neutral gear(It is the use of composition). 
     // Now this class would have five gear. 

                           obj = new Neutral();
                           obj.NeutralGear();
                       }

                       public override void color()
                       {
                           Console.WriteLine("This is a white color car");
                       }

                   }


             // This Safari class have four gears and it is not required the neutral
             //  gear and hence we don't need to compose here.

                   public class Safari :Car{
                       public Safari()
                       { }

                       public override void color()
                       {
                           Console.WriteLine("This is a red color car");
                       }


                   }

   // This class represents the neutral gear and it would be used as a composition.

   public class Neutral {
                      public void NeutralGear() {
                           Console.WriteLine("This is a Neutral Gear");
                       }
                   }

لا ، كلاهما مختلفان. يتبع تكوين علاقة "HAS-A" وراثة تتبع علاقة "IS-A". أفضل مثال للتكوين كان النمط الاستراتيجي.


التوريث يعني إعادة استخدام الوظائف الكاملة للفصل ، وهنا يجب على صفي استخدام جميع أساليب الطبقة الفائقة ، وسيتم الجمع بين فئتي مع الطبقة الفائقة وسيتم تكرار الشفرة في كلتا الفئتين في حالة التوريث.

لكن يمكننا التغلب على كل هذه المشاكل عندما نستخدم التركيب للتحدث مع فصل آخر. فالتشكيل يعلن عن صفة لفصل آخر في صفي الذي نريد التحدث إليه. وما الوظيفة التي نريدها من تلك الفئة التي يمكننا الحصول عليها باستخدام هذه الخاصية.


يعني التركيب إنشاء كائن لفئة لها علاقة بتلك الفئة المعينة. افترض أن الطالب له علاقة بالحسابات ؛

وراثة ، وهذا هو الصف السابق مع ميزة الموسعة. وهذا يعني أن هذا الفصل الجديد هو الفصل القديم مع ميزة ممتدة. افترض أن الطالب هو طالب ولكن كل الطلاب هم بشر. لذلك هناك علاقة مع الطالب والبشر. هذا هو الميراث.


هم مختلفون تماما. الوراثة هي علاقة "is-a" . التكوين هو "has-a" .

أنت تقوم بالتأليف من خلال وجود مثيل لفئة C أخرى كحقل من صفك ، بدلاً من توسيع C من الأمثلة الجيدة على أن التركيب سيكون أفضل بكثير من التوريث هو java.util.Stack ، الذي يمتد حاليًا إلى java.util.Vector . هذا يعتبر الآن خطأ. A stack "is-NOT-a" vector؛ يجب عدم السماح لك بإدراج العناصر وإزالتها بشكل تعسفي. كان يجب أن تكون تركيبة بدلاً من ذلك

لسوء الحظ ، فقد فات الأوان لتصحيح خطأ التصميم هذا ، لأن تغيير التسلسل الهرمي الآن سيؤدي إلى كسر التوافق مع الشفرة الحالية. لو استخدم Stack تكوينًا بدلاً من التوريث ، فيمكن دائمًا تعديله لاستخدام بنية بيانات أخرى دون انتهاك واجهة برمجة التطبيقات .

أنا أوصى كتاب جوش بلوخ في فعالية جافا الطبعة 2

  • البند 16: صالح التكوين على الميراث
  • البند 17: التصميم والتوثيق للوراثة أو تحظره

التصميم الجيد الموجه للكائن ليس حول توسيع الطبقات الموجودة بشكل حر. يجب أن تكون غريزتك الأولى هي الإنشاء بدلاً من ذلك.

أنظر أيضا:





composition