اخبار، مطالب و رویدادهای مرتبط با توسعه نرم افزار رادکام

الگوی طراحی Bridge

نقش الگوی طراحی bridge

اگر بخواهیم وظیفه اصلی الگوی طراحی Bridge را در یک جمله بیان کنیم، باید بگوییم: الگوی طراحی Bridge، پیاده سازی (Implementation) را از انتزاع (Abstraction) جدا می کند و این امکان را فراهم می کند تا این دو بتوانند به طور مستقل از هم عمل کنند. یکی از مهمترین کاربرد های الگوی طراحی Bridge زمانی است که نسخه جدیدی از یک نرم افزار متولد می شود که قرار است جایگزین نسخه قدیمی آن شود و قرار هست که نسخه قدیمی این نرم افزار نیز به همان قدرت قبلی به کار خود ادامه دهد. تا مشتریان قبلی بتوانند همچنان از نرم افزار خریداری شده خود استفاده کنند. کد برنامه نیازی ندارد تا تغییر کند، زیرا ساختار کد به دلیل تطابق با انتزاع (Abstraction) موجود مشخص است، ولی استفاده کننده خود باید مشخص کند که از کدام نسخه می خواهد در برنامه استفاده کند.

تصویر کلی الگوی طراحی bridge

گسترش نسخه جدید Net FrameWork. را در نظر بگیرید که برای تهیه و اجرای C# 3.0 استفاده شده است.شما می توانید در هر برهه ای از زمان چندین نسخه از فریمورک را در کامپیوتر خود داشته باشید و می توانید نسخه ای را که قصد استفاده از آن را دارید انتخاب کنید. که این کار با استفاده از تخصیص یک مسیر مشخص به نسخه های مختلف فریم ورک در سیستم عامل ویندوز صورت می گیرد. تنظیم این مسیر در واقع پلی است بین آنچه برنامه ها از فریم ورک می خواهند و نسخه واقعی که در جواب درخواست دریافت می کنند. در شکل زیر می بینید که پنج نسخه از فریم ورک در کامپیوتر بارگذاری شده است و در شکل بعد از آن نیز می بینید که نسخه ای که سیستم به سمت آن هدایت می شود نسخه 3.5 است که این نسخه شامل کامپایلر C3 3.0 است.

five versions of the .NET Framework loaded

environment Path variable set to Version 3.5

طراحی الگوی طراحی bridge

ارث بری روشی معمول برای مشخص کردن پیاده سازی های مختلف انتزاع (یک کلاس abstract) است. با این حال پیاده سازی ها به شدت به انتزاع (این کلاس های abstract) متصل  می شوند (اتصال سخت). و اعمال تغییرات در آنها به طور مستقل دشوار است. وقتی بیش از یک نوع از انتزاع داشته باشیم، الگوی Bridge جایگزینی برای ارث بری ارایه می دهد. نمودار UML زیر را در نظر بگیرید. دو نوع پیاده سازی به نام های A  و B ، اینترفیس Bridge را پیاده سازی می کنند. در انتزاع (کلاس abstract) یک مشخصه از نوع Bridge وجود دارد، اما به عبارت دیگر هیچ ارتباطی با پیاده سازی های مربوطه ندارد.

Bridge Pattern UML Diagram

از این نمودار می توانیم دریابیم که نقش آفرینان الگوی Bridge عبارتند از:
  • انتزاع (Abstraction)
    رابط کاربری که استفاده کننده می بیند.
  • عملیات (Operation)
    متدی که توسط استفاده کننده فرخوانی می شود.
  • پل (Bridge)
    اینترفیسی که آن بخش هایی از انتزاع که ممکن است متفاوت باشد را تعریف می کند.
  • پیاده سازی A و پیاده سازی B
    یک نوع پیاده سازی از اینترفیس Bridge
  • پیاده سازی متد
    متدی است در Bridge که از متد قرار داده شده در انتزاع (کلاس Abstract) فراخوانی می شود.
همانگونه که در الگوی طراحی Decorator دیدیم، برای یک انتزاع (کلاس Abstract) می توانیم پیاده سازی های متعددی داشته باشیم. پیاده سازی های مرتبط با ارث بری، اگر تصمیم دارند با همان روش قدیمی ایجاد و استفاده شوند، مجبور نیستند تا اینترفیس Bridge را پیاده سازی کنند. آنها فقط در صورت نیاز به استفاده متقابل از پیاده سازی های جدید ، این کار را باید انجام دهند (اینترفیس Bridge را پیاده سازی کنند).

پیاده سازی الگوی طراحی bridge

بار دیگر با یک مثال کوچک نظری (theoretical) شروع می کنیم. همانطور که مشاهده می کنید، هر نمونه سازی از انتزاع خود یک پیاده سازی متفاوتی دارد. و سپس، عملیات مربوطه فراخوانی می شود. هر فراخوانی به سمت یک پیاده سازی از عملیات هدایت می شود، و نتیجه مربوط به آن فراخوانی هم نمایش داده می شود. توجه داشته باشید که مجموعه پیاده سازی های نوشته شده، اینترفیس Bridge را پیاده سازی می کنند و انتزاع (کلاس Abstract) آن را یکپارچه می کند.


using System;

class BridgePattern 
{

	// Bridge Pattern Judith Bishop Dec 2006, Aug 2007
	// Shows an abstraction and two implementations proceeding independently

	class Abstraction 
	{
		Bridge bridge;
		public Abstraction (Bridge implementation) 
		{
			bridge = implementation;
		}
		public string Operation() 
		{
			return "Abstraction" + " <<< BRIDGE >>>> " + bridge.OperationImp();
 		}
	 }

	 interface Bridge 
	 {
		string OperationImp( );
	 }

	 class ImplementationA : Bridge 
	 {
	 	public string OperationImp ( ) 
	 	{
			return "ImplementationA";
 		}
	 }

	 class ImplementationB : Bridge 
	 {
		 public string OperationImp ( ) 
		 {
		 	return "ImplementationB";
		 }
	 }

	 static void Main ( ) 
	 {
		 Console.WriteLine("Bridge Pattern\n");
		 Console.WriteLine(new Abstraction (new ImplementationA( )).Operation( ));
		 Console.WriteLine(new Abstraction (new ImplementationB( )).Operation( ));
	 }
 }
 /* Output
 Bridge Pattern

 Abstraction <<< BRIDGE >>>> ImplementationA
 Abstraction <<< BRIDGE >>>> ImplementationB
 */

کاربرد الگوی طراحی Bridge

الگوی طراحی بریج (Bridge) یک الگوی به ظاهر ساده اما بسیار قدرتمند است، ما اگر پیاده سازی انجام شده در این الگو را در نظر بگیریم، با استفاده از Bridge و کلاس Abstract می توانیم دومین پیاده سازی را نیز به ساختار برنامه اضافه کنیم و به یک عمومیت و کلیت قابل توجهی نسبت به طرح اولیه اصلی دست پیدا کنیم. استفاده مناسب از الگوی طراحی پل، در کار های گرافیکی نمود پیدا می کند، آنجایی که نمایشگر های گوناگون، امکانات و سیستم های راه اندازی متفاوتی دارند.  اینها می توانند پیاده سازی الگوی Bridge باشند و Bridge می تواند یک اینترفیس از امکانات و توانایی های اساسی  آنها باشد. استفاده کننده از الگو، کلاس Abstract را فراخوانی می کند تا چیزی را نمایش دهد، و کلاس Abstract مشخصه های نمونه های ایجاد شده از Bridge را بررسی کرده و بهترین آنها را برای انجام کار درخواست شده انتخاب می کند.

از الگوی طراحی Bridge زمانی استفاده می کنیم که:

بتوانیم:
  • تشخیص دهیم، عملیاتی وجود دارد، که همیشه نیازی به اجرای آنها به یک روش  و متد ثابت نداریم و می توانیم نحوه اجرای آن را تغییر دهیم.
می خواهیم:
  • نحوه پیاده سازی ها را از استفاده کننده های آن پنهان کنیم.
  • از مقید کردن یک پیاده سازی به یک انتزاع (کلاس Abstract) به طور مستقیم اجتناب کنیم.
  • پیاده سازی انجام شده را تغییر دهیم، بدون این که نیاز به کامپایل مجدد کلاس Abstract باشیم.
  • قسمت های مختلف یک سیستم را در زمان اجرا پیوند داده و با هم ترکیب کنیم.

مثال: OpenBook

 الگوی طراحی Bridge، فرصت مناسبی در اختیار ما قرار می دهد تا بتوانیم مثالی که در الگو های طراحی Decorator و Proxy داشتیم را گسترش داده و تعامل الگوهای مختلف را با هم نشان دهیم. دوباره سیستم SpaceBook را در نظر می گیریم. فرض می کنیم که برنامه نویس بر روی یک نسخه جدیدی از SpaceBook کار می کند که نامش OpenBook است. مشخصه اصلی OpenBook این است که نیازی به اعتبار سنجی رمز عبور در آن وجود ندارد. همچنین ایجاد نمونه ها باعث ایجاد مشکل نخواهند شد، از آنجاییکه فرض بر این است که کاربران برنامه OpenBook به صورت مستقیم به سیستم دسترسی پیدا خواهند کرد. بنابراین، OpenBook جایگزین الگوی پروکسی در مثال SpaceBook شده و ساختار و نتیجه آن را تغییر نخواهد داد، و به طور مطمئن قصد این است که کاربران هر دو سیستم بتوانند صفحات یکدیگر را ببینند.
بنابراین ما یک طراحی را در نظر گرفته ایم که در آن MyOneBook و MySpaceBook باید اینترفیس عمومی را پیاده سازی کنند. ما این را اینترفیس Bridge می نامیم. این پیاده سازی، یک نسخه مناسب از شیء book را نگهداری کرده و هر کدام از متد های موجود در اینترفیس را به نسخه های موجود در آن شیء book هدایت می کند و سپس برنامه اصلی تغییرات را منعکس کرده و نشان می دهد:


class BridgePattern : SpaceBookSystem 
{
	static void Main () 
	{
		MySpaceBook me = new MySpaceBook();
		me.Add("Hello world");
		me.Add("Today I worked 18 hours");
		Portal tom = new Portal(new MyOpenBook("Tom"));
		tom.Poke("Judith");
		tom.Add("Judith","Poor you");
		tom.Add("Hey, I'm also on OpenBook - it was so easy!");
	}
}

کاربرانی مانند  Judith می توانند از همان SpaceBook قدیمی استفاده کنند، انگار که هیچ چیز تغییر نکرده است، اما Tom می تواند از کلاس Abstract (Portal) استفاده کرده و از طریق Bridge به کلاس جدید OpenBook متصل شده و به کلاس قدیمی SpaceBook دسترسی پیدا کنند. خروجی برنامه مانند گذشته آغاز می شود اما در ادامه می بینیم که Tom نیازی به ثبت نام یا تایید اعتبار ندارد.

	
Let's register you for SpaceBook
All SpaceBook names must be unique
Type in a user name: Judith
Type in a password: yey
Thanks for registering with SpaceBook
Welcome Judith. Please type in your password: yey
Logged into SpaceBook
======== Judith's SpaceBook =========
Hello world
Today I worked 18 hours
Tom poked you
Tom : hugged you
================================
======== Judith's SpaceBook =========
Hello world
Today I worked 18 hours
Tom poked you
Tom : hugged you
Tom : Poor you
================================
======== Tom-1's SpaceBook =========
Hey, I'm on OpenBook - it was so easy!
	
