1. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    هذه المقالة لتعلم كيفية كتابة اختبارات JUnit للغة الجافا بشكل مرتب وسلس حتى يشعر القارئ بالراحة وعدم الضياع في كلاس الاختبارات.
    هذا الموضوع عبارة عن تكملة للموضوع الرئيسي: 
    كتابة اختبارات الـ JUnit بشكل محترف
    توجد اتفاقية (Conventions) لكتابة الاختبارات بشكل محترف لدى المبرمجين, حتى يسهل عليهم قرائتها والتعامل معها. وهذه الطريقة تسمى اختصاراً بالـ AAA. و ايضاً سأقوم بالتطرق الى بعض الملاحظات والتحذيرات عند كتابة دوال الاختبارات.
    AAA Style for Tests
    وتتكون هذه الطريقة من ثلاثة اقسام وهم:
    الـ Arrange (الترتيب) اي ترتيب وتجهيز العناصر لإجراء الاختبارات عليها. الـ Action (الفعل) اي السلوك للعناصر المراد اختبارها "يعني الدوال للــ Object". الـ Assert (التأكيد او الجزم) في هذه المرحلة نكتب الكود الذي من خلاله نتحقق من صحة المنطق لدينا. مثال
    @Test public void setting_calculator_color_test(){ // Arrange Calculator calculator = new Calculator("none"); // Action calculator.setColor("blue"); // Assert assertEquals(calculator.getColor(), "blue"); } التعقيب
    الترتيب: قمنا بانشاء عنصر حاسبة من موديل الـ Calculator. الفعل: قمنا بالنداء على الدالة setColor() لتحويل الحاسبة الى اللون الازرق. التأكيد: قمنا بكتابة شفرة الجزم المطلوبة باستخدام assertEquals, والذي من خلالها سنجزم ان لون حاسبتنا اصبح ازرق حتى ينجح الاختبار, والا فأن الفعل setColor به خلل منطقي. والان حتى لانكرر انشاء العنصر calculator كل مرة نقوم بكتابة دالة اختبار. فالافضل ان نحوله الى Field. ثم نقوم بكتابة الدالة setUp ذي النوتيشن Before والتي فيها ننشئ عناصرنا.
     
    لتصبح دالة الاختبار بهذا الشكل:
    @Test public void setting_calculator_color_test(){ // Action calculator.setColor("blue"); // Assert assertEquals(calculator.getColor(), "blue"); }  
    اما باعلى الكلاس فالوضع اصبح هكذا:
    public class MainTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Red"); } ... ... ... تحذير: لاتقم باختبار فعلين في دالة واحده
    مثال
    @Test public void subtraction_multiplication_tests(){ // Action & Assert assertEquals(calculator.subtraction(10, 6), 4); // is 10 - 6 = 4 ? assertEquals(calculator.multiplication(6, 2), 12); // is 6 * 2 is 12 ? } تعقيب
    كتابة الاختبارات بهذا الشكل خاطئ جداً! لماذا؟
    لاننا قمنا باختبار فعلين مختلفين وهم substraction() و multiplications() في دالة واحدة وهذا غير مستحسن. ففي حالة فشل هذا الاختبار فأننا لاندري اي فعل هو المسبب للفشل, وسيكون الـ debug صعب جداً بل مربك. فمن الافضل ان نقوم باختبار فقط فعل واحد في كل دالة اختبار قدر المستطاع. اذن لنضع على هذه الداله النوتيشن Ignore حتى يتجاهلها الـ JUnit
    مثال اخر
    اختبار خوارزمية القسمة العادية و خوارزمية القسمة المطولة في نفس الدالة.
    @Test public void divisions_test(){ // Action & Assert assertEquals(calculator.division(100, 2), 50); assertEquals(calculator.longDivision(100, 2), 50); } الناتج

    تعقيب
    هل تستطيع تحديد اي من الخوارزميات الخاطئة في المنطق؟ هل هي division ام longDivision ؟ هل رأيت صعوبة الامر للقارئ.
    الحل
    هو فصل الفعلين الى دالتين اختبار منفصلتين. ولكن الم تلاحظ تقارب بين الفعلين؟ القسمة العادية والقسمة المطولة؟ فهنا نستطيع المحافظة عليهم في نفس دالة الاختبار ونقوم بإظافة رسالة تسهل علينا الأمر في حالة التعطل.
    الحل هو بأضافة تعليق لكل سطر تأكيد في الداله كما التالي:
    @Test public void divisions_test(){ // Action & Assert assertEquals("Normal Division", calculator.division(100, 2), 50); assertEquals("Long Division", calculator.longDivision(100, 2), 50); } الناتج

    تعقيب
    من الصورة نرى ان الخوارزمية Long Division هي السبب لفشل الاختبار. وهكذا اصبح على القارئ و المبرمج اكتشاف الاخطاء اسهل بكثير.
    الكلاس كاملة
    package com.company; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; public class MainTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Red"); } @Test public void addition_test() { // Action int result = calculator.addition(2, 2); // Assert assertEquals(result, 4); // is result actually equal 4? } @Test public void subtraction_test() { // Action int result = calculator.subtraction(10, 4); // Assert assertEquals(result, 6); } @Test public void multiplication_test() { // Action int result = calculator.multiplication(5, 5); // Assert assertEquals(result, 25); } @Test public void division_test() { // Action int result = calculator.division(10, 2); // Assert assertEquals(result, 5); } @Test public void check_color_and_change_it_test(){ // Action if (calculator.getColor().equals("Red")){ calculator.setColor("Blue"); } // Assert // Check is color changed? assertEquals(calculator.getColor(), "Blue"); } @Ignore @Test public void check_color_is_still_changed(){ // Assert assertEquals(calculator.getColor(), "Blue"); } // --------------------------- // // --- New Tests - Part 02 --- // // --------------------------- // @Test public void setting_calculator_color_test(){ // Action calculator.setColor("blue"); // Assert assertEquals(calculator.getColor(), "blue"); // is calculator color actually blue? } @Ignore @Test public void subtraction_multiplication_tests(){ // Action & Assert assertEquals(calculator.subtraction(10, 6), 4); // is 10 - 6 = 4 ? assertEquals(calculator.multiplication(6, 2), 12); // is 6 * 2 is 12 ? } @Test public void divisions_test(){ // Action & Assert assertEquals("Normal Division", calculator.division(100, 2), 50); assertEquals("Long Division", calculator.longDivision(100, 2), 50); } @Test public void calculator_is_not_null_test(){ // Assert assertNotNull(calculator); } @Test public void check_calculator_power_test(){ // Assert & Action assertTrue(calculator.checkPower()); // is calculator is powered on? } }  
    وهكذا تصبح قرائة الاختبارات اكثر سهولة وكتابتها ايضاً.
    مستوى المقال: متوسط
  2. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
    بعد غيبة طويلة أعود بموضوع صغير نوعاً ما لكنه ذي فائدة كبيرة.
    في هذا الموضوع إن شاء الله سنتعرض لطريقة حفظ وفتح ملفات PDF (سأستخدم pdf في المثال لكن في الحقيقة بالامكان حفظ أي نوع من أنواع الملفات سواء ملفات صوتية أو صور أو فيديو).
    يجب أن يكون القارء ملم ببعض الأساسيات بكيفية ربط قاعدة البيانات (MySQL) مع ملف Java كذلك كيفية التعامل مع قاعدة البيانات من إنشاء، استعراض واضافات البيانات داخل قاعدة البيانات . وإن شاء الله سأوفر كل الموارد التي نحتاجها في موضوعنا هذا. بسم الله نبدأ.
     
    - هل حفظ الملفات داخل قاعدة البيانات الطريقة الوحيدة؟
    بالطبع حفظ الملفات داخل قاعدة البيانات ليست الطريقة الوحيدة لحفظ الملفات داخل الخادم بل هناك طرق أخرى، مثلا يمكنك أن تحفظ الملفا داخل أي مكان في الخادم ومن ثم تحفظ المسار الكامل له داخل قاعدة البيانات، وقد يحبب الكثير هذه الطريقة؛ لكن لحفظ الملفات داخل قاعدة البيانات محاسنها (كما ولها مساوئها)  فمثلاً في حال أردت أخد نسخة احتياطية لبياناتك ليس عليك سوى أخذ نسخة من قاعدة البيانات نفسها بدون نسخ أي ملفات أخرى، قد تضطر لتغيير مكان الملفات في مرحلة ما وفي هذه الحال يجب عليك أن تغيير المسار المحفوظ للملف داخل قاعدة البيانات (لا أقول بأن هذا صعب لكنه يحتاج إلى وقت)، كذلك فإن بياناتك محمية من الدخول أو الحذف أو التغيير غير المصرح به بما أنها داخل قاعدة البيانات. من العيوب التي قد تمنعك من حفظ الملفات داخل قاعدة البيانات هو الحجم المهول الذي ستقدوا عليه بعد فترة من الزمن، لكن لا أعتقد بأن هذا ذي أهمية كبيرة حيث أنك تريد المحافظة على كل بياناتك من الضياع فعند نسخك أو أخذك نسخة احتياطية لقاعدة البيانات فإنك تريد الحفاظ على الملفات كذلك ولكن لحل هذه المشكلة بالامكان حفظ الملفات داخل جدول مستقل لإقصائها من بعض العمليات.
     
    - ما هي الملفات التي تقبل قاعدة البيانات حفظها؟
    قاعدة البيانات تحفظ الملفات على شكل ملف Binary (ثنائي) كبير؛ بالتالي فإن قاعدة البيانات قاددرة على حفظ أي نوع من أنواع الملفات مهما كان ملفات الفيديو مثل mp4. أو .mkv، ملفات الصوت مثل ,aac أو .m4a، الصور بشتى أنواعها أو المفات المكتبية. ببساطة أي ملف يمكن تخيله باستطاعتنا حفظه داخل قاعدة البيانات.
     
    - ما هو أقصى حجم للملف؟
    قواعد البيانات MySQL تحتوي على أربع أنواع يمكن حفظ الملفات فيها، ما يمز كل نوع عن الآخر هو أقصى حجم يمكن حفظها دخلها فقط، أما طريقة التعامل معها في الحفظ والاسترجاع فمتماثله.
    1. TINYBLOB: أقصى حجم هو (28 ما يعادل 256 بايت).
    2. BLOB: أقصى حجم هو (216 ما يعادل 65 كيلوبايت).
    3. MEDIUMBLOB: أقصى حجم هو (224 ما يعادل 16 ميجابايت).
    4. LONGBLOB: أقصى حجم هو (232 ما يعادل 4 جيجابايت).
    يعتمد على أقصى حجم تحتاجه لحفظ الملف مثلا ملفات الصوت لن يتعدى حجم الملف الواحد في أسوء الأحوال 16 ميغا، ففي هذه الحالة سأختار نوع MEDIUMBLOB، أما لو كنت أحتاج مساحة أكبر أو أصغر فهنا سأختار غيره من الأنواع.
     
    - الأدوات والبرامج المستخدمة:
    - سيرفر قاعدة بيانات MySQL (بالإمكان استخدام XAMPP أو SQLite)
    -ملف jar والذي يربط قاعدة البيانات بمشروع Java. (متوفر في المرفقات نسخة 5.1.44 mysql-connector-java-5.1.44.zip)
    على فرض بأنك قاعد على ربط ملف jar بمشروعك في Java سوف أكمل الشرح.
     
    خطوات العمل:
    أولاً: إنشاء جدول في قاعدة البيانات:
    سنقوم بإن شاء ملف داخل قاعدة البيانات لنحفظ بداخله اسم الملف، ونوعه ( The file name extension).
    إذا الجدول (باسم myData) يحتوي على 4 أعمدة، رقم الملف (id), اسم الملف(fullname), نوع الملف (type), الملف (file):
    CREATE TABLE myData(id INT(11) NOT NULL PRIMARY KEY, fullname VARCHAR(35)NOT NULL, type VARCHAR(8) NOT NULL, file MEDIUMBLOB NOT NULL); ثانياً: حفظ ملف باستخدام Java:
    الآن انتهى عملنا داخل قاعدة البيانات وننتقل إلى Java وسنقوم بانشاء class نقوم بتسميته storeData, ونقوم بإنشاء العمليات الازمة بربطه بقاعدة البيانات:
    try { Class.forName("com.mysql.jdbc.Driver"); Connection connect = DriverManager.getConnection("jdbc:mysql://localhost/pro3alam","root", ""); } catch (SQLException e) {} catch (Exception e) {} بعد ذلك نجهز اوجكت من نوع PreparedStatement لنقوم باطلاق كود MySQL من خلاله:
    PreparedStatement preStat = connect.prepareStatement("INSERT INTO myData VALUES(?, ?, ?, ?)"); بعد ذلك نقوم بإنشاء ملف ونحدد موقع الملف الذي نريد حفظه لنفرض بأن الملف في سطح المكتب باسم test ونوع pdf ونقوم بحفظ اسمه ونوعه في متغيرين مختلفين كالتالي:
    File myFile = new File("/Users/abather/Desktop/test.pdf"); String fileName = myFile.getName().substring(0, myFile.getName().lastIndexOf(".")); String fileType = myFile.getName().substring(myFile.getName().lastIndexOf("."), myFile.getName().length()); للتفصيل أكثر في الأكواد السابقة فقد قمت بحفظ اسم الملف داخل المتغيير fileName عن طريق اخذ الجزء من بداية الاسم الى آخر نقطة أي قبل نوع الملف.
    ومن ثم قمت بحفظ نوع الملف داخل المتغيير fileType عن طريق اخذ الجزء من اسم الملف الذي يبدأ بآخر نقطة الى نهاية الاسم.
    من الآفضل حفظ نوع الملف على حدى عن اسم الملف في حال أردت تغيير الاسم أو حفظ أكثر من نوع واحد من الملفات داخل نفس الجدول.
    الآن ننتقل إلى النقطة ما قبل الأخيرة وهي بتجهيز الملف ليتم كتابته داخل القاعدة، ونقوم بتجهيزية عن طريق FileInputStream كما يوضح الكود التالي:
    FileInputStream inputstream = new FileInputStream(myFile); الآن اصبح الملف جاهزة لكتابته دخل قاعدة البيانات، نعود الى PreparedStatement التي قمنا بانشائها ونقوم بادخال البيانات التي نريد حفظها ومن ثم نقوم باطلاقها للكتابة داخل قاعدة البيانات كما يوضح الكود التالي:
    FileInputStream inputstream = new FileInputStream(myFile); preStat.setInt(1, 1); preStat.setString(2,fileName); preStat.setString(3,fileType); preStat.setBinaryStream(4,inputstream, inputstream.available()); preStat.execute(); كما هو واضح في الكود فقد اتممت اضافة القيم الى كل عامو في الجدول من رقم الملف واسمه ونوعه والملف نفسه. 
    ويجب الحذر بأن نوع الميثود المستخدمة لكتابة الملفات هي setBinaryStream. وفي نهاية الكود بعد اطلاق PreparedStatement نكون قد حفظنا الملف داخل قاعدة البيانات.
    نعود لقاعدة البيانات ونبحث عن الملف لنتأكد من وجوده:

    ملاحظة: لا تحاول البحث عن الملف في حال كنت في Terminal لانه لن يكون سوى مجموعة من الرموز غير المفهومه.
    ثالثا: قراءة الملف المحفوظ داخل قاعدة البيانات:
    هنا سنقوم بقراءة الملف السابق من قاعدة البيانات وحفظه على سطح المكتب، في البداية سنقوم بانشاء class باسم restoreData.
    سنقوم بالخطوات السابقة بالاتصال بقاعدة البيانات، ومن ثم نقوم بإنشاء Statement  والبحث عن الصف الذي حفظنا الملف بداخله وتخزينه داخل ResultSet كالتالي:
    Statement statement = connect.createStatement(); ResultSet result = statement.executeQuery("SELECT * FROM myData WHERE id=1"); الان سنقوم بحفظ اسم الملف ونوعه داخل متغير واحد مع تغير بسيط في الاسم ومن ثم إن شاء ملف File وجعل مساره يشير الى سطح المكتب كالتالي:
    result.next(); String fullName = result.getString(2) + "From DB" + result.getString(3); //سيكون هذا اسم الملف الذي سنسترده من قاعدة البيانات //بالامكان تغيير الاسم كيفما نريد ولكن المهم هو نوع الملف File myFile = new File("/Users/abather/Desktop/"+fullName); الان نقوم بانشاء اوبجكت من نوع FileOutputStream والذي سيقوم بكتابة البيانات داخل الملف ومن ثم حفظه على سطح المكتب، كذلك نحن بحاجة لمتغير من نوع  Inputstream لحفظ البيانات من داخل الناتج من قاعدة البيانات وآخر من نوع byte والذي سيكون بمثابة المكان الذي سنخزن فيه البيانات مؤقتاً لكتابتها داخل الملف :
    FileOutputStream outputStream = new FileOutputStream(myFile); InputStream inputStream = result.getBinaryStream(4); byte[] buffer = new byte[1024]; while (inputStream.read(buffer) > 0) { outputStream.write(buffer); } هكذا نكون قد قمنا بحفظ الملف واسترجاعه من قاعدة البيانات.

    أسأل الله العلي العظيم أن أكون قد وفقت لإصال المعلومة بشكل مبسط وسلس.
    واي استفسار حول الموضوع أنا بالخدمة. كذلك السورس كود تجدونه في المرفقات لحفظ واسترجاع الملفات من قاعدة البيانات.
    storeData.java  restoreData.java
    مستوى المقال: محترف
  3.  
    السلام عليكم ورحمة الله وبركاتة
    هذا المقال يسهل لك ايها القارئ ايضاح مفهوم الـ Abstraction (اي التجريد) بالبرمجه من خلال ربطه بالحياه الواقعيه. مناسب لكل من هو مبتدئ او اي شخص يواجه صعوبه في فهم هذا المفهوم. فأنا في فتره من الفترات كنت لا اعرف ماهو هذا مطلقاً, ومن خلال بحثي وقرائتي عنه تكونت لدي صوره واضحه عنه واحببت ان انقل هذه الصوره لك اختي | اخي القارئ. والذي يعتبر التجريد بدوره عامل كبير جداً في البرمجة. وايضاً يعتبر المكون الاساسي لمفهوم الـ Object-oriented programming - OOP.
     
    المعنى الحرفي العربي لكلمة Abstraction
    التجريد.
    اصل ومعنى كلمة Abstraction

    الاصل مأخود من الكلمة اللاتينية abs, والتي تأتي بمعنى away from (اي: بعيداً عن). مثال: لنفرض ان لديك مقلمه بها العديد من الاقلام وقمت بعمل abs للقلم ذي اللون البرتقالي, هنا نستطيع القول انك اخدت هذا القلم بعيداً عن المقلمه. وكصورة عامة نستطيع القول انك قمت بعمل عملية الـ abstraction للمقلمه.
    اي عندما تعمل لشئ abs من بين عدة اشياء, هو فقط ان تاخده بعيداً عن تلك الاشياء. الان كرر عملية الـ abstraction واستمر في عمل abs لكل الاقلام ذوي الالوان الغير اساسيه, حتى يتبقى لديك مقلمه تحتوي فقط على ٣ اقلام وهي الالوان الاساسية الاحمر والاصفر والازرق وهنا نستطيع القول انك اقتربت من انهاء عملية التجريد للمقلمه. اكمل التجريد وأتي بمقلمه اخرى وضع بها الالوان الذي استخرجتهم من الاولى. وهنا اصبحت لديك مقلمتين واحده للإلوان الاساسيه والاخرى للإلوان الغير اساسيه ونستطيع القول ان التجريد قد اكتمل للمقلمه.
     
    الفائدة من تجريد المقلمه
    حتى يسهل على الطفل استخدامها! فوجود اقلام كثيره يجعل الطفل في حيره من امره. ولكن بوجود فقط ٣ اقلام اساسيه يصبح الشئ اكثر سهوله في الاختيار والفهم والحفظ والترتيب الخ... واذا احتاج الطفل اي من الاقلام الغير اساسية فيستطيع الاستعانه بالمقلمه الاخرى.
    اذن نستطيع القول من مثال المقلمه ان فائدة الـ abstraction هي تبسيط الاشياء المعقده الى اشياء سهله, عن طريق ابعادها وفصل الاشياء الجانبيه بحيث في النهاية يتبقى لدينا الاساسيات فقط في الواجهه.
     
    الفائدة من خلال القيام بعملية الـ Abstraction

    خلال القيام بعملية التجريد لشئ ما, يكتسب الدماغ فهم اكثر واعمق لهذا الشئ. فمثلاً الطفل عندما يقوم بتجريد لعبه مكونه من مكعبات اللوجو (اي يعمل abs لكل قطعه في شكل النمر) يكتسب خلال هذه العملية معرفة اعمق للقطع المكونه لهذه اللعبه وكيفية اتحادها مع بعضها البعض لتكوين هذا الشكل. ليصبح لديه في النهاية درايه وقدره اكبر لتكوين نفس الشكل او القدره في الابداع لتكوين اشكال اخرى من مكعبات اللوجو.

    فعند الاتيان بقطع متناثره من اللوجو (المكعبات) لطفل لم يعمل تجريد لاي لعبة من قبل, نرى ان لديه صعوبه في تكوين الاشكال. بعكس الطفل الذي قام بالكثير من عمليات الـ abstraction لـ ألعاب اللوجو من قبل, فهو على درايه كبيره في كيفية عمل كل قطعة صغيره وطرق التحامها بالاخرى, وايضاً تتكون لديه درايه اكبر في فهم الصوره العامه (big picture).
     
     
    معنى الـ Abstraction في البرمجة
    للاسف يوجد الكثر من مفاهيم ومعاني التجريد, فهي كلمه فلسفيه بحته. وسترى معاني غريبه لها في بادئ الامر. ولكن الان لنركز على الهدف من هذا المقال وهو مفهوم وتطبيق التجريد في البرمجه.
    لفهم التعريف تخيل ان مشروعك هو مقلمة الطفل. وان اسطرك البرمجية هي الاقلام بتلك المقلمه. وتذكر كيف جعلنا الامر اسهل على الطفل من خلال التجريد الى مقلمات اخرى. وتذكر ماذا اكتسب الطفل الاخر من خلال قيامه بتجريد قطع اللوجو.
     
    مثال: مشروع به ٥٠ مليون سطر برمجي
    تخيل لو ان فريق من المبرمجين يعملون على مشروع مكون من class واحده فقط (تسمى God Class من اسوء الاخطاء في البرمجة) فكم سطر برمجي ستكون هذه الكلاس؟ لنفرض انها ٥٠ مليون سطر! كما هو الحال في الشفره المصدريه لـ ويندوز فيزتا الرائع جداً! في هذه الحاله يجب على كل مبرمج ان يفهم هذه الكلاس كامله حتى يتعامل معها ويبرمج داخلها! وهذا يخلق صعوبه عاليه بل مستحيله جداً فلا يوجد مبرمج يستطيع ان يحشر ٥٠ مليون سطر في دماغه. ماذا لو احدث احد المبرمجين (مبرمج يريد اضافة ميزة جماليه للاشعارات) تغيير في السطر رقم ٣٣٤٢٣٣٣؟ وسطر ٥٤٣٢٣٤٥٦ قد احدث خطئ وهنق الويندوز! من هو الخارق الذي سيقرئ او يعمل تحليل لـ ٥٠ مليون سطر ليحل المشكله؟ هل سيقوم هذا المبرمج بالتنطط بين الـ ٥٠ مليون سطر بمطرقته الـ Debug! الا توجد طريقه لعمل هذا المشروع حتى يصبح تطويره واصلاحه من قبل المبرمجين في الفريق اسهل بكثير؟ نعم وهو بتطبيق مبدء التجريد!
     
    الحل هو تطبيق الـ Abstraction
    الهدف المراد تحقيقه: هو معرفة القليل من الكود الاساسي في هذه الكلاس العملاقه حتى يسهل حفظه من قبل كل مبرمج في الفريق, ويخلق لديهم المزيد من الكفائه للتعامل مع الكود والاضافه والاصلاحات.
    لنجرد كبدايه بعض الاسطر بهذه الكلاس العملاقه: لنفرض ان هنالك في هذه الكلاس كود مكون من ١٠٠٠ سطر وظيفته هي اظهار اشعار للمستخدم, فلماذا على كل مبرمج ان يحفظ هذا الكود الكبير! اليس من الاسهل ان نقوم بتغليف هذا الكود داخل ميثود ونسميها بفعلها كـ showNotification ونطلب من كل مبرمج فقط ان يحفظ اسم هذه الميثود و ماذا تخرج (return) و ماذا تريد ان يدخل بها (parameters). ويقوم باستدعائها فقط عند الحاجه! اذاً بهذا العمل قد قمنا باخفاء التعقيدات (اخفاء كيفية عمل كود الاشعارات ذي الـ ١٠٠٠ سطر).

    فأنت عندما ترى مشغل موسيقى امامك كل ماتراه هو واجهه (interface) فقط. ولا ترى مابداخل هذا المسجل من قطع الكترونيه. وتعرف ان هذا المسجل يدخل فيه شريط كاسيت و يخرج صوت وذلك عن طريق الضغظ على زر التشغيل. فرؤيتك الى interface او تعاملك مع interface يسهل لك حياتك في استخدام الاشياء ولا داعي للتعقيد ومعرفة كيفية سير كل الامور بداخل هذه المسجل.
     
    تطبيق المزيد من الـ Abstraction على الكلاس العملاقه ذي الـ ٥٠ مليون سطر
    الان لنرجع الى الكلاس العملاقه مره اخرى.
    اليس من الافضل ان نغلف هذا الكود الى العديد من الميثودات (كما قمنا في تغليف كود الاشعارات سابقاً) ونقوم بحفظ فقط اسمائها و مداخلها و مخارجها. ايضاً اليس من الافضل ان نقسم هذه الكلاس الكبيره الى عدة كلاسات اخرى. ونجرد اسطرها البرمجيه الى ميثودات بالكلاسات الاخرى. وان نجعل كل كلاس جديده تحتوي فقط على الميثودات المتقاربه (كالطفل والمقلمات). توقف هنا وتمعن! (هنا في هذه النقطة صنعنا شئ اسمه API في البرمجه). واخيراً لنعطي كل مبرمج من الفريق كلاس خاص به, فارغ تماماً, ونجلب له الـ Documentation ليتعلم او ليبحث عن اسماء تلك الميثودات ويعرف مخرجاتها ومدخلاتها, ويستدعي مايحتاجه لكتابه واكمال كلاسه للقيام بدوره في الفريق وانجاز المشروع.  
    كلاس مبرمج الاشعارات الان كيف ستكون؟
    تخيل كلاس المبرمج الذي يعمل على تجميل الاشعارات, هو الان يحتاج فقط ان ينادي على ميثود الـ showNotification ويقوم بكتابة بعض الاسطر القليله التي تنشئ جماليات لإضافتها الى الاشعارات. والذي من المؤكد انه سوف يبدع في دوره كثيراً لان مجمل تركيزه في الاشعارات, وليس كما كان في البداية مشغول في حفظ و التنطط بين الـ ٥٠ مليون سطر برمجي ومحاولة اصلاح ماقد تسبب به من اخطاء.
    فنحن بعملنا هذا قمنا بتجريد الكلاس العملاقه هذه وانتزاع منها اسطر برمجيه بالملايين, وتغليفهم في كلاسات خاصة بهم داخل ميثودات باسماء افعالهم, وجعلنا فقط بها الاسطر الاساسية وكأنها اصبحت interface يسهل على المبرمج التعامل معها (كمشغل الموسيقى والمستخدم العادي له!!!). مطبقين مبدء التجريد الـ abstraction وبالاستعانه ايضاً بمبدء التغليف الـ encabsulating والذي يعتبر بدوره جزء كبير من تحقيق عملية التجريد في البرمجه. واخيراً قمنا بتحويل المشروع كلياً الى شئ يسمى API حتى يسهل على المبرمج ندائه واستخدامه وتطويره.
     
     
    نصائح
    لاتتعمق في التجريد, والا سوف تصنع مشروع معقد على نفسك. لفهم الاشياء التي تراها في صوره كامله, حاول تجريدها قطعه قطعه (عملية التجريد). كتجريد مكونات الـ API للاندرويد. لتركيب صوره كامله لشئ تريد تعلمه, حاول تركيبها قطعه قطعه (عملية التجريد). اي شئ صعب فهمه حاول تجريده, وفهم القطع الصغيره منه وكيفية التحامها مع الاخره. التجريد وجد للتسهيل, لذلك لاتتفاجأ عندما ترى مكتبه او مشروع او api يحتوي على مئات الكلاسات والميثودات. فقط خد نفس عميق وابدء بفهمه قطعه قطعه (جرده) او قم بنداء مايلزم لاتمام شغلك فقط. عند تصميم مشروع في البدايه قم بالتفكير في التجريد, انظر الى الصوره الكبيره كما يفعل الطفل ذي الخبره في اللوجو, قم بعمل اللازم من كلاسات وميثودات, وفي النهايه استخدمها كما تحب في الـ mainActivity.class كانك تركب تطبيقك بالاندرويد في هذه الكلاس, ليس كتابة جميع الاكواد بها وجعلها (God Glass) وهذا شئ خاطئ جداً.  
    نقاط واسئله للتأمل في التجريد
    هل تستطيع الربط بين مفهوم الـ Abstraction و مفهوم كلاس الـ Abstract Class في مخيلتك! هل ترى الفلسفه في فكرة الربط بين واجهة المستخدم الرسوميه لتسهيل حياته, وواجهة المبرمج والتي هي ملف الـ interface لتسهيل عمله كمبرمج! هل تستطيع التنقل بسهوله بين طبقات التجريد؟ هل تستطيع عكس التجريد؟ هل مر عليك مصطلح: برمج الى انترفيس وليس الى كلاس؟  
     
    امثله برمجيه
    تجريد مشروع لتطبيق اندرويد الى كلاسات وبكجات كثيره:
    فبدلاً ان يكون البرمجه محشوره كلها في كلاس الـ mainActivity قمت بانشاء العديد من الكلاسات والبكجات لترتيب اسطري البرمجه. ثم ندائهم في الـ mainActivity لأصنع التطبيق.

     
    والان مثال للتجريد بالكود
    سأستخدم لغة البايثون فهي اسهل للفهم واقل كتابة من الجافا. وهذا فقط مثال للتوضيح وليس Abstraction محض.
    لدينا مبرمجان يعملون على انجاز برنامج, وظيفة هذا البرنامج هي: يطلب من المستخدم ادخال اسمه. ثم المبرمج الاول يقوم بكتابة كود يطبع حرف حرف للمستخدم مع مكان وجود الحرف في اسمه. اما المبرمج الثاني فيقوم باخد اسم المتسخدم وحساب عدد الحروف المكرره ثم يطبعها ايضاً حرف حرف مع عدد تكرارها.
    الكلاس قبل عمل الـ Abstraction لها:
    star = (chr(10029)) user_name = input("Enter your name:") user_name_total_char = 0 for i in range(len(user_name)): print(user_name[i] + " --> " + str(i + 1)) for i in range(len(user_name)): total = 0 for j in user_name: if j == user_name[i]: total += 1 print(user_name[i], "--->", total, "repeated")  
    الكلاس بعد عمل الـ Abstraction لها
    اخرجنا جميع الاكواد الى كلاسات فرعيه. واصبحت الكلاس هكذا:
    initialize() ask_user_for_name() calculate_user_characters() calculate_user_characters_counts() print_user_chars() print_user_char_counts() ويستطيع اي مبرمج اخر استخدام هذه الميثودات كما يشاء اذا احتاجها في تطوير شئ جديد كميزه بالبرنامج (تذكر هذا فقط مثال بسيط لتسهيل فهم التجريد والذي هو كافي تماماً في اغلب الحالات).
     
    الـ Abstraction وتمثله في الطبيعه (خلق الرحمن)

    في النهاية انظر الى الصوره (نبتة الماء) وتمعن في جمال صنيع الخالق وعظمته في الخلق. انظر الى قوة التجريد الذي من خلاله يخلق نبته جميله جداً. تمعن في كل قطعة بالنبته (جردها بعينك, اي اعمل لها abs بخيالك) وكيفية التحامها وتركيبها Composite وتناسقها مع القطع الاخرى لتكون في النهايه نبتة الماء كالصوه النهائيه لعملية التجريد. انظر الى درجة اعمق من التجريد, فكر في طريقة غدائها, وغداء كل قطعه منها على حدى الخ... تأمل!
    هل توجد هناك مقارنه بين ابداع الخالق في عملية التجريد, وعفسة المبرمج في عملية التجريد عندما ترى مشروعه من الوهله الاولى! فسبحان الله على بديع خلقه.
     
     
    مستوى المقال: متوسط
  4. السلام عليكم ورحمة الله وبركاتة
    هذه مقالة مبسطة لشرح مفهوم الـ Class بلغة البرمجة الـ Java لكل من يعاني من صعوبة في فهمها. فمن مدة قمت بكتابة مقاله مشابهه لها لتقريب مفهوم الكلاس بالبايثون في احدى المواقع الانجليزيه وقد نالت على الاعجاب, فأحببت ان اكتب مقاله تخدم نفس الهدف ولكن باللغة العربية وبلغة البرمجة الاكثر عمقاً وهي الجافا. الشرح مناسب لكل الاعمار, يستخدم الطريقة المشهورة في تبسيط الامور وهي: explain like I'm five, اي اشرحها لي كأني طفل او مبتدئ. فأرى ان كل شخص يريد تعلم شئ جديد يفوق مستواه الحالي في الفهم, في البداية يجب عليه ان يتواضع ويحاول فهمها كانه يملك دماغ طفل! بعيداً عن الغطرسة والمصطلحات المعقدة والتي بدورها تصعب الامور.
     

    هذه الصوره لـ ام وابنتها ونرى مدى تشابههم مع بعضهم البعض, وكأنهم يمثلون Class و Object.
     
    شرح مفهوم الكلاس بشكل تقريبي للحياة الطبيعية
    سيكون الشرح على شكل نقاط حتى يسهل الفهم, وستكون الامثله تقريبيه للحياه الطبيعيه لتسهيل الفهم فقط لاغير. وتستطيع قرائة هذه المقاله اكثر من مره والرجوع لها اذا واجهت مصطلح غامض اثناء تعلمك البرمجة بلغة الجافا. وان شاء الله سوف تنير لك طريقك.
    الـ Class تمثل في الحقيقة امك. الـ Object هو انت. و Object اخر يعتبر اختك او اخاك. ونستطيع تسميتكم بـ Instances of the class. اي اولاد ملكيتكم ترجع الى امكم. الـ Class Constructor تستطيع القول انه الرحم الذي سوف تتكون بداخله انت وجيناتك. الـ Declaration وهي عملية تحديد الـ Variables قبل استخدامها, اي تصريح الام بقيمها التي تتدخل في جيناتك و عملية ولادتك. الـ Class Fields تمثل قيم الام, والتي تتدخل في عملية ولادتك دائماً بشكل فريد عن باقي اخوتك واخواتك. كأسمك, لون بشرتك, وتسمى نسبتاً لك بالعادة Object Attributes. وفي بعض الاحيان يكون بعضها قيم خاصة للإم نفسها كأسم امك (ملاحظة بالنسبة لإسم الام: راح يكون static و public اي ثابت وعام وتستطيع السؤال عنه بدون اوجكتات. اما باقي الاشياء فمن المفضل جعلها private اي خاصة). الـ Instantiation هنا يبدئ التمهيد لعملية الولادة لك. الـ Initialization هنا قامت بولادتك الام. طبعاً باستخدام كلمة new والنداء على الـ Constructor اي الرحم. الـ Initialization Block عباره عن قطعه من الكود تعمل في كل مره تم انشاء اوبجكت من الكلاس, وتعمل مره واحده للكلاس نفسها. مثلاً كانها صرخة الولادة لكل طفل, او تحول المرأه الى ام, فالتحول هذا يصبح مره واحده في حياة المرأه. ألـ Class Methods or Functions تعتبر الافعال التي سوف تعلمك اياها امك وتختمها عن ظهر قلب بعد ولادتك. ككيفية ترتيب سريرك, كيفية الاكل, فرك اسنانك بالفرشاه والمعجون, نطق اسمك الخ.... وايضاً بعض من هذه الافعال راح تكون static اي امك التي تقوم بها, ونستطيع استخدامها من خلال امك بدون اوبجكتات (بدون حاجتك), كفعل نطق امك لاسمها متى شائت.  الـ Getter and Setter نتدرج من الافعال (الميثودز) التي تعلمك اياه امك. الـ Inheritance اي كلمة extends تاتي بمعنى الوراثة, مثال: لو وضعنا هذه الكلمة بعد اسم امك ثم اتينا باسم جدتك, سوف ترث امك جميع تعاليم جدتك وافعالها وقيمها وطريقة تربيتها لإولادها وتطبقها عليك (الاوبجكت). الـ Super تاتي هذه الكلمة في حالة الوراثة, اذا احتجت مساعده من الجده, تطلبها من خلال كتابة هذه الكلمة. في حالة الوراثة تسمى امك بكلاس الـ Child Class وجدتك باسم الـ Parent Class او Super Class. وانت تصبح ملكيتك الى امك, والى كلاس جدتك ايضاً. وايضاً (في حالة الورثاة) اذا اردت ان تتعامل مع امك حالياً تستخدم كلمة this واذا اردت ان تتعامل مع جدتك تستخدم كلمة super. الـ Overriding او كلمة @Override الموجوده فوق بعض افعال (ميثودات) الام التي ورثتها. هذه الكلمة تضعها الام في حالة تريد تغيير في فعل ورثته من جدتك. اي اذا ورثة وصفة طبخ ما وتريد تغيير بعض من مقاديرها, هنا تستخدم هذه الكلمة. لغة الجافا لاتحب الوراثة في كلاساتها! عكس لغة السي شارب! فالجافا لاتسمح للوراثة الا من شخص واحد او بالاحرى من جهه وحده. فإما ترث انت من جهت امك او من جهت ابوك! فقط لاغير. لتفتادي مشاكل التعقيد كمشكلة الالماسة القاتلة في البرمجة قدر المستطاع! الـ implements تستخدم هذه الكلمة لتحقيق رغبة الوراثه المتعدده واشياء اخرى كثيره. فهي تأتي بعد اسم الكلاس تلحقها باسماء كثيره من الـ interface. وهكذا تصبح للكلاس خصائص متعدده كثيره بدون الوراثه, نستطيع القول هنا انها مشابهه بالتقليد! اي ان امك قامت باخد وتقليد طرق وقيم وافعال كل من عماتك, خالاتك, جاراتك الخ... في تربيتك, بدون الحاجه منها ان ترثهم. الـ interface ليس معناتها واجهت المستخدم, بل المقصود هنا بالبرمجة هي الواجهه التي تكون بينك وبين اي طرف اخر تريده بالبرمجة. نستخدمها في البرمجة لإجبار الكلاس (امك) على اضافة افعال وقيم لها, بدون الحاجة الى الوراثة. وعلى امك ان تكتب هذه القيم والافعال كما تريد. دائماً فضل استخدام الـ interface على الكلاس. اي دائماً فضل الـ implements على الـ extends. ملاحظة: في حالة الوراثة لاتحتاج الى كتابة جميع افعال (ميثودز) تلك الكلاس. ولكن في حالة الـ implemention من interface تحتاج بشكل ضروري الى كتابة جميع تلك الافعال (ميثودز) كـ @Override والا ستتعطل الكلاس. ملاحظة: للـ interface استخدامات متعدده وكثيره جداً. الـ abstract كلمة تستخدم قبل اسم الكلاس, لجعها كلاس مجرده! اي جدة قابلة للوراثة فقط ولا تستطيع ولادة اي كائن لا امك ولا انت! اي كانها جدة قامت بتبني امك ثم قامت امك بوراثتها! يقوم عملها كـتعامل امك مع الـ interface تقريباً.  
    شرح بعض من كلمات لغة الجافا التي تتداخل مع مفهوم الكلاس بشكل تقريبي للحياة الطبيعية
    كلمة الـ private اي خاص, تستخدمها للاشياء الخاصة فقط, كمثلا لون ملابسك الداخلية. كلمة الـ public اي عام, تستخدمها للاشياء التي تريدها ان تكون عامه ومنظوره من قبل الجميع كوجهك. كلمة الـ protected اي خاصة بعض الشئ, تستخدمها للاشياء التي تريدها فقط ان تكون معروفة بين افراد اسرتك واقربائهم, ومخفيه على العالم. كاسرار عائلتك مثلا. بدون كلمة! خاصة فقط لك و لعائلتك التي في منزلك فقط لا اقرباء. وهذا هي القيمة الافتراضية بلغة الجافا, اي انك اذا لم تختر اي من احد الكلمات الثلاث السابقة. كلمة الـ final تستخدم للاشياء التي نريدها ان تكون غير قابله للتغير. كنسبك الى امك, لاتستطيع تغييره ابداً.  
    مثال برمجي للكلاس:
    هذا مثال برمجي يحاكي ماتم تناولة في النقاط السابقة.
    كلاس الام:
    حاول ان تتمعن بالكلاس وارجع الى النقاط بالشرح لتوضيح الفهم لديك وتقريب المعنى.
    /** * Created by mohammad on 10/13/17. */ public class Mother extends GrandMother implements Aunt, Uncle{ // Class Fields public static final String TAG = "Mother Class Tag"; // <--- filed can not be changed private String mName; private String mSkinColor; public static String mYourMotherName; private static int mTotalChild = 0; // Initialization Block - running just one time // Static one static { Log.d("TAG", "static initializer: Woman Become Mother"); } // Initialization Block - running each time an object created // instance one { Log.d(TAG, "instance initializer: Mother Cry of pain"); mTotalChild = mTotalChild + 1; } // Class Constructor public Mother(String childName){ mName = childName; } // getters and setters (same as methods/functions) public static int getChildNumber(){ return mTotalChild; } public static void setYourMotherName(String yourMotherName){ mYourMotherName = yourMotherName; } // methods / functions public void eat(){ Log.d(TAG, this.mName + " eat: I'm eating ..."); // <-- this, refer to who is eating here Log.d(TAG, mName + " eat: I'm eating ..."); // <-- or by using m principle better } public void speak(){ Log.d(TAG, "speak: My name is: " + mName); } // method from GrandMother class // Okay to remove it if you don't need it @Override public void cookingPizza() { super.cookingPizza(); // <-- making the pizza with grandMother recipe. // <-- if you want yours recipe remove super.cookingPizza(); // <-- and write your recipe. } // method from you Aunt interface // you must implemented it (have it) or your program gonna crash (you can't remove it) // and it's okay to leave its body empty. @Override public void drawing() { } }  
    استخدامها:
    // Instantiation Initialization Mother firstChild = new Mother("Noah"); Mother secondChild = new Mother("Emily"); // setting a name for your mother by using the setter Mother.setYourMotherName("Emma"); // calling your mother name from her static fields Log.d(TAG, "Your MotherName is : " + Mother.mYourMotherName); // making you and your sister doing what your *mother* teach you firstChild.cookingPizza(); // <-- *her* inherited cooking pizza from her grand mother and teach it to you. secondChild.eat(); // <-- *her* teach your sister how to eat. // asking your mother how many child she give birth to Log.d(TAG, "Total Children: " + Mother.getChildNumber());  
    النتيجة:
    Woman Become Mother initializer: Mother Cry of pain initializer: Mother Cry of pain Your MotherName is : Emma Class: cookingPizza: Pizza is cooking Class Tag: Emily eat: I'm eating ... Class Tag: Emily eat: I'm eating ... Total Children: 2  
    اخيراً
    اتمنى ان المعلومة وصلت بسهوله لك اختي \ اخي القارئ. فهذه كانت فقط لايضاح وتقريب معنى مفهوم الكلاس. وليس شرح كامل للكلاس او طرق انشائها. واكرر اتمنى ان المعنى قد اتضح لديك عزيزي القارئ.
     
    مستوى المقال: مبتدئ
  5. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته،،
    موضوعنا اليوم سيكون عن المصفوفات التي هي من أهم تراكيب البيانات التي نرتب بها البيانات. وهي طريقة مستخدمة في أغلب لغات البرمجة العالية المستوى (high level programming languages).

    ماهي المصفوفة؟
    المصفوفة عبارة عن كائن (Object) يتم فيه تخزين عدد محدد من بيانات من نفس النوع.
    قد يبدو الكلام النظري هنا صعب الفهم فدعنا نطرح مثالا للتوضيح؛ افترض أن لديك درجة لطالب في مادة الرياضيات وتود تخزينها في البرنامج، سيكون هذا سهلا للغاية كل ما عليك هو إنشاء متغير واحد فقط وتعطيه القيمة (درجة الطالب)، لكن ماذا لو أردت تخزين درجات جميع الطلاب في شعبة الرياضيات (100 طالب)!! من الصعب جدا أن نعرف 100 متغير، غير أن ذلك سيستهلك مساحة كبيرة من الذاكرة. فالحل هو إنشاء مصفوفة!
    فهنا تكمن فائدة المصفوفات إذ أنك من خلال إنشاء مصفوفة واحدة حجمها 100 ستتمكن من تخزين ال 100 درجة في مكان واحد وباسم متغير واحد.
     
    إذن، كيف تنشئ مصفوفة؟
    هناك عدة أمور يجب تذكرها جيدًا عند إنشاء المصفوفات:
    1-    يجب أن تكون جميع البيانات في المصفوفة من نفس النوع (data type).
    مثال: أن تكون جميع درجات الطلاب من نوع int.
    2-    يجب أن يكون حجم المصفوفة ثابت لا يتغير (fixed size).
    مثال: أن يكون حجم مصفوفة درجات الطلاب 100 فلا يمكن إضافة درجة أي طالب بعد ال100.
     
    تعريف المصفوفة (Array declaration) يكون كالآتي:

    مثال:

    فبعد هذا السطر نكون قد عرفنا المصفوفة فقط ولم ننشئ المصفوفة بعد، بمعنى أنه تم إنشاء اسم متغير يشير إلى null (لا شيء) في الذاكرة.

    إنشاء المصفوفة (Array creation) يكون كالآتي:

    مثال:

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

    وبإمكاننا أيضا عمل تعريف وإنشاء للمصفوفة في نفس السطر كالآتي:

    مثال:

     
    حسنا، للتو تعلمنا كيف نعرف وننشئ مصفوفة، لكنها ستكون بقيم ابتدائية! ما معنى ذلك؟
    أي أن المصفوفة ستكون معبأة بقيم ابتدائية خاصة بنوع البيانات فكما في مثالنا السابق ستكون القيم الابتدائية 0 لأن نوع البيانات هو int بينما لو كان نوع البيانات Boolean ستكون القيم الابتدائية false وهكذا على حسب نوع البيانات.
     
    لكننا لا نريد ذلك! نريد أن نعبأ المصفوفة بالقيم التي نريد! ولكن كيف نصل إلى عناصر المصفوفة؟
    كل المصفوفات عناصرها مرقمة من 0 إلى (حجم المصفوفة -1) ويسمى هذا الترقيم بال index فهو بمثابة عنوان للعنصر وبه نستطيع الوصول إليه.
     
    مثلا لو كان عندي مصفوفة اسمها numbers حجمها 4 لتخزين أربعة أرقام فسيكون ال index  لها من 0 إلى 3، إذ أن العنصر الأول سيكون متواجد عند الindex رقم 0 والعنصر الثاني عند الindex رقم 1، وهكذا إلى نهاية المصفوفة.

     
    مثلا لو أردنا وضع رقم 5 في العنصر الأول سنقوم بعمل الآتي:
    ; القيمة المراد وضعها =  [index] اسم المتغير
    ;numbers[0]=5
    ولو أردنا وضع رقم 90 في العنصر الأخير سنقوم بعمل الآتي:
    ; القيمة المراد وضعها =  [حجم المصفوفة-1] اسم المتغير
    ;numbers[numbers.length-1]=90

     
    استخدمنا هنا خاصية خاصة بالمصفوفات تسمى length تعطينا حجم المصفوفة، وقمنا بإنقاص 1 من حجم المصفوفة لأننا سنتعامل مع index وآخر حد للindex هو حجم المصفوفة-1. وكيفية استدعاء هذه الخاصية كالآتي:
    length.اسم المصفوفة
     
    هذه الطريقة مفيدة في حالة أردنا إجراء تعديلات على عناصر محددة، لكن لو أردنا تعبئة المصفوفة كاملة فهذه الطريقة ستكون مضيعة للوقت!
    لذلك نحتاج أن نسنخدم الloop وهي أن نمر على كل عنصر بالترتيب ونضع فيها القيمة التي نريدها.
     
    مثلا لو أردنا إنشاء مصفوفة حجمها 5 فيها الأرقام من 1 إلى 5 سيكون كالآتي:

     *هنا i+1 لأن index يبدأ من الصفر ونحن نريد المصفوفة تبدأ من رقم 1.
     
    ولو أردنا طباعة عناصر المصفوفة سنحتاج إلى loop أيضا كالتالي:

     
    Output:

    وهكذا في جميع العمليات التي تجرى على المصفوفات سنحتاج إلى loop وننتبه إلى أن الloop يجب أن تنتهي عند آخر index في المصفوفة ولا تزيد لكيلا يظهر الخطأ ArraysOutOfBoundException.
     
    *المصادر:
    كتاب  Introduction to Java programming, Tenth Edition, Y. Daniel Liang.
    مستوى المقال: مبتدئ
  6. بسم الله الرحمن الرحيم
    عندما نريد إنشاء  instance من class معين فإننا غالبا ما نقوم بإستخدام public constructor, لكن هنا طريقة أخرى, يجب أن يكون المبرمج ملماً بها, ألا وهي  public static factory method. ببساطة شديدة هي دالة static تقوم بإرجاع -return- لـ instance   من  class, على سبيل المثال:
    public class Client { public static Client getInstance() { return new Client(); } } كما نلاحظ أن المفهوم في غاية البساطة, لكن متى أحتاج أن أستخدمه ؟ , سنقوم الان بالمقارنة بينه وبين  Constructor, ونستعرض المميزات والعيوب.
    أولا, تتميز static factory method بكونها قابلة لتسمية, فعلى سبيل المثال لو كان لدينا مركز رياضي ونوعين من العملاء, مشترك وزائر, المشترك ندخل أسمه, أما الزائر فنكتب فقط زائر, فسيكون شكل class كالتالي
    public class Client { private String name; public static Client getVisitorInstance() { Client client = new Client(); client.name = "visitor"; return client; } public static Client getSubscribedInstance(String name) { Client client = new Client(); client.name = name; return client; } } دعنا نقوم بإستدعائها, واستدعاء constructor.
    Client client1 = Client.getVisitorInstance(); Client client2 = Client.getSubscribedInstance("Abdulaziz"); Client client3 = new Client(); Client client4 = new Client("Abdulziz"); كما نلاحظ, في static factory method من النظرة الأولى, تمكنت من معرفة نوع العميل, بالإضافة إلى أنه لو أراد شخص ما إكمال تطوير المشروع, سيتمكن من التعامل مع class الذي قمت ببنائه دون النظر فيه -Readability-, على عكس  public constructor.
    ثانيا, من خلال static factory method يمكنك أن تجبر مستخدم الـ class على إنشاء instance واحد فقطلهذا الـ class, وهو ما نسميه بـ singleton, كما في المثال
    public class Client { private static final Client client = new Client(); private Client(){ } public static Client getClient() { return client; } } كما نلاحظ أن constructor private, بمعنى أنه لا يمكنك إنشاء instance عن طريقه, لكن تستخدم static factory method والتي دائما ستعيد لك نفس  object الذي هو client, وبهذا لن تحصل إلا على object واحد فقط عن طريق هذا class.
    ثالثا, يمكن لـ static factory method أن يقوم بعمل return لـ  instance من sub-type لـ class, على سبيل المثال لدينا class يقوم بإزالة الزوائد من القيم الداخلة إليه, مثلا لو تلقى قيمة 0010 يقوم بحذف الأصفار, ولو تلقى “محمد  ” يقوم بحذف space وهكذا, لنبدأ في الكود.
    بداية سنقوم بإنشاء Interface بإسم  trimmer
    public interface Trimmer<T> { T trim(); } الان, سنقوم بإنشاء class لتعامل مع String
    public class StringTrim implements Trimmer<String> { String value; StringTrim(String value) { this.value = value; } @Override public String trim() {...} } وأخر لتعامل مع Integer
    public class IntegerTrim implements Trimmer<Integer> { Integer value ; IntegerTrim(Integer value) { this.value = value; } @Override public Integer trim() {...} } نلاحظ أن access modifier  لـ constructor من نوع  package-private أي لا يمكن الوصول إليه من خارج  package,  ثم نقوم بإنشاء class  نستخدمه إذا ما أردنا الإستفادة من classes السابقة
    public class Trimmers { private Trimmers(){} public static Trimmer<String> getTrimString(String s){ return new StringTrim(s); } public static Trimmer<Integer> getTrimInteger(Integer i){ return new IntegerTrim(i); } } نلاحظ هنا كيف استفدنا من static factory method, بحث أنه قام بإرجاع object, عبارة عن sub-type لـ return type.
    وفي main نستدعيه بالطريقة التالية:
    Integer i = Trimmers.getTrimInteger(0150).trim(); String s = Trimmers.getTrimString(" abdulaziz").trim(); وهذا الأسلوب يسمى  interface-based API أو interface-based frameworks
    بعد استعراضات المميزات لـ static factory method, لنستعرض السلبيات, وهما اثنتين.
    الأولى, لا يمكن الوراثة -inheritance- من class لا يوجد فيه public or protected constructor, ففي هذه الحالة لا يمكن لـ static factory method أن تعوض constructor.
    الثانية, أن static factory method قد لا يمكن تمييزها بسهولة عن بقية static methods التي بداخل class,  لذلك تستخدم عادة بعض التسميات المتعارف عليها, لتحل هذه المشكلة.
    الان, لنمثل علىstatic factory method في Android, فلو أردنا أن نقوم بإنشاء activity داخلها fragment سيكون الكود كالتالي
    public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FragmentManager manager = getSupportFragmentManager(); Fragment fragment = manager.findFragmentById(R.id.fragment); if (fragment == null){ fragment = new BlankFragment(); manager.beginTransaction().add(R.id.fragment,fragment).commit(); } } } وفي Activity أخرى
    public class SecondActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_secound); FragmentManager manager = getSupportFragmentManager(); Fragment fragment = manager.findFragmentById(R.id.fragment); if (fragment == null){ fragment = new BlankFragment(); manager.beginTransaction().add(R.id.fragment,fragment).commit(); } } } لنقوم الان بتحسين هذا الكود, سنقوم بالتالي, أولا بناء static factory method داخل fragment
    public static BlankFragment newInstance() { BlankFragment fragment = new BlankFragment(); return fragment; } ثم نقوم ببناء BaseActivity كالتالي
    public abstract class BaseActivity extends AppCompatActivity { protected abstract Fragment createFragment(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity); FragmentManager manager = getSupportFragmentManager(); Fragment fragment = manager.findFragmentById(R.id.fragment); if (fragment == null){ fragment = createFragment(); manager.beginTransaction() .add(R.id.fragment,fragment) .commit(); } } } لاحظ هنا أن هناك دالة ستعيد لنا fragment سنستخدمها داخل  oncreate, وستظهر فائدة هذا الشيء عندما نجعل MainActivityb و SecoundActivity ترث منها, فيكون شكل الكود  كالتالي
    public class SecondActivity extends BaseActivity { @Override protected Fragment createFragment() { return BlankFragment.newInstance(); } } public class MainActivity extends BaseActivity { @Override protected Fragment createFragment() { return BlankFragment.newInstance(); } } إلى هنا أتمنى أن أكون وفقت في تبسيط هذا المفهوم,
    والسلام عليكم ورحمة الله وبركاته.المصادر:
    Big nerd ranch Android
    Effective java
    Static factory methods vs traditional constructors
    مستوى المقال: محترف
  7. شرح الـ Interface في جافا
     
    ما هو الـ interface؟
    الـ interface يشبه كثيرا الـ abstract class في أنه يحدد خصائص مشتركة للكائنات (objects) في كلاسات لها علاقةوراثية ببعضها (Inheratance) بالإضافة إلى أنه يحدد يحدد خصائص مشتركة للكائنات (objects) في كلاسات ليس بالضرورة  أن يكون لها علاقة ببعضها وهو ما يميز الـ Interface.
    لم تضح الصورة لك بعد؟ لا بأس سأشرح لك بمثال
    لو كان عندي Abstract class اسميته Fruits وهو (parent class (super class لمجموعة من الفواكه هي الموز والبرتقال (child classes) وأنشأت Abstract class آخر أسميته Animals  وهو (parent class (super class لمجموعة من الحيوانات الدجاجة والأسد (child classes)، ثم أنشأت Interface أسميته Eddible (قابل للأكل).
    لاحظ أن الموز والبرتقال بإمكاننا أن نقول أنها فواكه لأن العلاقة هنا وراثية (Inheratance) فأي موزة هي فاكهة وأي برتقال هو فاكهة، وأيضا بإمكاننا أن نقول أن الموز والبرتقال قابلان للأكل.
    والشئ نفسه ينطبق على الدجاجة والأسد في كونهما حيوانات لأن العلاقة وراثية فأي دجاجة هي حيوان وأي أسد هو حيوان،وأيضا بإمكاننا أن نقول أن الدجاجة قابلة للأكل لكن لا يمكننا القول بأن الأسد قابل للأكل فهنا الـEdible interface سيصلح فقط للدجاجة دون الأسد.
    إن ما أردت توضيحه هو أن الفواكه والحيوانات ليس لها رابطة واضحة أو خصائص مشتركة لكن الـ Interface أوجد خاصية مشتركة بينها وهي قابلية الأكل وهذا ما يميز الـInterface عن الـabstract class.
     
    لماذا نستخدم الـ interface؟
    ببساطة لأن Java لايدعم Multiple Inheratance (الوراثة المتعددة)، وفي أغلب الأحيان نحتاج لأكثر من كلاس لنأخذ منه خصائص مشتركة فالحل هو الـInterface.
    *ملاحظة: بإمكان الكلاس أن يكون له علاقة وراثية واحدة فقط أي أن يكون له Super classs واحد فقط، بينما بإمكانه أن يكون متعدد الـInterfaces وتسمى هذه العلاقة Interface Inheratance.
     
    كيف ننشئ الـ interface؟
    الصيغة العامة للـInterface هي:

    مثال:

     
    كيف نستخدم الـ interface؟
    ليستخدم الكلاس الـInterface المطلوب نستخدم كلمة implements بعد اسم الكلاس وقبل اسم الـ Ineterface كما هو موضح في المثال.
    وبطبيعة الحال بما أن في الـInterface يوجد Abstarct Method فيجب علينا أن ننفذ Implementation للميثود في الكلاس الذي استدعى الـInterface وإلا ستبقى الميثود abstract وسيتحول الكلاس إلى abstract class.
    مثال:

    main class:

    Output:

     
     
    *المصادر:
    كتاب  Introduction to Java programming, Tenth Edition, Y. Daniel Liang.
    مستوى المقال: مبتدئ

  8.  
    بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    في هذا الموضوع، سنستعرض الStreams، وهي عبارة عن API جديدة ورائعه تم اضافتها في التحديث الأخير للJava 8.
    باستخدام الStreams، ستستطيع معالجة بيانات الCollections كأنك تقوم بعمل Query في احد الSQL databases، وذلك بطريقة تعريفية بسيطة دون الحاجة لكتابة Loop في كل مرة تريد معالجة البيانات لتخرج بنتيجة معينة (جمع عناصر الArrayList على سبيل المثال)، وذلك بكتابة سطر برمجي واحد فقط!
    هناك ميزة أخرى أيضا للStreams، وهي امكانية تفعيل جميع أنوية المعالج لتسريع عملية تنفيذ البرنامج دون الحاجة الى كتابة سطر واحد من كلاس الThreads المزعج!
     
    ما هو الStream؟                                             
    سنذكر تاليا أهم سمات الStream في الجافا:
    تسلسل عناصر: الStream هو عبارة عن تسلسل لعناصر يتم استخلاصها من أحد المصادر (Sources) -قد تكون Array أو ArrayList الخ-، حيث يقوم الStream بـ قراءة/معالجة بيانات هذه المصادر عند الحاجة فقط المصادر: قد تكون Collection, Arrays, I/O العمليات: يدعم الStream مجموعة من العمليات (أو methods) على سبيل المثال لا الحصر: filter, map, limit, reduce, find, match تكرارات تلقائية: الStreams تدعم التكرارات التلقائية (Automatic Iterations)، أي كما قلنا سابقا، لن تكتب المزيد من الloops، كل ماعليك فعله هو كتابة سطر واحد باستعمال الStreams والجافا ستقوم بالباقي  
    إنشاء الStream                                               
    في الجافا 8، هناك طريقتان لإنشاء Stream:
    ()stream: ستنشئ ستريم تسلسلي مربوط بcollection، ولكن بدون الاستفادة من ميزة تعدد أنوية المعالج في التنفيذ ()parallelStream: ستنشئ ستريم متوازي مربوط بcollection، مستفيدًا من ميزة تعدد أنوية المعالج في التنفيذ مثال:
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());  
    أهم ميثودز الStream                                         
    ()forEach:
    هذه الميثود تعطيك امكانية المرور بجميع عناصر الستريم للقيام بعملية معينة، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام forEach:
    Random random = new Random(); random.ints().limit(10).forEach(System.out::println); ()map:
    بهذه الميثود تستخدم لربط كل عنصر بالستريم مع نتيجة خاصة به. في المثال التالي سنقوم بطباعة مربعات ارقام مميزة باستخدام map:
    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of unique squares List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); ()filter:
    يتم استخدام هذه الميثود للتخلص من بعض عناصر الستريم بناء على شروط معينة، المثال التالي يقوم بطباعة عدد ال Strings الفارغة:
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.stream().filter(string -> string.isEmpty()).count(); ()limit:
    هذه الميثود تستخدم للحد من حجم الستريم بدون أي شروط، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام  limit:
    Random random = new Random(); random.ints().limit(10).forEach(System.out::println);  ()sorted:
    يتم استخدام هذه الميثود لترتيب الستريم، الكود التالي يظهر كيف تقوم بطباعة 10 ارقام عشوائية مرتبة:
    Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);  ( لاحظ كيف أنجزنا المهمة بسطر واحد فقط، تخيل لو أردت أن تقوم بطباعة 10 ارقام عشوائية مرتبة بالطريقة التقليدية! )
     
    Parallel Processing:                                        
    هذه هي الطريقة الثانية لإنشاء الستريم الموازي (استعمال جميع أنوية المعالج لتنفيذ البرنامج) كما هو مذكور بالأعلى:
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.parallelStream().filter(string -> string.isEmpty()).count(); لاحظ أنك تستطيع التبديل بين الStream والparallelStream بسهولة تامة.
     
    Collectors:                                                       
    نستخدم الCollectors لجمع نتائج معالجة بيانات الستريم واعادتها على شكل List.
    List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString);  
     
    في المثال التالي، سنقوم بعمل مقارنة بين الJava 7 والJava 8 في برنامج يقوم بضم الStrings غير الفارغة. import java.util.*; public class Java8StreamTest { public static void main(String[] args) { // Java 7 approach System.out.println("Using Java 7: "); List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("List: " +strings); StringBuilder stringBuilder = new StringBuilder(); for (String string: strings) { if (!string.isEmpty()) { stringBuilder.append(string); stringBuilder.append(", "); } } String mergedString = stringBuilder.toString(); System.out.println("Merged String: " + mergedString); // Java 8 approach System.out.println("Using Java 8: "); System.out.println("List: " +strings); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); } }  
     
    وهنا نصل الى ختام موضوعنا، أسأل الله لي ولكم التوفيق والسداد.
    مستوى المقال: محترف
  9. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته،
    سنتحدث في هذا الموضوع عن مفهوم الAbstract عامة وبالتحديد في لغة الJava، وكيفية استخدامه وتطبيقه مع امثلة توضيحية
     
    ماهو الAbstraction؟
    اذا بحثنا في القاموس عن معنى كلمة Abstract (تجريد)، فسنجد انها تعني [ خاصية التعامل مع الفكرة لا الحدث ]. بمعنى اهمال التفاصيل الغير لازمة واستبدالها بما هو مهم وواضح.
    مثال على ذلك: عندما تحاول ان ترسل ايميل الى شخص ما، فانك لن تهتم بالتفاصيل الصغيرة مثل مالذي يحدث بالضبط عندما تضغط على زر ارسال او البروتوكول المستخدم لنقل الرسالة. كل ما تريد عمله هو ان تكتب عنوان الرسالة والمحتوى ومستقبل الرسالة وترسلها. 
    نفس الشيء ينطبق في مفاهيم ال Object-Oriented. في الabstraction نهدف الى اخفاء تفاصيل الimplementation عن المستخدم، بمعنى اخر، المستخدم سيهتم بما الغرض من الobject بدلا عن كيفية قيامه به.
    في الجافا، يمكننا تطبيق هذا المفهوم عن طريق انشاء abstract class او abstract interface، (عكسها concrete class او normal class)
     
    Abstract Classes
    الكلاس الذي يحتوي على كلمة abstract في تعريفه يعتبر abstract class، وسيتبع القوانين التالية:
    من الممكن للAbstract class أن يحتوي على abstract methods (ليس اجباريا)، وهي الميثودز التي لا تحتوي على تعريف مثل ( ;()public abstract void get ) ولكن، اذا احتوى الكلاس على abstract method، فيجب تعريفه ك abstract class اذا تم تعريف الكلاس ك abstract، فلا يمكن انشاء objects منه لتستخدم ال abstract class وخصائصه، يجب عليك ان ترثه (inherit it) من كلاس آخر، ويجب عليك اعادة تعريف كل ال abstract methods مثال:
    سننشئ abstract class باضافة الكلمة abstract الى تعريف الكلاس:
    public abstract class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public double computePay() { System.out.println("Inside Employee computePay"); return 0.0; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } } لاحظ ان الabstract class السابق لا يختلف ابدا عن الكلاس العادي، فهو يحتوي على attributes, constructor, normal methods. الفرق الوحيد هو كلمة abstract بالتعريف
    الآن لنحاول انشاء اوبجكت من الكلاس السابق:
    public class AbstractDemo { public static void main(String [] args) { Employee e = new Employee("George W.", "Houston, TX", 43); e.computePay(); } } عند تشغيل البرنامج سنحصل على الخطأ التالي:
    Employee.java:46: Employee is abstract; cannot be instantiated Employee e = new Employee("George W.", "Houston, TX", 43); ^ 1 error لأنه لا يمكن انشاء اوبجكت من abstract class حتى وان احتوى على constructor.
     
    Inheriting Abstract Classes
    نستطيع اعادة استخدام خصائص وميثودز الabstract class تماما كأي كلاس آخر عن طريق وراثته (extends):
    public class Salary extends Employee { private double salary; // Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } } هنا لا يمكننا انشاء اوبجكت من كلاس Employee، ولكن يمكننا انشاء اوبجكت من كلاس Salary واستخدام جميع خصائص وميثودز كلاس Employee:
    public class AbstractDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } } والOutput سيكون كالتالي:
    Constructing an Employee Constructing an Employee Call mailCheck using Salary reference -- Within mailCheck of Salary class Mailing check to Mohd Mohtashim with salary 3600.0 Call mailCheck using Employee reference-- Within mailCheck of Salary class Mailing check to John Adams with salary 2400.0  
    Abstract Methods
    اذا اردت انشاء ميثود ولكنك تريد تعريفها بالكلاس الإبن (Inheriting class)، يمكنك استخدام كلمة abstract في تعريف الميثود، مثال:
    public abstract class Employee { private String name; private String address; private int number; public abstract double computePay(); } تعريف الميثود (مثل ()computePay) ك abstract method له آثار يجب الانتباه لها:
    الكلاس الذي يحتويها يجب أن يكون abstract الكلاس الذي يرث الكلاس الذي يحتويها يجب أن يعيد تعريفها مثال، كلاس Salary سيرث كلاس Employee السابق:
    public class Salary extends Employee { private double salary; // Annual salary public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } } نلاحظ أن الميثود ()computePay تمت اعادة تعريفها لتحصل على implementation جديد خاص بكلاس Salary
     
    هنا نصل الى نهاية موضوعنا، أتمنى لي ولكم التوفيق والسداد.
    مستوى المقال: مبتدئ
  10. السلام عليكم ورحمة الله وبركاته،
    هذا الدرس البسيط سيشرح باذن الله مفهوم الOverloading وطريقة تطبيقه على لغة الJava 
    ماهو الOverloading؟
    هي ميزة تقدمها العديد من لغات البرمجة، تتيح للمبرمج كتابة اثنين او اكثر من الmethods المتكررة (تحمل نفس الاسم) ولكن تختلف بخصائصها.
     
    كيف نفرق بين هذه الmethods المتشابهة؟
    صحيح ان الOverloaded methods تتشابه في الاسم، ولكنها يجب أن تختلف في أحد أو كل ما يلي:
    عدد الParameters  نوع الParameters ترتيب الParameters  
    أمثلة للMethod overloading:
    كما ذكرنا بالأعلى، فإن الOverloaded methods يجب ان تختلف في الArgument list
    وسنرى الآن مثال لكل حالة ممكنة للOverloading.
    مثال 1: اختلاف عدد الParameters
    class DisplayOverloading { public void disp(char c) { System.out.println(c); } public void disp(char c, int num) { System.out.println(c + " "+num); } } class Sample { public static void main(String args[]) { DisplayOverloading obj = new DisplayOverloading(); obj.disp('a'); obj.disp('a',10); } } Output:
    a a 10 في المثال السابق، قمنا بكتابة الميثود ()disp مرتين، مرة باستخدام Parameter واحد ومرة باستخدام اثنين.
    نلاحظ ان الcompiler ذكي كفاية ليربط لنا كل استدعاء بالميثود المناسبة له حسب الArgument list المستخدمة.
     
    مثال 2: اختلاف نوع الParameters
    class DisplayOverloading2 { public void disp(char c) { System.out.println(c); } public void disp(int c) { System.out.println(c ); } } class Sample2 { public static void main(String args[]) { DisplayOverloading2 obj = new DisplayOverloading2(); obj.disp('a'); obj.disp(5); } } Output:
    a 5 كما المثال السابق، نلاحظ هنا ان الميثود ()disp كتبت مرتين، مرة مع Parameter من نوع char ومرة من نوع int.
     
    مثال 3: اختلاف ترتيب الParameters
    في هذا المثال، قمنا بتغيير ترتيب الParameters لكتابة اكثر من نسخة من الميثود ()disp، في المرة الأولى كانت تحتوي على (char, int) وفي الثانية اصبحت (int, char).
    class DisplayOverloading3 { public void disp(char c, int num) { System.out.println("I’m the first definition of method disp"); } public void disp(int num, char c) { System.out.println("I’m the second definition of method disp" ); } } class Sample3 { public static void main(String args[]) { DisplayOverloading3 obj = new DisplayOverloading3(); obj.disp('x', 51 ); obj.disp(52, 'y'); } } Output:
    I’m the first definition of method disp I’m the second definition of method disp  
     
    لنرى امثلة على طرق overload خاطئة:
    الحالة 1:
    int mymethod(int a, int b, float c) int mymethod(int var1, int var2, float var3) النتيجة: خطأ في الCompilation، كلا الميثودين يحملان نفس عدد ونوع وترتيب الParameters.
     
    الحالة 2:
    int mymethod(int a, int b) float mymethod(int var1, int var2) النتيجة: خطأ في الCompilation، اختلاف الreturn type للميثودين لا يهم في الoverloading.
     
    هنا نصل الى نهاية موضوعنا، أتمنى لي ولكم التوفيق والسداد.
    مستوى المقال: مبتدئ
  11. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    استأنافا لما بدأنا عنه حول مواضيع هياكل البيانات سنتقطرق اليوم على نوع من أنواع الـ Methods واللتي لها علاقة
    بما يليها من مواضيع حول هياكل البيانات، كما ولها طبيقات رياضية كثيرة، والتي سنذكر منه ها هنا.
     
    ماذا نعني بـ Recursion ؟
    المعنى الحرفي لكلمة Recursion  هو الإستدعاء الذاتي وهذا المعنى لوحده يكفي لتعريفها، فبكل بساطة هو نوع من
    أنواع الـMethods والتي تقوم بنداء نفسها، ولهذه Method هيكلة وأساسيات لابد من توافرها في هذه Method.
     
    الشكل العام للـRecursion Methods:
    public void Test1(int i){ //أي عدد من اسطر الأكواد if(){//الحالة الأساسية والتي تقوم بإنهاء النداء الذاتي } Test1(/*any Value To pass*/);//النداء الذاتي //أي عدد من أسطر الأكواد } الأمر المهم الذي يجب عدم نسيانه هو الحالة الأساسية وهي عبارة عن شرط هذا الشرط
    يجعل لنداء الميثود لنفسها نهاية فليس من المعقول أن نقوم بنداء إلى مالنهاية. وهذا الشرط
    شبيه بالشرط الذي نضعه لإنها loop. وعند نسيان هذا الشرط سوف نواجه نداء لا نهائي من ثم انهيار التطبيق.
     
    لفهم معنى Recursion أفضل سوف نقفز مباشرة الى عدد من الأمثلة:
     
    ١. مضروب العدد Factorial (س!):
    ونعني به هنا هو مجموع حاصل ضرب جميع الأرقام من 1 الى العدد س.
    ويمكننا حل هذه العملية الحسابية بكل بساطة باستخدام التالي:
    public int Factorial (int i){ if(i == 0){ return 1; } else { return i * Factorial (i-1); } } هذه الميثود تأخذ عدد من نوع int وتقوم بإرجاع عدد من نوع int كذلك.
    أولا علينا تحديد الحالة الأساسية وفي هذه الحالة ستكون عندما يكون المضروب 0 فإن الناتج هو 1، 
    أي عندما نرسل للميثود 0 فإنها تعطينا الناتج 1.
    في حال لم نقم بإرسال 0 الى الميثود فإنها ستذهب للخيار الآخر وهو نداء الميثود لنفسها لكن هذا النداء
    يحتوي على بعض الأمور التي يجب أخذها بعين الاعتبار، اولها بأننا قمنا بتحديث قيمة i فقمنا بإنقاصها 1؛
    وهذا التحديث مهم حيث أنه في حال نسيانه سنواجه نداء لانهائي. الأمر الآخر بأننا قمنا بضرب العدد الحالي بسابقه.
     
    لنفرض بأننا قمنا بنداء هذه الميثود كالتالي:
    System.out.println(Factorial(4)); في النداء الأول بما أن 4 لا تساوي 0 فإننا سنقوم بالخطوة الثانية:
    4 * Factorial(4-1) وهذا يرسلنا الى النداء الثاني، ومن هذا النداء يتولد لنا:
    3 * Factorial(3-1) وندخل بعدها للنداء الثالث:
    2 * Factorial(2-1) ومنه للنداء الرابع:
    1 * Factorial(1-1) في النداء الخامس قيمة i تساوي 0 وهذا يحقق شرطنا فعندها سنقوم
    بإعادة 1 الى آخر نداء لنا أي أننا سنقوم بالتالي وليكن في البال بأننا في حال
    قمنا بأكثر من لنداء لنفس الميثود فإنا النداءات سوف تترب في stack أي أن
    آخر نداء سوف يحصل على الإجابة قبل غيره. وهذا ينتج لنا التالي:

    ٢. المجموع للعدد س:
    كما فعلنا في مثالنا السابق سنقوم هاهنا باستدعاء متكرر لنفس الميثود والتي ستقوم بدورها بجمع الأعداد من 0 إلى س.
    public int SUM(int i){ if(i == 0){ return 0; } else{ return i + SUM(i -1); } }  
    ٣. طباعة الأعداد:
    هنا المستخدم يرسل رقم (س) ونقوم بطباعة الأرقام من س الى 1 بشكل تنازلي :
    public void printInt(int i){ if(i == 1){ System.out.println(1); }else{ System.out.println(i); printInt(i-1); } } أما في حال أردنا الطباعة بشكل تصاعدي فكل ما علينا فعله هو عكس آخر سطري كود لينتج لدينا:
    public void printInt(int i){ if(i == 1){ System.out.println(1); }else{ printInt(i-1); System.out.println(i); } } ملاحظة: نداء الميثود لنفسها لا يقتصر على الأرقام فحسب (كما سنرى في المواضيع القادمة بإذن الله) بل إنه أوسع من ذلك؛ لكن لتبسيط الأمور استعنت بمجموعة
    من الأمثلة تحتوي على أرقام فهي أبسط للفهم، كذلك في حال الملاحظة فإن نداء الميثود لنفسها شبيه بالـ loop الى حد بعيد.
     
     
    اتمنى من الله أني وفقت لإصال المعلومة
    في حفظ الله
    مستوى المقال: مبتدئ
  12. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
    سنتطرق في هذا الموضوع للGenerics (الميثودز العامة)، مقدمة عن ماهي، ما فائدتها، وكيفية استخدامها بالجافا.
     
    مقدمة                                                                                   
    في أي مشروع او برنامج تعمل عليه بالجافا، ستواجه مشاكل في الcompiling وستواجه الكثير من الexceptions. لذلك من مهام المسؤولين عن لغة الجافا أن يساعدوا المطورين في مواجهة هذه الأخطاء والتقليل منها بقدر المستطاع.
    أحد أهم ما قدم في تحديث الJava 1.5 كان هو الGenerics. طريقة جديدة لتجنب مشاكل قد تواجهك في تطويرك لمشروعك.
     
    فائدتها                                                                                  
    ماهي هذه المشاكل التي قد تواجهك؟ 
    أكبر مشكلة أتت هذه الGenerics لحلها هي الأنواع المستخدمة في المجموعات (Collections)، كالArrayList, LinkedLists الخ..
    المشكلة تكمن (ما قبل Java 1.5) في النوع المستخدم لعناصر الCollection غير قابل للتحديد من قبل الكلاس، لذلك عندما يأتي المستخدم وينشئ اوبجكت من هذا الكلاس ويستخدم الميثودز الخاصة به، قد يستخدم cast خاطئ لعنصر في collection معينة، فمثلا قد يعمل كاست لعنصر (Integer) ك(String)
    مثلا:
    static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (((String) i.next()).length() == 4) i.remove(); } في المثال السابق، الميثود expurgate ستفترض دائما أن العناصر المقروءة من المجموعة c هي Strings. بالتالي في حالة أن اخطأ المستخدم بادخال مجموعة تحتوي على عناصر من نوع آخر سنواجه Casting exceptions.
    سنعدل المثال السابق باستخدام الgenerics لنرى كيف نتفادى مشاكل الcasting:
    static void expurgate(Collection<String> c) { for (Iterator<String> i = c.iterator(); i.hasNext(); ) if (i.next().length() == 4) i.remove(); } لاحظ تحديد نوع العناصر في الانبوت لتكون من نوع String، ولاحظ أيضا عدم الحاجة للCast داخل اللوب، وبذلك نلغي احتمالية حدوث Cast exceptions.
    سنتحدث عن الSyntax وأنواع الجينات لاحقا.
    لكن لنخلص أهم فوائد الGenerics أولا:
    مساعدة الCompiler في تحديد الأخطاء وقت الCompilation التخلص من الCasts  مساعدة المطورين على كتابة ميثودز عامة، وعدم الحاجة لكتابة أكثر من ميثود لاستقبال أكثر من نوع من الparameters.  
    طريقة استخدامها                                                                
    لاشك أنك لاحظت أن الGenerics تستعمل نوع خاص من الأقواس <> (الدايموند)، هذا صحيح. يجب استعمال هذه الأقواس عند الرغبة باستخدام الGenerics في كتابة الكلاسات وعند الرغبة بانشاء Objects منها.
    لنأخذ مثال كلاس الArrayList الموجود في مكاتب الجافا الافتراضية، مكتوب بالشكل التالي:
    public class ArrayList<E> implements List<E> .... { // Constructor public ArraList() { ...... } // Public methods public boolean add(E e) { ...... } public void add(int index, E element) { ...... } public boolean addAll(int index, Collection<? extends E> c) public abstract E get(int index) { ...... } public E remove(int index) ....... } نلاحظ استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين لعناصر الArrayList وترك الخيار للمستخدم.
    لإنشاء اوبجكت ArrayList:
    ArrayList<Integer> lst1 = new ArrayList<Integer>(); // E substituted with Integer lst1.add(0, new Integer(88)); lst1.get(0); ArrayList<String> lst2 = new ArrayList<String>(); // E substituted with String lst2.add(0, "Hello"); lst2.get(0); قمنا هنا بانشاء اوبجكتين من الArrayList الأول بعناصر من نوع Integer والثاني بعناصر من نوع String، وذلك باستخدام الكلاس والميثودز نفسها.
    إذا اردت انشاء كلاس خاص فيك وربط الاوبجكت بنوع عام (وترك التخصيص للمستخدم) يمكنك عمل التالي:
    public class GenericBox<E> { // Private variable private E content; // Constructor public GenericBox(E content) { this.content = content; } public E getContent() { return content; } public void setContent(E content) { this.content = content; } public String toString() { return content + " (" + content.getClass() + ")"; } } نلاحظ مرة أخرى استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين وترك الخيار للمستخدم.
    لاحظ في ميثود الtoString() قمنا باستدعاء الكلاس الخاص بالGeneric (أيا كان) لطباعته.
    لإنشاء أوبجكت من الكلاس السابق:
    public class TestGenericBox { public static void main(String[] args) { GenericBox<String> box1 = new GenericBox<String>("Hello"); String str = box1.getContent(); System.out.println(box1); GenericBox<Integer> box2 = new GenericBox<Integer>(123); // autobox int to Integer int i = box2.getContent(); System.out.println(box2); GenericBox<Double> box3 = new GenericBox<Double>(55.66); // autobox double to Double double d = box3.getContent(); System.out.println(box3); } } قمنا بالكود السابق انشاء 3 اوبجكتات من الكلاس GenericBox بانواع مختلفة، وأيضا باستخدام الكلاس والمثودز نفسها .
     
    أنواعها                                                                                  
    للGenerics أنواع عديدة أهمها:
    <Element - <E تستخدم كثيرا في مكتبات الجافا الافتراضية <Type - <T مقاربة للنوع الأول وأكثر الأنواع استخداما من قبل المطورين <Key & Value - <K, V للأنواع المتعددة (مفتاح وقيمة) ...  
    مثال على استخدام Generic الأنواع المتعددة:
    public interface Pair<K, V> { public K getKey(); public V getValue(); } public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } ولإنشاء اوبجكت من الPair class:
    Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world");  
    اختصار يمكن الإستغناء عن تحديد انواع العناصر عند استدعاء الConstructor والاكتفاء بتحديدها عند التعريف، حيث يمكن للCompiler ان يربطهما.
    OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8); OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");  
    المراجع                                                                                  
     Oracle : The Java™ Tutorials: Generics (Updated)s
    ntu : Java Programming Tutorial: Generics
     
    مستوى المقال: محترف

عالم البرمجة

عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل