CodeGym /مدونة جافا /Random-AR /أمثلة على وراثة الطبقات المتداخلة
John Squirrels
مستوى
San Francisco

أمثلة على وراثة الطبقات المتداخلة

نشرت في المجموعة
أهلاً! سننظر اليوم إلى آلية مهمة: الوراثة في الفئات المتداخلة. هل فكرت يومًا فيما ستفعله إذا كنت بحاجة إلى جعل فئة متداخلة ترث فئة أخرى. إذا لم يكن الأمر كذلك، صدقوني: قد يكون هذا الوضع مربكا، لأن هناك الكثير من الفروق الدقيقة.
  1. هل نجعل فئة متداخلة ترث بعض الفئات؟ أم أننا نجعل بعض الفئات ترث فئة متداخلة؟
  2. هل فئة الطفل/الوالد هي فئة عامة عادية أم أنها أيضًا فئة متداخلة؟
  3. وأخيرًا، ما نوع الفئات المتداخلة التي نستخدمها في كل هذه المواقف؟
هناك العديد من الإجابات المحتملة لكل هذه الأسئلة، وسيدور رأسك :) كما تعلم، يمكننا حل مشكلة معقدة عن طريق تقسيمها إلى أجزاء أبسط. لنفعل ذلك. دعونا نفكر في كل مجموعة من الفئات المتداخلة بدورها من منظورين: من يمكنه أن يرث كل نوع من الفئات المتداخلة، ومن يمكنه أن يرث. لنبدأ بالفئات المتداخلة الثابتة.

فئات متداخلة ثابتة

أمثلة على وراثة الطبقات المتداخلة - 2قواعد الميراث الخاصة بهم هي الأبسط. هنا يمكنك أن تفعل أي شيء تقريبًا يرغب فيه قلبك. يمكن للفئة المتداخلة الثابتة أن ترث:
  • فئة عادية
  • فئة متداخلة ثابتة تم الإعلان عنها في فئة خارجية أو أسلافها
تذكر مثالاً من درسنا حول الفئات المتداخلة الثابتة.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
دعونا نحاول تغيير الكود وإنشاء Drawingفئة متداخلة ثابتة وسليلها — Boeing737Drawing.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
كما ترون، لا توجد مشكلة. يمكننا حتى سحب Drawingالفصل وجعله فئة عامة عادية بدلاً من فئة متداخلة ثابتة - لن يتغير شيء.
public class Drawing {

}

public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
نحن نفهم هذا. ولكن ما هي الفئات التي يمكن أن ترث فئة متداخلة ثابتة؟ عمليا أي! متداخل/غير متداخل، ثابت/غير ثابت - لا يهم. هنا نجعل Boeing737Drawingالطبقة الداخلية ترث Drawingالفئة المتداخلة الثابتة:
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public class Boeing737Drawing extends Drawing {

       public int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
يمكنك إنشاء مثيل Boeing737Drawingمثل هذا:
public class Main {

   public static void main(String[] args) {

      Boeing737 boeing737 = new Boeing737(1990);
      Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
      System.out.println(drawing.getMaxPassengersCount());

   }

}
على الرغم من أن Boeing737Drawingفصلنا يرث فئة ثابتة، إلا أنه ليس ثابتًا في حد ذاته! ونتيجة لذلك، سوف تحتاج دائمًا إلى مثيل للفئة الخارجية. يمكننا إزالة Boeing737Drawingالفصل من Boeing737الفصل وجعله فصلًا عامًا بسيطًا. لا شيء يتغير. لا يزال بإمكانه أن يرث Drawingالفئة المتداخلة الثابتة.
public class Boeing737 {

   private int manufactureYear;
   public static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }
}

public class Boeing737Drawing extends Boeing737.Drawing {

   public int getMaxPassengersCount() {

       return Boeing737.maxPassengersCount;

}
النقطة المهمة الوحيدة هي أننا في هذه الحالة نحتاج إلى جعل maxPassengersCountالمتغير الثابت عامًا. إذا ظلت خاصة، فلن تتمكن الطبقة العامة العادية من الوصول إليها. لقد اكتشفنا الطبقات الثابتة! :) الآن دعنا ننتقل إلى الطبقات الداخلية. أنها تأتي في 3 أنواع: الطبقات الداخلية البسيطة، والطبقات المحلية، والطبقات الداخلية المجهولة. أمثلة على وراثة الطبقات المتداخلة - 3مرة أخرى، دعنا ننتقل من البسيط إلى المعقد :)

فئات داخلية مجهولة

لا يمكن للفئة الداخلية المجهولة أن ترث فئة أخرى. لا يمكن لأي فئة أخرى أن ترث فئة مجهولة. لا يمكن أن يكون الأمر أكثر بساطة! :)

الطبقات المحلية

