Adapter Pattern
هذا النمط عبارة عن محول يقوم بعمل interface لنظام معقد ربما يكون كود جاهزمثلا او احدى المكتبات(libraries) القديمة لديك وتريد ان تعيد استخدامها ولكن ال interface لهذا الكود او المكتبة غير متوافق مع الكود الجديد الذي تستخدم معه هذه المكتبة فنقوم بعمل محول يوافق بين الجزئيتين
ITarget :
هو الانترفيس المراد استخدامه من المستخدم النهائي للكود او المستخدم لل(Adaptee)
Adaptee :
هو الكود او المكتبة والمراد استخدام محتواها
Adapter :
هي الكلاس التي تورث من ITarget وتوافق شروط ال Adaptee
Request:
هو الطلب الذي نريد تنفيذه في النهاية
SpecificRequest :
المحتوى الذي نريد تنفيذه والموجود في ال Adaptee
نستعرض مثال بسيط لتوضيح الفكرة
في البداية نعرض الكلاس Adaptee المراد الانتفاع من خدماتها وهي كود قديم او ربما يكون كود حديث في نفس البرنامج ولكن نريد ان نستخدمه في مكان اخر لا يتوافق مع الانترفيس له
using System;
// Adapter Pattern - Simple Judith Bishop Oct 2007
// Simplest adapter using interfaces and inheritance
// Existing way requests are implemented
class Adaptee
{
// Provide full precision
public double SpecificRequest(double a, double b)
{
return a / b;
}
}
هذا الانترفيس الجديد ITarget للكود الجديد الذي نريد ان نعمل عليه
// Required standard for requests
interface ITarget
{
// Rough estimate required
string Request(int i);
}
هنا نقوم بتعريف كلاس Adapter تجمع بين القديم والحديث وتوفق بينهم J
حيث اني في الكلاس الجديدة رغبتي هي اني اريد ان امرر اي رقم فيقسم تلقائيا على 3 بدون ان امرر الرقم 3 وهذا ما تقوم به الدالة Request تقوم باستخدام الدالة القديمة SpecificRequest وتمرر الرقم الجديد وتمرر الرقم 3 ونقوم ايضا بعمل تقريب للناتج الى اقرب رقم صحيح
// Implementing the required standard via Adaptee
class Adapter : Adaptee, ITarget
{
public string Request(int i)
{
return "Rough estimate is " + (int)Math.Round(SpecificRequest(i, 3));
}
}
الان نقوم بعرض الكلاس Client ونرى الفرق بين الحديث والقديم
class Client
{
static void Main()
{
// Showing the Adapteee in standalone mode
Adaptee first = new Adaptee();
Console.Write("Before the new standard\nPrecise reading: ");
Console.WriteLine(first.SpecificRequest(5, 3));
// What the client really wants
ITarget second = new Adapter();
Console.WriteLine("\nMoving to the new standard");
Console.WriteLine(second.Request(5));
}
}
ويكون الناتج كالتالي
/* Output
42 Before the new standard
43 Precise reading: 1.66666666666667
44
45 Moving to the new standard
46 Rough estimate is 2
47 */
Two-Way Adapters
هناك مشكلة من الممكن ان نواجهها اثناء عملنا وهي اذا اردنا ذات مرة ان نقوم بعمليتين احداهما تابعة لمكتبة معينة والاخرى تتبع لمكتبة ثانية ونريد ان نجعلهما يعملان سويا
فمثلا لو ان مخترع حاول ان يصنع طائرة مائية لها هيكل طائرة وموتور ولوحة تحكم لسفينة واسماها Seabird ويقوم بتشغيل الطائرة AirCraft و الجزء المائي منها اثناء وجدودها على صفحة الماء SeaCradt وسوف يتحكم في اختراعه عن طريق interface لكل جزء وسوف يكون الجزء المتحكم في الانتقال من انترفيس لاخر هو ال Seabird . اللآن نحول هذا المثال الى كود برمجي
- في البداية نقوم بعمل النترفيس الذي سيكون مسئول عن مرحلة الطيران
// ITarget interface
public interface IAircraft
{
bool Airborne { get; }
void TakeOff();
int Height { get; }
}
كما نرى فهو يشمل على خاصية Airborne Property واخرى Height ودالة Takeoff
- الآن نقوم بتوريث الانترفيس لكلاس تكون مسئولة عن الطيران
// Target
public sealed class Aircraft : IAircraft
{
int height;
bool airborne;
public Aircraft()
{
height = 0;
airborne = false;
}
public void TakeOff()
{
Console.WriteLine("Aircraft engine takeoff");
airborne = true;
height = 200; // Meters
}
public bool Airborne
{
get { return airborne; }
}
public int Height
{
get { return height; }
}
}
الكلاس Aircraft كما نرى هي كلاس sealed اي انه لا يمكن ان نشتق منها كلاس اخرى
في هذه الكلاس قمنا بملأ الانترفيس
- الآن نقوم بعمل انترفيس المتحكم في السقينة
// Adaptee interface
public interface ISeacraft
{
int Speed { get; }
void IncreaseRevs();
}
كما نرى يحتاج فقط الى دالة IncreaseRevs و خاصية Speed
- الآن نقوم بوراثة الانترفيس
// Adaptee implementation
public class Seacraft : ISeacraft
{
int speed = 0;
public virtual void IncreaseRevs()
{
speed += 10;
Console.WriteLine("Seacraft engine increases revs to " + speed + " knots");
}
public int Speed
{
get { return speed; }
}
}
نقوم الان بعمل الادابتر وبطبيعة الحال لا نستطيع الوراثة من كلاسيين فنرث من كلاس وانترفيس
// Adapter
public class Seabird : Seacraft, IAircraft
{
int height = 0;
// A two-way adapter hides and routes the Target's methods
// Use Seacraft instructions to implement this one
public void TakeOff()
{
while (!Airborne)
IncreaseRevs();
}
// Routes this straight back to the Aircraft
public int Height
{
get { return height; }
}
// This method is common to both Target and Adaptee
public override void IncreaseRevs()
{
base.IncreaseRevs();
if (Speed > 40)
height += 100;
}
public bool Airborne
{
get { return height > 50; }
}
}
قمنا بالوراثة من كلاس ال Seacraft و انترفيس ال IAircraft و هذا بالطبع اضطراري وذلك لعدم امكانيتنا في السي شارب ان نرث من اكثر من كلاس . الآن نحن قادرون من استخدام مميزات متعددة كمميزات السفينة والطائرة J
الآن نقوم بوضع المفتاح ونقوم بتشغيل السفينة نورماندي ( على بركة الله)
static void Main()
{
// No adapter
Console.WriteLine("Experiment 1: test the aircraft engine");
IAircraft aircraft = new Aircraft();
aircraft.TakeOff();
if (aircraft.Airborne) Console.WriteLine(
"The aircraft engine is fine, flying at "
+ aircraft.Height + "meters");
// Classic usage of an adapter
Console.WriteLine("\nExperiment 2: Use the engine in the Seabird");
IAircraft seabird = new Seabird();
seabird.TakeOff(); // And automatically increases speed
Console.WriteLine("The Seabird took off");
// Two-way adapter: using seacraft instructions on an IAircraft object
// (where they are not in the IAircraft interface)
Console.WriteLine("\nExperiment 3: Increase the speed of the Seabird:");
((ISeacraft)seabird).IncreaseRevs();
(seabird as ISeacraft).IncreaseRevs();
if (seabird.Airborne)
Console.WriteLine("Seabird flying at height " + seabird.Height +
" meters and speed " + (seabird as ISeacraft).Speed + " knots");
Console.WriteLine("Experiments successful; the Seabird flies!");
}
/* Output
Experiment 1: test the aircraft engine
Aircraft engine takeoff
The aircraft engine is fine, flying at 200 meters
Experiment 2: Use the engine in the Seabird
Seacraft engine increases revs to 10 knots
Seacraft engine increases revs to 20 knots
Seacraft engine increases revs to 30 knots
Seacraft engine increases revs to 40 knots
Seacraft engine increases revs to 50 knots
The Seabird took off
Experiment 3: Increase the speed of the Seabird:
Seacraft engine increases revs to 60 knots
Seacraft engine increases revs to 70 knots
Seabird flying at height 300 meters and speed 70 knots
Experiments successful; the Seabird flies!
*/
· في حال وجود اي استفسار او اي جزئية غير واضحة نرجوا عدم التردد في إبلاغي
great job, barakala allaho fek
ردحذف