الخطوات التالية

مقدمة إلى البرمجة وC++

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

التعلُّم بالمثال الثاني

ينصب تركيزنا في هذه الوحدة على اكتساب المزيد من التدريب على التحلل وفهم المؤشرات، والبدء في استخدام الكائنات والفئات. اعمل من خلال الأمثلة التالية. اكتب البرامج بنفسك عندما يُطلب منك ذلك، أو أجرِ التجارب. لا يمكننا التأكيد بما فيه الكفاية على أن المفتاح لتصبح مبرمجًا جيدًا هو الممارسة والممارسة والتدريب!

المثال 1: المزيد من ممارسات التحليل التدريجي

ضع في اعتبارك النتيجة التالية من لعبة بسيطة:

Welcome to Artillery.
You are in the middle of a war and being charged by thousands of enemies.
You have one cannon, which you can shoot at any angle.
You only have 10 cannonballs for this target..
Let's begin...

The enemy is 507 feet away!!!
What angle? 25<
You over shot by 445
What angle? 15
You over shot by 114
What angle? 10
You under shot by 82
What angle? 12
You under shot by 2
What angle? 12.01
You hit him!!!
It took you 4 shots.
You have killed 1 enemy.
I see another one, are you ready? (Y/N) n

You killed 1 of the enemy.

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

StartUp(); // This displays the introductory script.
killed = 0;
do {
  killed = Fire(); // Fire() contains the main loop of each round.
  cout << "I see another one, care to shoot again? (Y/N) " << endl;
  cin >> done;
} while (done != 'n');
cout << "You killed " << killed << " of the enemy." << endl;

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

In case you are a little rusty on physics, here are the calculations:

Velocity = 200.0; // initial velocity of 200 ft/sec Gravity = 32.2; // gravity for distance calculation // in_angle is the angle the player has entered, converted to radians. time_in_air = (2.0 * Velocity * sin(in_angle)) / Gravity; distance = round((Velocity * cos(in_angle)) * time_in_air);

بسبب الاستدعاءات إلى cos() وsin()، ستحتاج إلى تضمين match.h. تجربة كتابة هذا البرنامج - إنها ممارسة رائعة في تحليل المشكلات للغة C++ الأساسية. تذكر أن تقوم بمهمة واحدة فقط في كل دالة. هذه هي الذي كتبناه حتى الآن أكثر تطورًا، لذلك قد يستغرق الأمر قليلاً حان الوقت للقيام بذلك.إليك الحلّ الذي نقدّمه.

المثال الثاني: التدرّب باستخدام المؤشرات

هناك أربعة أشياء يجب تذكرها عند التعامل مع المؤشرات:
  1. المؤشرات هي متغيّرات تحتفظ بعناوين الذاكرة. أثناء تنفيذ البرنامج، يتم تخزين جميع المتغيرات في الذاكرة، وكل منها على عنوان أو موقع فريد خاص به. المؤشر هو نوع خاص من المتغيرات التي تحتوي على عنوان ذاكرة بدلاً من قيمة البيانات. ومثلما يتم تعديل البيانات عند استخدام متغير عادي، يتم تعديل قيمة العنوان المخزّنة في المؤشر كمتغيّر مؤشر تم التلاعب به. وفي ما يلي مثال لذلك:
    int *intptr; // Declare a pointer that holds the address
                 // of a memory location that can store an integer.
                 // Note the use of * to indicate this is a pointer variable.
    
    intptr = new int; // Allocate memory for the integer.
    *intptr = 5; // Store 5 in the memory address stored in intptr.
          
  2. نقول عادةً أن المؤشر "نقاط" إلى مكان تخزينها ("الموجّه"). إذًا، في المثال أعلاه، نقاط intptr إلى المؤشر 5-

    لاحظ استخدام لتخصيص ذاكرة لعددنا الصحيح مدبّب. هذا إجراء يجب علينا القيام به قبل محاولة الوصول إلى الموجّه.

    int *ptr; // Declare integer pointer.
    ptr = new int; // Allocate some memory for the integer.
    *ptr = 5; // Dereference to initialize the pointee.
    *ptr = *ptr + 1; // We are dereferencing ptr in order
                     // to add one to the value stored
                     // at the ptr address.
          

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

  3. يؤدي تعيين المؤشر بين مؤشرين إلى جعلهما يشيران إلى نفس المؤشر. بالتالي التعيين y = x; يجعل ص يشير إلى نفس نقطة التوجيه مثل س. تعيين المؤشر لا يلمس الموجّه. يؤدي هذا الإجراء إلى تغيير مؤشر واحد فقط ليحصل على الموقع نفسه. كمؤشر آخر. بعد تعيين المؤشر، يرمز المؤشران "مشاركة" الـ مدبّب. 
  4. void main() {
     int* x; // Allocate the pointers x and y
     int* y; // (but not the pointees).
    
     x = new int; // Allocate an int pointee and set x to point to it.
    
     *x = 42; // Dereference x and store 42 in its pointee
    
     *y = 13; // CRASH -- y does not have a pointee yet
    
     y = x; // Pointer assignment sets y to point to x's pointee
    
     *y = 13; // Dereference y to store 13 in its (shared) pointee
    }
      

في ما يلي أثر لهذه التعليمة البرمجية:

1. خصص مؤشرين x وy. يؤدي تخصيص المؤشرات وليس تخصيص أيّ نقاط توجيه
2. يمكنك تخصيص أداة توجيهية وضبط x للإشارة إليها.
3- يجب إدخال الرمز x لتخزين 42 في الموجِّه. هذا مثال أساسي لعملية إلغاء الإشارة. ابدأ عند x، واتّبِع السهم للوصول إلى: بوينته.
4. حاوِل الإشارة إلى y لتخزين الرقم 13 في أداة التوجيه. يتعطّل هذا بسبب حدوث عطل. ليس لدي مُوجه -- لم يتم تعيينه أبدًا.
5- تعيين y = x; بحيث يشير ص إلى النقطة س. تشير الآن x و y إلى نفس الموجه -- إنهم "يشاركون".
6- حاوِل الإشارة إلى y لتخزين الرقم 13 في أداة التوجيه. هذه المرة تعمل، لأن التكليف السابق أعطاك أحد المرشدين.

كما ترى، تكون الصور مفيدة جدًا في فهم استخدام المؤشر. إليك مثال آخر.

int my_int = 46; // Declare a normal integer variable.
                 // Set it to equal 46.

// Declare a pointer and make it point to the variable my_int
// by using the address-of operator.
int *my_pointer = &my_int;

cout << my_int << endl; // Displays 46.

*my_pointer = 107; // Derefence and modify the variable.

cout << my_int << endl; // Displays 107.
cout << *my_pointer << endl; // Also 107.

لاحظ في هذا المثال أنّنا لم نخصص ذكرى مطلقًا بالكلمة "new" (جديد) . أعلنا عن متغير عدد صحيح عادي وعالجناه باستخدام المؤشرات.

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

int *ptr1; // Declare a pointer to int.
ptr1 = new int; // Reserve storage and point to it.

float *ptr2 = new float; // Do it all in one statement.

delete ptr1; // Free the storage.
delete ptr2;

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

// Passing parameters by reference.
#include <iostream>
using namespace std;

void Duplicate(int& a, int& b, int& c) {
  a *= 2;
  b *= 2;
  c *= 2;
}

int main() {
  int x = 1, y = 3, z = 7;
  Duplicate(x, y, z);
  // The following outputs: x=2, y=6, z=14.
  cout << "x="<< x << ", y="<< y << ", z="<< z;
  return 0;
}

إذا بقينا &'s خارج الوسيطات في تعريف الدالة المكررة، ونمرر المتغيرات "حسب القيمة"، أي أن النسخة تتكون من قيمة المتغير. تؤدي أي تغييرات تم إجراؤها على المتغير في الدالة إلى تعديل النسخة. ولا تقوم بتعديل المتغير الأصلي.

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

إذا كنت مبرمجًا بلغة البرمجة C، فهذا شيء جديد. يمكننا أن نفعل الشيء نفسه في C من خلال إعلان Duplicate() على النحو التالي Duplicate(int *x)، وفي هذه الحالة x مؤشرًا إلى int، ثم استدعاء Duplicate() مع الوسيطة &x (عنوان x)، واستخدام إزالة مرجع x داخل Duplicate() (انظر أدناه). لكن C++ يوفر طريقة أبسط لتمرير القيم إلى الدوال عن طريق مرجعيًا، على الرغم من استخدام حرف "C" القديم للقيام بذلك لا يزال يعمل.

void Duplicate(int *a, int *b, int *c) {
  *a *= 2;
  *b *= 2;
  *c *= 2;
}

int main() {
  int x = 1, y = 3, z = 7;
  Duplicate(&x, &y, &z);
  // The following outputs: x=2, y=6, z=14.
  cout << "x=" << x << ", y=" << y << ", z=" << z;
  return 0;
}

إشعار بمراجع C++، لا نحتاج إلى تمرير عنوان متغير، هل نحتاج إلى إلغاء الإشارة إلى المتغير داخل الدالة المستدعاة.

ماذا يُخرج البرنامج التالي؟ ارسم صورة للذاكرة لاستكشافها.

void DoIt(int &foo, int goo);

int main() {
  int *foo, *goo;
  foo = new int;
  *foo = 1;
  goo = new int;
  *goo = 3;
  *foo = *goo + 3;
  foo = goo;
  *goo = 5;
  *foo = *goo + *foo;
  DoIt(*foo, *goo);
  cout << (*foo) << endl;
}

void DoIt(int &foo, int goo) {
  foo = goo + 3;
  goo = foo + 4;
  foo = goo + 3;
  goo = foo;
} 

شغّل البرنامج لمعرفة ما إذا كنت قد حصلت على الإجابة الصحيحة.

المثال الثالث: تمرير القيم حسب المرجع

اكتب دالة تسمى accelerate() تستخدم كمدخل لسرعة السيارة ومقدار ما. تضيف الدالة الكمية إلى السرعة لتسريع المركبة. يجب تمرير مَعلمة السرعة بالمرجع، والمبلغ حسب القيمة. إليك الحلّ الذي نقدّمه.

المثال 4: الفئات والكائنات

ضع في الاعتبار الفئة التالية:

// time.cpp, Maggie Johnson
// Description: A simple time class.

#include <iostream>
using namespace std;

class Time {
 private:
  int hours_;
  int minutes_;
  int seconds_;
 public:
  void set(int h, int m, int s) {hours_ = h; minutes_ = m; seconds_ = s; return;}
  void increment();
  void display();
};

void Time::increment() {
  seconds_++;
  minutes_ += seconds_/60;
  hours_ += minutes_/60;
  seconds_ %= 60;
  minutes_ %= 60;
  hours_ %= 24;
  return;
}

void Time::display() {
  cout << (hours_ % 12 ? hours_ % 12:12) << ':'
       << (minutes_ < 10 ? "0" :"") << minutes_ << ':'
       << (seconds_ < 10 ? "0" :"") << seconds_
       << (hours_ < 12 ? " AM" : " PM") << endl;
}

int main() {
  Time timer;
  timer.set(23,59,58);
  for (int i = 0; i < 5; i++) {
    timer.increment();
    timer.display();
    cout << endl;
  }
}

لاحظ أن متغيرات عضو الفئة تحتوي على شرطة سفلية لاحقة. يتم ذلك للتفريق بين المتغيرات المحلية ومتغيرات الفئة.

أضِف طريقة تناقص إلى هذه الفئة. إليك الحلّ الذي نقدّمه.

عجائب العلوم: علوم الكمبيوتر

تمارين

كما هو الحال في الوحدة الأولى من هذه الدورة، لا نقدم حلولاً للتمارين والمشروعات.

تذكَّر أنّ هذا البرنامج جيد...

... يتم تحليلها منطقيًا إلى دوال حيث تكون أي دالة يقوم بمهمة واحدة فقط.

... لديه برنامج رئيسي يشبه مخططًا تفصيليًا لما سيفعله البرنامج.

... لها دالة وصفية وأسماء ثابتة ومتغيرات.

... يستخدم الثوابت لتجنب أي "سحر" الأرقام في البرنامج.

... لديه واجهة مستخدم سهلة الاستخدام.

تمارين إحماء

  • التمرين 1

    يمتلك العدد الصحيح 36 خاصية خاصة: إنه مربع مثالي مجموع الأعداد الصحيحة من 1 إلى 8. والعدد التالي هو 1225 حيث هو 352، ومجموع الأعداد الصحيحة من 1 إلى 49. البحث عن الرقم التالي بحيث يكون مربعًا مثاليًا وكذلك مجموع السلسلة 1...ن. هذا الرقم التالي أكبر من 32767. يمكنك استخدام دوال المكتبة التي تعرفها (أو المعادلات الرياضية) لجعل برنامجك يعمل بشكل أسرع. من الممكن أيضًا لكتابة هذا البرنامج باستخدام التكرارات الحلقية لتحديد ما إذا كان الرقم مثاليًا مربع أو مجموع سلسلة. (ملاحظة: وفقًا لجهازك وبرنامجك، قد يستغرق العثور على هذا الرقم بعض الوقت).

  • التمرين 2

    يحتاج متجر الكتب بالكلية إلى مساعدتك في تقدير نشاطه التجاري خلال المرحلة التالية سنة. أثبتت التجربة أن المبيعات تعتمد إلى حد كبير على ما إذا كان يجب شراء الكتاب أم لا بالنسبة لدورة تدريبية أو اختيارية فقط، وما إذا تم استخدامها في الفصل أم لا من قبل. سيباع الكتاب المدرسي الجديد المطلوب بنسبة 90% من التسجيل المحتمل، ولكن إذا تم استخدامه في الفصل من قبل، فسيشتري 65٪ فقط. وبالمثل، سوف يشتري 40% من الطلاب المحتملين كتابًا مدرسيًا جديدًا اختياريًا، ولكن إذا استُخدِمت في الفئة قبل أن يشتري 20% فقط من الأشخاص. (يُرجى ملاحظة أنّ كلمة "مُستعمَل" هنا لا يعني الكتب المستعملة).

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

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

    قبل أن تبدأ في كتابة التعليمات البرمجية، خذ بعض الوقت للتفكير في تصميم هذا البرنامج. وحلِّلها إلى مجموعة من الدوال، وأنشئ دالة main() التي تنص على ما يلي: مخطط تفصيلي لحل المشكلة. تأكد من أن كل دالة تقوم بمهمة واحدة.

    في ما يلي نموذج للمخرجات:

    Please enter the book code: 1221
     single copy price: 69.95
     number on hand: 30
     prospective enrollment: 150
     1 for reqd/0 for optional: 1
     1 for new/0 for used: 0
    ***************************************************
    Book: 1221
    Price: $69.95
    Inventory: 30
    Enrollment: 150
    
    This book is required and used.
    ***************************************************
    Need to order: 67
    Total Cost: $4686.65
    ***************************************************
    
    Enter 1 to do another book, 0 to stop. 0
    ***************************************************
    Total for all orders: $4686.65
    Profit: $937.33
    ***************************************************

مشروع قاعدة البيانات

في هذا المشروع، نقوم بإنشاء برنامج C++ كامل الوظائف يقوم بتنفيذ تطبيق قاعدة البيانات.

سيسمح لنا برنامجنا بإدارة قاعدة بيانات للملحّنين والمعلومات ذات الصلة عنها. وتشمل ميزات البرنامج ما يلي:

  • إمكانية إضافة مؤلف جديد
  • القدرة على تصنيف مؤلف موسيقي (أي الإشارة إلى ما يعجبنا أو لا نحبه موسيقى الملحن)
  • إمكانية عرض كافة المؤلفين في قاعدة البيانات
  • إمكانية عرض كل الملحّنين حسب الترتيب

"هناك طريقتان لإنشاء تصميم البرامج: إحدى الطرق هي تسهيل الأمر بحيث يكون هناك وعدم وجود أي أوجه قصور بها، والطريقة الأخرى هي جعل الأمر معقدًا للغاية بحيث هي عدم وجود أي قصور واضحة. الطريقة الأولى أكثر صعوبة بكثير". - C.A.R. Hoare

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

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

في تصميم OO، نعرّف الأشياء المادية من حيث الفئات والكائنات؛ السمات وسلوكياتهم. يوجد بشكل عام عدد كبير من الكائنات في برنامج OO. ومع ذلك، فإن العديد من هذه الكائنات في الأساس نفس الشيء. ضع في اعتبارك ما يلي.

الفئة هي مجموعة من السمات والسلوكيات العامة لكائن، والتي قد تكون موجودة ماديًا في العالم الحقيقي. في الرسم التوضيحي أعلاه، لدينا فئة Apple. جميع التفاح، بغض النظر عن نوعه، له سمات اللون والطعم. لدينا أيضًا سلوكًا تعرض فيه Apple سماتها.

في هذا الرسم التخطيطي، حددنا كائنين من فئة Apple. ولكل كائن السمات والإجراءات نفسها مثل الفئة، لكن الكائن تحدد سمات نوع معين من التفاح. بالإضافة إلى ذلك، تستخدم الشبكة الإعلانية الإجراء يعرض السمات لهذا الكائن المعين، على سبيل المثال، "أخضر" و"Sour".

يتكون تصميم OO من مجموعة من الفئات، والبيانات المرتبطة بهذه الفئات، ومجموعة الإجراءات التي يمكن أن تؤديها الفئات. نحتاج أيضًا إلى تحديد الطرق التي تتفاعل بها الفئات المختلفة. يمكن تنفيذ هذا التفاعل بواسطة الكائنات لفئةٍ ما يستدعي أفعال كائنات من الفئات الأخرى. على سبيل المثال، يمكن أن يحتوي على فئة AppleOutputer التي تُخرج لون الصفيفة وطعمها من كائنات Apple، عن طريق استدعاء طريقة Display() لكل كائن من كائنات Apple.

فيما يلي الخطوات التي نقوم بها للقيام بتصميم OO:

  1. حدد الفئات وحدد بشكل عام كائن من فئات كل فئة يخزن كبيانات وما الذي يمكن أن يفعله الكائن.
  2. تحديد عناصر البيانات لكل فئة
  3. تحديد إجراءات كل فئة وكيف يمكن تنفيذ بعض الإجراءات لفئة واحدة وتنفيذها باستخدام إجراءات من الفئات الأخرى ذات الصلة.

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

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

نحتاج أيضًا إلى مجموعة من كائنات Composer. لهذا، نحدد فئة قاعدة البيانات الذي يدير السجلات الفردية. يمكن كائن من هذه الفئة إضافة أو استرداد كائنات المؤلفين، وعرض عناصر فردية من خلال استدعاء إجراء عرض كائن Composer.

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

الآن بعد أن حددنا فئات تطبيق قاعدة بيانات المؤلف، فإن الخطوة التالية هي تحديد التصنيفات والإجراءات للفئات. بعد مزيد من تطبيق معقد، فيمكننا الجلوس مع قلم رصاص وورقة أو UML أو بطاقات CRC أو OOD لتعيين التسلسل الهرمي للفئة وكيفية تفاعل الكائنات.

بالنسبة لقاعدة بيانات المؤلفين، نحدد فئة Composer تحتوي على القيم البيانات التي نريد تخزينها على كل مؤلف. كما أنه يحتوي على طرق لمعالجة والترتيب وعرض البيانات.

تحتاج فئة قاعدة البيانات إلى نوع من البنية للاحتفاظ بكائنات Composer. نحتاج إلى أن نكون قادرين على إضافة كائن Composer جديد إلى البنية، بالإضافة إلى لاسترداد كائن Composer معيّن. نود أيضًا عرض جميع الكائنات إما حسب الإدخال أو الترتيب.

تنفذ فئة واجهة المستخدم واجهة قائمة، مع معالِجات لإجراءات الاستدعاء في فئة قاعدة البيانات.

إذا كانت الفئات يسهل فهمها وكانت سماتها وإجراءاتها واضحة، كما هو الحال في تطبيق المؤلف، يسهل نسبيًا تصميم الفئات. لَكِنْ وإذا كانت هناك أي أسئلة في ذهنك حول كيفية ارتباط الفصول وتفاعلها، فمن الأفضل رسمه أولاً، والعمل على التفاصيل قبل البدء إلى الترميز.

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

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

// composer.h, Maggie Johnson
// Description: The class for a Composer record.
// The default ranking is 10 which is the lowest possible.
// Notice we use const in C++ instead of #define.
const int kDefaultRanking = 10;

class Composer {
 public:
  // Constructor
  Composer();
  // Here is the destructor which has the same name as the class
  // and is preceded by ~. It is called when an object is destroyed
  // either by deletion, or when the object is on the stack and
  // the method ends.
  ~Composer();

  // Accessors and Mutators
  void set_first_name(string in_first_name);
  string first_name();
  void set_last_name(string in_last_name);
  string last_name();
  void set_composer_yob(int in_composer_yob);
  int composer_yob();
  void set_composer_genre(string in_composer_genre);
  string composer_genre();
  void set_ranking(int in_ranking);
  int ranking();
  void set_fact(string in_fact);
  string fact();

  // Methods
  // This method increases a composer's rank by increment.
  void Promote(int increment);
  // This method decreases a composer's rank by decrement.
  void Demote(int decrement);
  // This method displays all the attributes of a composer.
  void Display();

 private:
  string first_name_;
  string last_name_;
  int composer_yob_; // year of birth
  string composer_genre_; // baroque, classical, romantic, etc.
  string fact_;
  int ranking_;
};

فئة قاعدة البيانات مباشرة أيضًا.

// database.h, Maggie Johnson
// Description: Class for a database of Composer records.
#include  <iostream>
#include "Composer.h"

// Our database holds 100 composers, and no more.
const int kMaxComposers = 100;

class Database {
 public:
  Database();
  ~Database();

  // Add a new composer using operations in the Composer class.
  // For convenience, we return a reference (pointer) to the new record.
  Composer& AddComposer(string in_first_name, string in_last_name,
                        string in_genre, int in_yob, string in_fact);
  // Search for a composer based on last name. Return a reference to the
  // found record.
  Composer& GetComposer(string in_last_name);
  // Display all composers in the database.
  void DisplayAll();
  // Sort database records by rank and then display all.
  void DisplayByRank();

 private:
  // Store the individual records in an array.
  Composer composers_[kMaxComposers];
  // Track the next slot in the array to place a new record.
  int next_slot_;
};

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

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

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

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

Composer Database
---------------------------------------------
1) Add a new composer
2) Retrieve a composer's data
3) Promote/demote a composer's rank
4) List all composers
5) List all composers by rank
0) Quit

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

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

// test_composer.cpp, Maggie Johnson
//
// This program tests the Composer class.

#include <iostream>
#include "Composer.h"
using namespace std;

int main()
{
  cout << endl << "Testing the Composer class." << endl << endl;

  Composer composer;

  composer.set_first_name("Ludwig van");
  composer.set_last_name("Beethoven");
  composer.set_composer_yob(1770);
  composer.set_composer_genre("Romantic");
  composer.set_fact("Beethoven was completely deaf during the latter part of "
    "his life - he never heard a performance of his 9th symphony.");
  composer.Promote(2);
  composer.Demote(1);
  composer.Display();
}

نحتاج إلى برنامج اختبار مشابه لفئة قاعدة البيانات.

// test_database.cpp, Maggie Johnson
//
// Description: Test driver for a database of Composer records.
#include <iostream>
#include "Database.h"
using namespace std;

int main() {
  Database myDB;

  // Remember that AddComposer returns a reference to the new record.
  Composer& comp1 = myDB.AddComposer("Ludwig van", "Beethoven", "Romantic", 1770,
    "Beethoven was completely deaf during the latter part of his life - he never "
    "heard a performance of his 9th symphony.");
  comp1.Promote(7);

  Composer& comp2 = myDB.AddComposer("Johann Sebastian", "Bach", "Baroque", 1685,
    "Bach had 20 children, several of whom became famous musicians as well.");
  comp2.Promote(5);

  Composer& comp3 = myDB.AddComposer("Wolfgang Amadeus", "Mozart", "Classical", 1756,
    "Mozart feared for his life during his last year - there is some evidence "
    "that he was poisoned.");
  comp3.Promote(2);

  cout << endl << "all Composers: " << endl << endl;
  myDB.DisplayAll();
}

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

اكتمل تصميم تطبيقنا الآن. تتمثل الخطوة التالية في تنفيذ ملفات .cpp للفئات وواجهة المستخدم.للبدء، تابع انسخ/ألصق h .واختبر رمز برنامج التشغيل أعلاه في الملفات، وقم بتجميعها.استخدام السائقين التجريبيين لاختبار صفوفك. بعد ذلك، نفِّذ الواجهة التالية:

Composer Database
---------------------------------------------
1) Add a new composer
2) Retrieve a composer's data
3) Promote/demote a composer's rank
4) List all composers
5) List all composers by rank
0) Quit

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

تذكر - يجب أن تتبع جميع التعليمات البرمجية اصطلاحات البرمجة لدينا، والتي يتم تكرارها هنا لتسهيل الأمر عليك:

  • يبدأ كل برنامج نكتبه بتعليق في العنوان، يوفر اسم والمؤلف ومعلومات الاتصال به ووصف موجز واستخدامه (إذا كان ذلك منطبقًا). تبدأ كل دالة/طريقة بتعليق على العملية والاستخدام.
  • نحن نضيف تعليقات توضيحية باستخدام جمل كاملة، كلما كانت التعليمات البرمجية وليس توثيقها بنفسه، على سبيل المثال، إذا كانت عملية المعالجة صعبة أو غير واضحة، أو شيقة أو مهمة.
  • استخدم دائمًا أسماء وصفية: المتغيرات عبارة عن كلمات بأحرف صغيرة تفصل بينها _، كما في my_variable. تستخدم أسماء الدوال/الأحرف الأحرف الكبيرة لوضع علامة ، كما في MyExciteFunction(). تبدأ الثوابت بحرف "k" أو استخدم الأحرف الكبيرة لوضع علامة على الكلمات، كما في kDaysInWeek.
  • المسافة البادئة في مضاعفات الرقم اثنين. المستوى الأول عبارة عن مسافتين؛ إذا كانت أخرى هناك حاجة إلى مسافة بادئة، فنحن نستخدم أربع مسافات وستة مسافات وما إلى ذلك.

