John Squirrels
مستوى
San Francisco

مبادئ OOP

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

ما هو الكائن؟

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

التجريد

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

public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outgoingNumber);
    public abstract void ring(int incomingNumber);
}
في أحد البرامج، يمكننا إنشاء أنواع جديدة من الهواتف باستخدام هذه الفئة المجردة وتطبيق المبادئ الأساسية الأخرى لـ OOP، والتي سنستكشفها أدناه.

التغليف

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

التغليف والتحكم في الوصول

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

public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    // findSwitch
    // openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("Calling");
}

public void ring() {
    System.out.println("Ring-ring");
}

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

ميراث

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

public abstract class CordlessPhone extends AbstractPhone {

    private int hour;

    public CordlessPhone (int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
ترث الهواتف المحمولة خصائص الهاتف اللاسلكي، ونطبق طرق الاتصال والرنين في هذه الفئة:

public class CellPhone extends CordlessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outgoingNumber) {
        System.out.println("Calling " + outgoingNumber);
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("Incoming call from " + incomingNumber);
    }
}
وأخيرا، لدينا فئة الهواتف الذكية، والتي، على عكس الهواتف المحمولة الكلاسيكية، لديها نظام تشغيل كامل. يمكنك توسيع وظائف هاتفك الذكي عن طريق إضافة برامج جديدة يمكن تشغيلها على نظام التشغيل الخاص به. في الكود، يمكن وصف الفصل على النحو التالي:

public class Smartphone extends CellPhone {
    
    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program) {
    System.out.println("Installing " + program + " for " + operationSystem);
}

}
كما ترون، أنشأنا قدرًا كبيرًا من التعليمات البرمجية الجديدة لوصف فئة الهواتف الذكية ، لكننا حصلنا على فئة جديدة بوظائف جديدة. يتيح مبدأ OOP هذا تقليل كمية كود Java المطلوبة بشكل كبير، مما يجعل الحياة أسهل للمبرمج.

تعدد الأشكال

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

public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// And here's polymorphism: using the AbstractPhone type in the code!
        phone.call(number);
    }
}
 }
الآن سوف نقوم بوصف عدة أنواع من الهواتف. من الهواتف الأولى:

public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outgoingNumber) {
        System.out.println("Crank the handle");
        System.out.println("What number would you like to connect to?");
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("The phone is ringing");
    }
}
هاتف أرضي عادي:

public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outgoingNumber) {
        System.out.println("Calling " + outgoingNumber);
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("The phone is ringing");
    }
}
وأخيرًا، هاتف فيديو رائع:

public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outgoingNumber) {
        System.out.println("Connecting video call to " + outgoingNumber);
    }
    @Override
    public void ring(int incomingNumber) {
        System.out.println("Incoming video call from " + incomingNumber);
    }
  }
سنقوم بإنشاء كائنات في الطريقة main() واختبار طريقة callAnotherUser() :

AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Jason");
user.callAnotherUser(224466, firstPhone);
// Crank the handle
// What number would you like to connect to?
user.callAnotherUser(224466, phone);
// Calling 224466
user.callAnotherUser(224466, videoPhone);
// Connecting video call to 224466
يؤدي استدعاء نفس الأسلوب على كائن المستخدم إلى نتائج مختلفة. يتم تحديد تطبيق محدد لأسلوب الاستدعاء ديناميكيًا داخل أسلوب callAnotherUser() بناءً على نوع الكائن المحدد الذي يتم تمريره عند تشغيل البرنامج. هذه هي الميزة الرئيسية لتعدد الأشكال – القدرة على اختيار التنفيذ في وقت التشغيل. في أمثلة فئات الهاتف المذكورة أعلاه، استخدمنا طريقة تجاوز - وهي خدعة حيث نقوم بتغيير تنفيذ طريقة محددة في الفئة الأساسية دون تغيير توقيع الطريقة. يستبدل هذا بشكل أساسي الطريقة: يتم استدعاء الطريقة الجديدة المحددة في الفئة الفرعية عند تنفيذ البرنامج. عادة، عندما نتجاوز طريقة ما، يتم استخدام التعليق التوضيحي Override . يخبر المترجم بالتحقق من توقيعات الطرق المتجاوزة والمتجاوزة. أخيرًا، للتأكد من أن برامج Java لديك متوافقة مع مبادئ OOP، اتبع هذه النصائح:
  • تحديد الخصائص الرئيسية للكائن؛
  • تحديد الخصائص والسلوك المشترك واستخدام الميراث عند إنشاء الفئات؛
  • استخدام الأنواع المجردة لوصف الكائنات؛
  • حاول دائمًا إخفاء الأساليب والحقول المتعلقة بالتنفيذ الداخلي للفصل.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION