نموذج التصميم وزن الذبابة
يفتقر محتوى هذه المقالة إلى الاستشهاد بمصادر. (يناير 2022) |
يفيد هذا النموذج في بعض الحالات التي تستخدم فيها كائن صغير وكثير فلإستهلك كثيرا من المصادر ويكون من المفضل وقتها ان نجمع كل هذه الكائنات الصغيرة في كائن واحد كبير أو اقل عدد ممكن من الكائنات الكبيرة نوعا ما هو اوفر على النظام من كائنات كثيرة صغيرة.
هذا النموذج يقوم على تقسيم الكائنات إلى intrinsic data و extrinsic data والجزء الأول يكون للوظائف الداخلية للصف ولا يمكن فصلها عن الكائن اما الجزء الثاني فهي الوظائف التي من الممكن ان تفصلها عن الصف وتخزن خارجه وبذلك يمكننا ان نستبدل جميع الاجزاء المتشابهه في الجزء الداخلي واستبدالها بكائن واحد. وهناك جزء اخر يدير عملية التاكد من عدم وجود الكائن قبل انشائه أي يتاكد اننا لم ننشأ intrinsic data مطابقة من قبل وفي حالة اننا انشئناها من قبل يقوم باستخدامها في إنشاء الكائن الجديد بدلا من إنشاء intrinsic data جديدة.
- Client: يدير ويعمل على إدارة الوظائف الداخلية للكائن.
- IFlyweight: واجهة يستخدم في إنشاء البيانات الداخلية للكائنات intrinsic State.
- FlyweightFactory: إنشاء وإدارة الاجزاء الفريدة من نوعها data intrinsic.
- Flyweight: تخزين وانشاء ومشاركة الكائنات المتشابهة بين الكائنات.
مثال
عدلعرض صور مصغرة ومقسمة إلى مجموعات. في البداية نقوم بعمل الواجهة الذي سنشتق منه.
public interface IFlyweight
{
void Load(string filename);
void Display(PaintEventArgs e, int row, int col);
}
وهي واجهة بها العمليات الداخلية للكائن الذي نريد ان ننشأه وبها دالتين، الأولى هي Load وهي تقوم على تحميل الصور المصغرة بالذاكرة اما الثانية فهي تقوم بعرض ورسم الصور على الشاشة.
الخطوة الثانية – نقوم بعمل استركتشر يرث من الواجهة
public struct Flyweight : IFlyweight
{
// Intrinsic state
Image pThumbnail;
public void Load(string filename)
{
pThumbnail = new Bitmap(@"E:\wallpapers\" + filename).GetThumbnailImage(100, 100, null, new IntPtr());
}
public void Display(PaintEventArgs e, int row, int col)
{
e.Graphics.DrawImage(pThumbnail, col * 100 + 10, row * 130 + 40, pThumbnail.Width, pThumbnail.Height);
}
}
الآن نملك استركتشر يقوم بعمل ادراج للصورة في الذاكرة ويقوم برسم الصورة على الواجهة. لاحظ ان الدالة load لا تقوم بارجاع القيمة انها فقط تقوم بعملها ولا تعيد القيمة في الـ return value ثم نقوم بانشاء صف تعمل على تخزين الوحدات من الاستركتشر السابق.
public class FlyweightFactory
{
// Keeps an indexed list of IFlyweight objects in existence
Dictionary<string, IFlyweight> flyweights =new Dictionary<string, IFlyweight>();
public FlyweightFactory()
{
flyweights.Clear();
}
public IFlyweight this[string index]
{
get
{
if (!flyweights.ContainsKey(index))
flyweights[index] = new Flyweight();
return flyweights[index];
}
}
}
كما نرى الصف في بدايته يقوم بتعريف Directory المفتاح فيه سترينج String والقيمة FlyWeight وبه indexer تقوم بارجاع قيمة ال flyweight إذا وجدت، والا فانه يقوم بانشاء flyweight جديد وبذلك من خلال الصف نفسه نكون قادرين على الولوج للكائن المراد مباشرة
الآن نقوم بعمل الصف التي ستعرض الصور
class Client
{
// Shared state - the images
static FlyweightFactory album = new FlyweightFactory();
// Unshared state - the groups
static Dictionary<string, List<string>> allGroups = new Dictionary<string, List<string>>();
public void LoadGroups()
{
var myGroups = new[] {
new {Name = "FirstGroup",
Members = new [] {"1.jpg", "2.jpg","3.jpg", "4.jpg"}},
new {Name = "SecondGroup",
Members = new [] {"5.jpg","6.jpg","7.jpg", "8.jpg"}},
new {Name = "ThirdGroup",
Members = new [] {"9.jpg", "10.jpg"}}
};
// Load the Flyweights, saving on shared intrinsic state
foreach (var g in myGroups)
{ // implicit typing
allGroups.Add(g.Name, new List<string>());
foreach (string filename in g.Members)
{
allGroups[g.Name].Add(filename);
album[filename].Load(filename);
}
}
}
public void DisplayGroups(Object source, PaintEventArgs e)
{
// Display the Flyweights, passing the unshared state
int row = 0;
foreach (string g in allGroups.Keys)
{
int col = 0;
e.Graphics.DrawString(g, new Font("Arial", 16), new SolidBrush(Color.Black), new PointF(0, row * 130 + 10));
foreach (string filename in allGroups[g])
{
album[filename].Display(e, row, col);
col++;
}
row++;
}
}
}
الصف هو المسؤول عن إخراج الصورة في شكلها النهائي نقوم بتعريف كائن من الصف FlyweightFactory لكي نضع به صور كل البوم ثم نقوم بعمل مصفوفة directory لكي نضع بها أسماء الصور وأسماء مجموعات الصور.
وضعنا دالتين في هذه الصف الأول LoadGroups وهي تعمل على ادراج الصور والمجموعات في المصفوفات الخاصة بها الدالة الثانية وهي DisplayGroup هي دالة عملها الاساسي هو القيام باستدعاء روتين فرعيالدالة Display من كلاس FlyWieght لتقوم برسم الصورة:
الآن نقوم باستدعاء بتشغيل البرنامج كالاتي
public partial class Window : Form
{
public Window()
{
InitializeComponent();
this.Height = 600;
this.Width = 600;
this.Text = "Picture Groups";
Client client = new Client();
client.LoadGroups();
this.Paint+= new PaintEventHandler(client.DisplayGroups);
}
static void Main()
{
Application.Run(new Window());
}
}
كما نرى البرنامج يعمل على مراحل في البداية قمنا باستدعاء الدالة LoadGroups لكي نجمع الصور لعرضها اثناء العرض وكما نرى الحدث Paint يقوم باستدعاء الدالة DisplayGroups.