مرحبًا بك في العالم الحقيقي

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

ملفات التعريف

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

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

أنظمة إدارة التهيئة

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

ويتم حفظ الدليل التقني على كمبيوتر يستطيع كل من يوسف وسوسن الوصول إليهما. وفي حال عدم وجود أي أداة أو عملية حالية لمدير المنتدى، يمكن أن ينشأ عدد من المشاكل. وَاحِدْ هو إعداد الكمبيوتر الذي يقوم بتخزين المستند بحيث لا يستطيع كل من يوسف وسوسن العمل على الدليل في الوقت نفسه. سيؤدي هذا إلى إبطاء بشكل كبير.

ينشأ موقف أكثر خطورة عندما يسمح كمبيوتر التخزين بالوثيقة. ليتم فتحها بواسطة كل من بوب وسوزان في نفس الوقت. إليك ما يمكن أن يحدث:

  1. يفتح أمجد المستند على جهاز الكمبيوتر ويعمل في القسم الخاص به.
  2. تفتح سوزان المستند على جهاز الكمبيوتر وتعمل على القسم الخاص بها.
  3. يُكمل أمجد التغييرات ويحفظ المستند على كمبيوتر التخزين.
  4. تُكمل سوزان التغييرات وتحفظ المستند على كمبيوتر التخزين.

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

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

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

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

إدارة إعداد البرامج

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

توفِّر جميع أنظمة "إدارة الشؤون التجارية والعقود" الميزات الأساسية التالية:

  • إدارة التزامن
  • تحديد الإصدارات
  • المزامنة

لنلقِ نظرة على كل ميزة من هذه الميزات بمزيد من التفصيل.

إدارة التزامن

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

بالنظر إلى مثال بسيط في المجال الهندسي: لنفترض أننا نسمح بالمهندسين لتعديل الملف نفسه في الوقت نفسه في مستودع مركزي لرمز المصدر. يحتاج كل من Client1 وClient2 إلى إجراء تغييرات على ملف في نفس الوقت:

  1. يفتح العميل1 bar.cpp.
  2. يفتح العميل2 bar.cpp.
  3. يغيّر Client1 الملف ويحفظه.
  4. يقوم Client2 بتغيير الملف وحفظه بدلاً من تغييرات Client1.

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

يمكن أن تكون هذه الخوارزميات بسيطة (مطالبة المهندسين بحل التغييرات المتعارضة) أو ليست بسيطة للغاية (تحديد كيفية دمج التغييرات المتعارضة بذكاء ولا تسأل المهندس إلا إذا تعطل النظام بالفعل).

تحديد الإصدارات

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

المزامنة

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

التخريب

Subversion (SVN) هو نظام مفتوح المصدر للتحكّم في الإصدار. وهي تحتوي على كل الميزات الموضحة أعلاه.

تتبنى SVN منهجية بسيطة في حالة حدوث تعارضات. يحدث التعارض عندما يكون اثنان أو يقوم المزيد من المهندسين بإجراء تغييرات مختلفة على نفس المنطقة من قاعدة التعليمات البرمجية ثم يرسل كلاهما تغييراتهما. تنبه SVN المهندسين فقط بوجود نزاع - والأمر متروك للمهندسين لحله.

سنستخدم SVN خلال هذه الدورة لمساعدتك على التعرف على إدارة عملية الإعداد. هذه الأنظمة شائعة جدًا في الصناعة.

تتمثّل الخطوة الأولى في تثبيت SVN على نظامك. (يُرجى النقر.) هنا من أجل على التعليمات ابحث عن نظام التشغيل ونزِّل البرنامج الثنائي المناسب.

بعض مصطلحات SVN

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

الآن وبعد تثبيت SVN، سنتناول بعض الأوامر الأساسية. تشير رسالة الأشكال البيانية أول شيء يجب فعله هو إعداد مستودع في دليل محدد. إليك الأوامر:

$ svnadmin create /usr/local/svn/newrepos
$ svn import mytree file:///usr/local/svn/newrepos/project -m "Initial import"
Adding         mytree/foo.c
Adding         mytree/bar.c
Adding         mytree/subdir
Adding         mytree/subdir/foobar.h

Committed revision 1.

ينسخ الأمر استيراد محتوى شجرة الدليل إلى مشروع الدليل في المستودع. يمكننا إلقاء نظرة على الدليل في مستودع يتضمّن الأمر list

$ svn list file:///usr/local/svn/newrepos/project
bar.c
foo.c
subdir/

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

$ svn checkout file:///usr/local/svn/newrepos/project
A    foo.c
A    bar.c
A    subdir
A    subdir/foobar.h
…
Checked out revision 215.

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

هناك بعض أسماء الدلائل العادية التي يتم استخدامها غالبًا مع Subversion. "الصندوق" الدليل يحمل الخط الرئيسي للتطوير لمشروعك. "الفروع" الدليل يحمل أي إصدار فرع قد تعمل عليه.

$ svn list file:///usr/local/svn/repos
/trunk
/branches

لنفترض أنك أجريت جميع التغييرات المطلوبة على نسخة العمل وتريد مزامنتها مع المستودع. إذا كان الكثير من المهندسين الآخرين يعملون في هذا الجزء من المستودع، من المهم الحفاظ على تحديث نسخة عملك. يمكنك استخدام أمر حالة svn لعرض التغييرات التي أجريتها. الذي تم إجراؤه.

A       subdir/new.h      # file is scheduled for addition
D       subdir/old.c        # file is scheduled for deletion
M       bar.c                  # the content in bar.c has local modifications

لاحظ أن هناك الكثير من العلامات في أمر الحالة للتحكم في هذا الإخراج. إذا كنت ترغب في عرض التغييرات المحددة في ملف مُعدَّل، استخدم svn diff.

$ svn diff bar.c
Index: bar.c
===================================================================
--- bar.c	(revision 5)
+++ bar.c	(working copy)
## -1,18 +1,19 ##
+#include
+#include

 int main(void) {
-  int temp_var;
+ int new_var;
...

أخيرًا، لتعديل نسخة العمل من المستودع، استخدِم الأمر تحديث svn.

$ svn update
U  foo.c
U  bar.c
G  subdir/foobar.h
C  subdir/new.h
Updated to revision 2.

هذا مكان قد يحدث فيه تعارض. في الإخراج أعلاه، تشير "U" يشير إلى لم يتم إجراء أي تغييرات على إصدارات المستودع من هذه الملفات وتعديل الانتهاء منها. "G" ما يعني حدوث دمج. كان لإصدار المستودع تم تغييرها ولكن التغييرات لم تتعارض مع تغييراتك. الحرف اللاتيني c يشير إلى خلاف. وهذا يعني أن التغييرات من المستودع تتداخل مع التغييرات التي أجريتها، والآن عليك الاختيار بينهما.

لكل ملف به تعارض، تضع Subversion ثلاثة ملفات في عملك نسخة:

  • file.mine: هذا هو ملفك كما كان في نسخة عملك قبل قامت بتحديث نسخة العمل الخاصة بك.
  • file.rOLDREV: هذا هو الملف الذي تحققت منه من المستودع قبل وإجراء التغييرات.
  • file.rNEWREV: هذا الملف هو الإصدار الحالي في المستودع.

يمكنك اتخاذ أحد الإجراءات الثلاثة لحل التعارض:

  • انتقِل عبر الملفات وادمج الملفات يدويًا.
  • انسخ أحد الملفات المؤقتة التي أنشأتها SVN باستخدام نسخة العمل.
  • تنفيذ svn return لتجاهل جميع التغييرات التي أجريتها.

بعد حل التعارض، يمكنك إعلام SVN من خلال تنفيذ تم حل svn. يؤدي ذلك إلى إزالة الملفات المؤقتة الثلاثة ولن تعرض SVN الملف بعد ذلك في حالة التعارض.

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

svn commit -m "Update files to include new headers."  

ويمكن التعرُّف على مزيد من المعلومات حول SVN وكيفية دعمه للبرامج الكبيرة. المشروعات الهندسية. هناك موارد كبيرة متاحة على الويب - قم بالبحث في Google عن "Subversion".

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

المراجع

كتاب فرعي على الإنترنت

مقالة من ويكيبيديا عن SVN

الموقع الإلكتروني الفرعي

التطبيق: دراسة في علم التشريح

تعرَّف على موقع eSkeletons من الجامعة. تكساس في أوستن