يتم الإعلان عن الفئات المحلية (في حالة نسيانها) داخل كتلة التعليمات البرمجية لفئة أخرى. يحدث هذا غالبًا داخل إحدى طرق الطبقة الخارجية. منطقيًا، يمكن فقط للفئات المحلية الأخرى داخل نفس الطريقة (أو كتلة التعليمات البرمجية) أن ترث فئة محلية. هنا مثال:
public class PhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       class CellPhoneNumber extends PhoneNumber {

       }

       class LandlinePhoneNumber extends PhoneNumber {


       }

       // ...number validation code
   }
}
هذا هو الكود من درسنا حول الفصول المحلية. تحتوي فئة التحقق من الرقم لدينا على PhoneNumberفئة محلية. إذا أردنا أن يمثل كيانين مختلفين، على سبيل المثال، رقم هاتف محمول ورقم هاتف أرضي، فلا يمكننا القيام بذلك إلا بنفس الطريقة. السبب بسيط: يقتصر نطاق الفئة المحلية على الطريقة (كتلة التعليمات البرمجية) التي تم الإعلان عنها. ونتيجة لذلك، لن نتمكن من استخدامه خارجيًا (بما في ذلك وراثة الفصل). ومع ذلك، فإن احتمالات الميراث داخل الطبقة المحلية نفسها أوسع بكثير! يمكن للفئة المحلية أن ترث:
  1. فئة عادية.
  2. فئة داخلية تم الإعلان عنها في نفس الفئة مثل الفئة المحلية أو في أحد أسلافها.
  3. تم الإعلان عن فئة محلية أخرى بنفس الطريقة (كتلة التعليمات البرمجية).
تبدو النقطتان الأولى والثالثة واضحتين، لكن النقطة الثانية مربكة بعض الشيء:/ فلننظر إلى مثالين. مثال 1 - "جعل فئة محلية ترث فئة داخلية معلنة في نفس الفئة مثل الفئة المحلية":
public class PhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       // ...number validation code
   }
}
هنا قمنا بإزالة PhoneNumberالفصل من validatePhoneNumber()الطريقة وجعلناه فئة داخلية بدلاً من فئة محلية. هذا لا يمنعنا من جعل الفصلين المحليين يرثونها. مثال 2 — "... أو في أسلاف هذه الفئة." الآن أصبح هذا بالفعل أكثر إثارة للاهتمام. يمكننا أن ننتقل PhoneNumberإلى مستوى أعلى في سلسلة الميراث. لنعلن عن AbstractPhoneNumberValidatorفئة مجردة، والتي ستصبح سلف صفنا PhoneNumberValidator:
public abstract class AbstractPhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

}
كما ترون، لم نعلن ذلك فحسب، بل قمنا أيضًا بنقل PhoneNumberالطبقة الداخلية إليه. ومع ذلك، في السلالة PhoneNumberValidator، يمكن للطبقات المحلية المعلنة في الأساليب أن ترث PhoneNumberدون أي مشكلة!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       // ...number validation code
   }
}
بسبب علاقة الميراث، فإن الطبقات المحلية داخل الطبقة السليلة "ترى" الطبقات الداخلية داخل السلف. وأخيرا، دعونا ننتقل إلى المجموعة الأخيرة :)

الطبقات الداخلية

يمكن للفئة الداخلية المعلنة في نفس الطبقة الخارجية (أو في سليلها) أن ترث فئة داخلية أخرى. دعونا نستكشف هذا باستخدام مثالنا مع الدراجات من الدرس الخاص بالطبقات الداخلية.
public class Bicycle {

   private String model;
   private int maxWeight;

   public Bicycle(String model, int maxWeight) {
       this.model = model;
       this.maxWeight = maxWeight;
   }

   public void start() {
       System.out.println("Let's go!");
   }

   class Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }

   class SportSeat extends Seat {

       // ...methods
   }
}
هنا أعلنا Seatالطبقة الداخلية داخل Bicycleالفصل. نوع خاص من مقاعد السباق SportSeatيرثها. لكن يمكننا إنشاء نوع منفصل من "دراجات السباق" ووضعه في فئة منفصلة:
public class SportBicycle extends Bicycle {

   public SportBicycle(String model, int maxWeight) {
       super(model, maxWeight);
   }


   class SportSeat extends Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }
}
وهذا أيضًا خيار. الطبقة الداخلية للسليل ( SportBicycle.SportSeat) "ترى" الطبقات الداخلية للسلف ويمكن أن ترثها. وراثة الطبقات الداخلية لها ميزة واحدة مهمة جدًا! في المثالين السابقين، SportSeatكانت صفيتنا عبارة عن طبقة داخلية. ولكن ماذا لو قررنا إنشاء SportSeatطبقة عامة عادية ترث Seatالطبقة الداخلية في نفس الوقت؟
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
لقد حصلنا على خطأ! يمكنك تخمين لماذا؟ :) كل شيء واضح ومباشر. عندما تحدثنا عن Bicycle.Seatالطبقة الداخلية، ذكرنا أن الإشارة إلى مثيل الطبقة الخارجية يتم تمريرها ضمنيًا إلى مُنشئ الطبقة الداخلية. هذا يعني أنه لا يمكنك إنشاء Seatكائن دون إنشاء Bicycleكائن. ولكن ماذا عن إنشاء SportSeat؟ على عكس Seat, لا يحتوي على هذه الآلية المضمنة لتمرير مرجع ضمني للمنشئ إلى مثيل للفئة الخارجية. S حتى، بدون Bicycleكائن، لا يمكننا إنشاء SportSeatكائن، تمامًا كما في حالة Seat. لذلك، لم يتبق لنا سوى شيء واحد للقيام به - وهو تمرير SportSeatإشارة إلى Bicycleكائن ما إلى المنشئ بشكل صريح. هيريس كيفية القيام بذلك:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
نحن نسمي منشئ الطبقة الفائقة باستخدام super(); Now، إذا أردنا إنشاء SportSeatكائن، فلن يمنعنا شيء من القيام بذلك:
public class Main {

   public static void main(String[] args) {

       Bicycle bicycle = new Bicycle("Peugeot", 120);
       SportSeat peugeotSportSeat = new SportSeat(bicycle);

   }
}
أوف! كان هذا الدرس طويلاً :) لكنك تعلمت الكثير! الآن حان الوقت لحل بعض المهام! :)
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION