زمان تخمینی مطالعه: 9 دقیقه
الگوی Facade یا نما، پیچیدگیهای سیستم را پنهان میکند و اینترفیسی را برای مشتری فراهم میکند که با استفاده از آن مشتری میتواند به سیستم دسترسی داشته باشد. این نوع الگوی طراحی زیر مجموعهای از الگوی ساختاری(Structural) قرار میگیرد زیرا این الگو یک اینترفیس به سیستم موجود اضافه میکند تا پیچیدگیهای آن را پنهان کند. این الگو شامل یک کلاس واحد است که متدهای ساده شده مورد نیاز مشتری را ارائه میدهد و فراخوانیها را به متدهای کلاسهای سیستم موجود واگذار میکند. در واقع Facade یک الگوی طراحی است که یک اینترفیس ساده برای یک کتابخانه، یک چارچوب یا هر مجموعه پیچیده دیگری از کلاسها را ارائه میدهد.
بیان مسئله: تصور کنید که باید کد نوشته شده شما باید با مجموعه وسیعی از اشیاء که به یک کتابخانه یا چارچوب پیچیده تعلق دارند، کار کند. به طور معمول، شما باید تمام این اشیاء را مقداردهی اولیه کنید، وابستگیها را پیگیری کنید، متدها را به ترتیب صحیح اجرا کنید و غیره. در نتیجه، منطق تجاری کلاسهای شما به شدت با جزئیات پیادهسازی کلاسهای شخص ثالث مرتبط میشود و درک و نگهداری آن را سخت میکند.
الگوی Facade کلاسی است که یک اینترفیس ساده برای یک زیرسیستم پیچیده که شامل تعداد زیادی قطعات متحرک است فراهم میکند. یک الگوی نما ممکن است عملکرد محدودی را در مقایسه با کار مستقیم با زیرسیستم ارائه دهد. با این حال، فقط شامل ویژگیهایی است که مشتریان واقعاً به آنها اهمیت میدهند. داشتن الگوی Facade زمانی مفید است که نیاز دارید برنامه خود را با کتابخانهای پیچیده که دارای دهها ویژگی است یکپارچه کنید، اما شما فقط به تعداد کمی از عملکرد آن نیاز دارید. به عنوان مثال، اپلیکیشنی که ویدیوهای خندهدار کوتاه با گربهها را در رسانههای اجتماعی آپلود میکند، میتواند به طور بالقوه از یک کتابخانه تبدیل ویدیویی حرفهای استفاده کند. با این حال، تمام چیزی که واقعاً به آن نیاز دارد، یک کلاس با متد واحد encode(filename, format) است. پس از ایجاد چنین کلاسی و اتصال آن با کتابخانه تبدیل ویدیو، اولین الگوی Facade خود را خواهید داشت.
نمونه قابل قیاس در دنیای واقعی
هنگامی که برای سفارش تلفنی، مشتری با یک مغازه تماس میگیرد، اپراتور پاسخگو به مشتری در واقع نمایانگر شما برای تمامی خدمات و بخشهای فروشگاهی است که اداره میکنید. این اپراتور یک رابط صوتی ساده برای سیستم سفارش، درگاههای پرداخت و خدمات مختلف تحویل را در اختیار شما قرار میدهد.
ساختار الگوی Facade
در این بخش به بررسی ساختار الگوی نما(Facade) میپردازیم و پیادهسازی آن را به صورت UML خواهیم دید.
- گام 1: الگوی Facade دسترسی راحت به بخش خاصی از عملکرد زیرسیستم را فراهم میکند. در واقع میداند که درخواست مشتری را به کجا هدایت کند و چگونه تمام قطعات متحرک را وادار به کار کند.
- گام 2: یک کلاس facade اضافی را میتوان برای جلوگیری از آلودگی یک نما(facade) با ویژگیهای نامرتبط ایجاد کرد که ممکن است آن را به ساختار پیچیده دیگری تبدیل کند. نماهای اضافی هم برای مشتریان و هم برای نماهای دیگر قابل استفاده است.
- گام 3: زیرسیستم پیچیده از دهها شی مختلف تشکیل شده است. برای اینکه همه آنها کاری معنادار انجام دهند، باید عمیقاً در جزئیات پیادهسازی زیر سیستم فرو بروید، مانند مقداردهی اولیه اشیاء به ترتیب صحیح و ارائه دادهها به آنها با فرمت مناسب. طبقات زیرسیستم از وجود Facade آگاه نیستند. آنها در داخل سیستم عمل میکنند و مستقیماً با یکدیگر کار میکنند.
- گام 4: Client به جای فراخوانی مستقیم اشیاء زیرسیستم از نما استفاده میکند.
شبه کد(Pseudocode)
در این مثال، الگوی Facade تعامل با یک چارچوب پیچیده تبدیل ویدیو را ساده میکند.
به جای اینکه کاری کنید که کد شما مستقیماً با دهها کلاس فریمورک کار کند، یک کلاس Facade ایجاد کند که آن عملکرد را محصور میکند و آن را از بقیه کدها پنهان میکند. این ساختار همچنین به شما کمک میکند تا تلاش برای ارتقاء به نسخههای آینده فریم ورک یا جایگزینی آن با فریمورک دیگری را به حداقل برسانید. تنها چیزی که باید در برنامه خود تغییر دهید، اجرای متدهای الگوی Facade است.
// These are some of the classes of a complex 3rd-party video
// conversion framework. We don't control that code, therefore
// can't simplify it.
class VideoFile
// ...
class OggCompressionCodec
// ...
class MPEG4CompressionCodec
// ...
class CodecFactory
// ...
class BitrateReader
// ...
class AudioMixer
// ...
// We create a facade class to hide the framework's complexity
// behind a simple interface. It's a trade-off between
// functionality and simplicity.
class VideoConverter is
method convert(filename, format):File is
file = new VideoFile(filename)
sourceCodec = (new CodecFactory).extract(file)
if (format == "mp4")
destinationCodec = new MPEG4CompressionCodec()
else
destinationCodec = new OggCompressionCodec()
buffer = BitrateReader.read(filename, sourceCodec)
result = BitrateReader.convert(buffer, destinationCodec)
result = (new AudioMixer()).fix(result)
return new File(result)
// Application classes don't depend on a billion classes
// provided by the complex framework. Also, if you decide to
// switch frameworks, you only need to rewrite the facade class.
class Application is
method main() is
convertor = new VideoConverter()
mp4 = convertor.convert("funny-cats-video.ogg", "mp4")
mp4.save()
قابلیتها و کاربردها
- زمانی که نیاز به داشتن یک اینترفیس محدود اما ساده برای یک زیر سیستم پیچیده دارید، از الگوی Facade استفاده کنید. اغلب، سیستمهای فرعی با گذشت زمان پیچیدهتر میشوند. حتی استفاده از الگوهای طراحی معمولاً منجر به ایجاد کلاسهای بیشتر میشود. یک زیر سیستم ممکن است انعطافپذیرتر شود و استفاده مجدد آن در زمینههای مختلف آسانتر شود، اما مقدار پیکربندی و کد مشخصی که از یک مشتری میخواهد نیز بیشتر میشود. الگوی Facade سعی میکند این مشکل را با ارائه یک میانبر برای پرکاربردترین ویژگیهای زیر سیستم که مطابق با اکثر نیازهای مشتری است، برطرف کند.
- زمانی که میخواهید یک زیر سیستم را به صورت لایهای ساختار دهید از الگوی Facade استفاده کنید. برای تعریف نقاط ورود به هر سطح از یک زیر سیستم، نماهایی ایجاد کنید. شما میتوانید اتصال بین چندین زیر سیستم را با الزام آنها به ارتباط فقط از طریق Facade کاهش دهید. به عنوان مثال، اجازه دهید به چارچوب تبدیل ویدیوی خود بازگردیم. میتوان آن را به دو لایه تقسیم کرد: تبدیلات تصویر و تبدیلات صوت. برای هر لایه، میتوانید یک نما ایجاد کنید و سپس کلاسهای هر لایه را از طریق آن نماها به یکدیگر ارتباط دهید. این رویکرد بسیار شبیه به الگوی Mediator است.
نحوه پیادهسازی
- بررسی کنید که آیا امکان ارائه رابط کاربری سادهتر از آنچه که یک زیر سیستم موجود در حال حاضر ارائه میدهد وجود دارد یا خیر. اگر این اینترفیس کد مشتری را از بسیاری از کلاسهای زیر سیستم مستقل کند، در مسیر درستی هستید.
- این اینترفیس را در یک کلاس نمای جدید تعریف و پیادهسازی کنید. نما باید فراخوانیها را از کد مشتری به اشیاء مناسب زیر سیستم هدایت کند. نما باید مسئول اولیهسازی زیرسیستم و مدیریت چرخه عمر بیشتر آن باشد مگر اینکه کد مشتری قبلاً این کار را انجام دهد.
- برای بهرهمندی کامل از الگوی Facade، کاری کنید که تمام کدهای مشتری فقط از طریق نما با زیر سیستم ارتباط برقرار کنند. اکنون کد مشتری از هر گونه تغییر در کد زیر سیستم محافظت میشود. به عنوان مثال، هنگامی که یک زیر سیستم به نسخه جدید ارتقا مییابد، فقط باید کد موجود در نما را تغییر دهید.
- اگر نما خیلی بزرگ شد، بخشی از رفتار آن را به یک کلاس نمای جدید و تصفیه شده انتقال دهید.
مزایا و معایب الگوی Facade
این الگوی طراحی دارای مزایا و معایبی به شرح زیر است:
– مزایا
- شما میتوانید کد خود را از پیچیدگی یک زیر سیستم جدا کنید.
– معایب
- یک نما میتواند تبدیل به یک شیء خدا گونه(God object) شود که با تمام کلاسهای یک برنامه همراه است.
ارتباط با الگوهای دیگر
- الگوی Facade یک اینترفیس جدید برای اشیاء موجود تعریف میکند، در حالی که Adapter سعی میکند اینترفیس موجود را قابل استفادهتر کند. الگوی آداپتور معمولاً فقط یک شی را میپوشاند، در حالی که Facade با یک زیر سیستم کامل از اشیا کار میکند.
- الگوی Abstract Factory میتواند به عنوان جایگزینی برای Facade عمل کند زمانی که شما فقط میخواهید نحوه ایجاد اشیاء زیر سیستم را از کد مشتری پنهان کنید.
- الگوی Flyweight نحوه ساخت تعداد زیادی اشیاء کوچک را نشان میدهد، در حالی که Facade نشان میدهد که چگونه یک شی منفرد بسازید که یک زیر سیستم کامل را نشان میدهد.
- الگوهای Facade و Mediator عملکرد مشابهی دارند: آنها سعی میکنند همکاری بین بسیاری از کلاسهای کاملاً مرتبط را سازماندهی کنند.
- Facade یک اینترفیس ساده برای زیر سیستمی از اشیاء تعریف میکند، اما هیچ عملکرد جدیدی را تعریف نمیکند. خود زیر سیستم از نما بیاطلاع است. اشیاء درون زیر سیستم میتوانند مستقیماً ارتباط برقرار کنند.
- Mediator ارتباط بین اجزای سیستم را متمرکز میکند. اجزاء فقط در مورد شی واسطه میدانند و مستقیماً ارتباط برقرار نمیکنند.
- یک کلاس Facade اغلب میتواند به یک Singleton تبدیل شود زیرا یک شی نما در بیشتر موارد کافی است.
- الگوی Facade شبیه به Proxy است که هم یک موجودیت پیچیده را بافر میکند و هم آن را به تنهایی مقداردهی اولیه میکند. بر خلاف Facade، الگوی Proxy دارای اینترفیس یکسانی با شی سرویس خود است که باعث میشود آنها قابل تعویض باشند.