حال فرض می کنیم که برنامه نویس تصمیم گرفته است که با اضافه کردن شماره سریال به هر شناسه کاربر از ایجاد مغایرت جلوگیری کند. اگر کاربر بعدی Pat است، نامش Pat-2 خواهد بود. در حال حاظر،خروجی Tom همچنان به SpaceBook اشاره دارد زیرا سیستم جدید نیز همچنان از امکانات SpaceBook استفاده می کند. به مجرد اینکه OpenBook شخصی سازی (Customize) گردید ، تغییر حاصل خواهد گردید. بخش جلویی در اینترفیس Bridge محصور (Encapsulate) شده است.
	
interface Bridge 
{
	void Add(string message);
	void Add(string friend, string message);
	void Poke(string who);
}

Portal بسیار ساده است و وظایف مربوط به انتزاع (Abstraction) را دقیقا مانند آنچه در کد اولیه در بالا دیدیم انجام می دهد. با این حال سه عملیات به جای یک عملیات برای ادامه کار وجود دارد.

	
class Portal 
{
	Bridge bridge;
	public Portal (Bridge aSpaceBook) 
	{
		bridge = aSpaceBook;
	}

	public void Add(string message)
	{
		bridge.Add(message);
	}
	
	public void Add(string friend, string message)
	{
		bridge.Add(friend,message);
	}
		
	public void Poke(string who)
	{
		bridge.Poke(who);
	}
}

پیاده سازی بعدی اینترفیس Bridge در این مثال، خود به عنوان Proxy برای SpaceBook عمل می کند. بسیاری از مکانیسم های الگوی پروکسی از بین رفته اند،  و آنچه باقی مانده است، یک الگوی پروکسی هوشمند است که کار آن نگهداری تعداد شماره سریال کاربران است. حال می توانید OpenBook را در حالت اصلی ببینید.

	
public class MyOpenBook : Bridge 
{
	// Combination of a virtual and authentication proxy
	SpaceBook mySpaceBook;
	string name;
	static int users;
	public MyOpenBook (string n) 
	{
		name = n;
		users++;
		mySpaceBook = new SpaceBook(name+"-"+users);
	}
	public void Add(string message) 
	{
		mySpaceBook.Add(message);
	}
	public void Add(string friend, string message) 
	{
		mySpaceBook.Add(friend, name + " said: "+message);
	}
	public void Poke(string who) 
	{
		mySpaceBook.Poke(who,name);
	}
}

	
در نظر داشته باشید که الگوی Bridge عملیاتی را که توسط همه اعضای کلاس Portal پشتیبانی خواهند شد را مشخص و تعریف می کند. حال فرض کنید کلاس OpenBook بخواهد چند عملیات دیگری مانند SuperPoke را به برنامه اضافه کند:
	
public void SuperPoke (string who, string what) 
{
	myOpenBook.Add(who, what+" you");
}

کلاس SuperPoke به صورتی نسبتا مبتدی در سطح بالای متد Add پیاده سازی شده است، به دلیل اینکه، این یک ویژگی است که توسط SpaceBook پشتیبانی می شود. اگر ما متد SuperPoke را در کلاس OpenBook قرار دهیم، کامپایلر بدون گرفتن ایراد آن را قبول می کند. اما ما نمی توانیم آن را فراخوانی کنیم، زیرا در برنامه اصلی Tom به شیء Portal اشاره می کند، در حالیکه SuperPoke در Portal قرار ندارد. این مشکل را به دو روش می توانیم حل کنیم:

  • عملیات جدیدی به کلاس Portal اضافه کنیم (Abstraction)، و با Bridge کاری نداشته باشیم، بنابراین ، این تغییر روی بقیه پیاده سازی ها اثر نخواهد گذاشت.
  • اگر امکان تغییر در Portal وجود نداشته باشد، می توانیم یک متد از نوع متد های Extension Method ایجاد کنیم تا بتوانیم کلاس مربوطه را گسترش داده باشیم.

static class OpenBookExtensions 
{
	public static void SuperPoke (this Portal me, string who, string what) 
	{
		me.Add(who, what+" you");
	}
}

و به همان روشی که بقیه متد ها را فراخوانی می کنیم، این متد را فراخوانی می کنیم.

tom.SuperPoke("Judith-1","hugged");	

برنامه کامل برای کلاس OpenBook در زیر آورده شده است، کلاس های SpaceBook و MySpaceBook که در بالا دیدیم، به هیچ وجه تغییر نکرده است. در خروجی برنامه ، Judith از Open-book استفاده می کند، بنابراین نام آن به Judith-1 تغییر یافته است، و Top نیز به عنوان دومین کاربر OpenBook، نامش به Tom-2 تغییر یافته است.

	
using System;
using System.Collections.Generic;
// Bridge Pattern Example Judith Bishop Dec 2006, Aug 2007
// Extending SpaceBook with a second implementation via a Portal
// Abstraction
class Portal 
{
	Bridge bridge;
	public Portal (Bridge aSpaceBook) 
	{
		bridge = aSpaceBook;
	}

	public void Add(string message)
	{
		bridge.Add(message);
	}

	public void Add(string friend, string message)
	{
		bridge.Add(friend,message);
	}

	public void Poke(string who)
	{
		bridge.Poke(who);
	}
}
	
// Bridge
interface Bridge 
{
	void Add(string message);
	void Add(string friend, string message);
	void Poke(string who);
}

class SpaceBookSystem 
{
	// The Subject
	private class SpaceBook { ... }
	// The Proxy
	public class MySpaceBook { ... }
	// A Proxy with little to do
	// Illustrates an alternative implementation of the Bridge pattern
	public class MyOpenBook : Bridge 
	{
		// Combination of a virtual and authentication proxy
		SpaceBook myOpenBook;
		string name;
		static int users;
		public MyOpenBook (string n) 
		{
			name = n;
			users++;
			myOpenBook = new SpaceBook(name+"-"+users);
		}

		public void Add(string message) 
		{
			myOpenBook.Add(message);
		}

		public void Add(string friend, string message) 
		{
			myOpenBook.Add(friend, name + " : "+message);
		}

		public void Poke(string who) 
		{
			myOpenBook.Poke(who,name);
		}
	}
}

static class OpenBookExtensions 
{
	public static void SuperPoke (this Portal me, string who, string what) 
	{
		me.Add(who, what+" you");
	}
}

// The Client
class BridgePattern : SpaceBookSystem 
{
	static void Main ( ) 
	{
		Portal me = new Portal(new MyOpenBook("Judith"));
		me.Add("Hello world");
		me.Add("Today I worked 18 hours");
		Portal tom = new Portal(new MyOpenBook("Tom"));
		tom.Poke("Judith-1");
		tom.SuperPoke("Judith-1","hugged");
		tom.Add("Judith-1","Poor you");
		tom.Add("Hey, I'm on OpenBook - it's cool!");
	}
}

/* Output
======== Judith-1's SpaceBook =========
Hello world
===================================
======== Judith-1's SpaceBook =========
Hello world
Today I worked 18 hours
===================================
======== Judith-1's SpaceBook =========
Hello world
Today I worked 18 hours
Tom poked you
Tom : hugged you
===================================
======== Judith-1's SpaceBook =========
Hello world
Today I worked 18 hours
Tom poked you
Tom : hugged you
Tom : Poor you
===================================
======== Tom-2's SpaceBook =========
Hey, I'm on OpenBook - it's cool!
===================================
*/


منبع:

C# 3.0 Design Patterns - Ebook


پست های مرتبط

نام را وارد کنید
تعداد کاراکتر باقیمانده: 1000
نظر خود را وارد کنید