الگوی طراحی Factory که گاهی اوقات به عنوان الگوی سازنده مجازی Virtual Constructor نیز شناخته میشود، راهی برای پنهان کردن منطق ایجاد یک شی را ارائه میدهد، اما تضمین میشود که شیء بازگردانده شده به یک رابط شناخته شده پایبند است.
این الگو روشی را ارائه میدهد که به شما امکان میدهد اشیا را بدون نیاز به دانستن دقیقاً کدام نوع شیء را میسازید، ایجاد کنید.
این کار با پنهان کردن جزئیات ایجاد در داخل یک “کارخانه” انجام میشود که در اینجا همان متد Factory است.
این روش تضمین میکند که همه اشیایی که ایجاد میکند با یک رابط مشترک مطابقت دارند، بنابراین میتوانید بدون نگرانی از جزئیات پیادهسازی، با آنها کار کنید.
این مقاله مناسب افراد تازه کار نیست و اگر هنوز وارد مسیر برنامه نویسی موبایل نشده اید پیشنهاد میکنم از دوره آموزش فلاتر استفاده نمایید.
الگوهای طراحی ایجادی creational design patterns، همانطور که از اسم آنها مشخص است، دستیارهای ما برای ساختن شی و هرچیزی که به آن ربط دارد هستند.
با داشتن این ابزارها تو جعبه آچار برنامهنویسیتون، میتونین سریعتر کد بزنین، قالبهای زیباتر و قابل استفاده مجدد برای شیها درست کنین، و به پروژههاتون یه ساختار کلی و مرتب بدین.
این الگوها مثل نقشههای معماری هستن که با دنبال کردنشون، میتونین مشکلات مربوط به ساختن شی که در خیلی از پروژههای نرمافزاری رخ میدهند را به راحتی حل کنید.
مثلا میتونین از یه الگو استفاده کنین که یه کارخانه شیسازی راه بندازه، و هر بار که لازم شد، به جای اینکه خودتون دست به کار بشین و تکتک قطعات شی رو کنار هم بچسبونین، از این کارخانه بخواین یه شی خوشدست و آماده تحویل بگیرین.
در این مقاله، یه مثال کلاسیک از الگوی طراحی Factory در فریمورک فلاتر و زبان برنامه نویسی دارت را بررسی میکنیم که نشان میدهد چگونه میشود به صورت انعطافپذیر، اشیایی برای نمایش شکلهای مختلف ایجاد کرد.
بعدش هم میبینیم که چطور میتونیم از این الگو برای ساخت سادهی المانهای UI برای پلتفرمهای مختلف در فلاتر استفاده کنیم.
خب، برای اینکه ساختار الگوی روش Factory براتون کاملا جا بیفته، از یه مثال خیلی ساده ولی کلاسیک شروع میکنیم. میخواهیم یه کارخانهی شکل Shape درست کنیم که بتونه مثل یه جادوگر هم مثلث triangle خلق کنه و هم مستطیل rectangle.
طرحِ پایین، اجزای اصلی و ارتباطات بینشون رو نشون میده:
کلاس Shape به عنوان کارخانه و رابط در این مثال عمل میکند، در حالی که Triangle و Rectangle نمونههایی از محصولات عینی کارخانه هستند. این محصولات رابط کارخانه را پیادهسازی میکنند و پیادهسازیهای ملموسی از متد draw() ارائه میدهند.
اما نوبت به پیاده سازی این عملیات به زبان دارت میباشد.
enum ShapeType {
triangle,
rectangle
}
abstract class Shape {
factory Shape(ShapeType type) {
switch (type) {
case ShapeType.triangle: return Triangle();
case ShapeType.rectangle: return Rectangle();
default: return null;
}
}
void draw();
}
class Triangle implements Shape {
@override
void draw() {
print("TRIANGLE");
}
}
class Rectangle implements Shape {
@override
void draw() {
print("RECTANGLE");
}
}
با ایجاد یک enum شروع میکنیم که درخواست نوع خاصی از شکل را برای کد کلاینت آسان میکند. فهرست اشکال را میتوان برای پشتیبانی از انواع بیشتر گسترش داد.
در مرحله بعد، کارخانه اشیا قرار دارد که در این مورد به شکل یک کلاس انتزاعی به نام Shape است.
کلاس Shape یک constructor از نوع Factory دارد که به عنوان متد کارخانه برای این الگو عمل میکند.
این متد مسئول ایجاد اشکال از نوع درخواستی است.
کلاس به صورت Abstract پیاده سازی شده است تا از نمونهسازی مستقیم Shape جلوگیری شود، زیرا کلاس هیچ پیادهسازی برای متد draw() ندارد.
constructorهای کارخانهای زبان دارت مانند توابع static عمل میکنند که اتفاقاً نامی مشابه کلاس دارند و لزوماً نمونهای از همان کلاس را بر نمیگردانند (اگرچه باید یک نوع مرتبط را برگردانند).
با استفاده از این دستور، میتوانیم کد کلاینت را زیبا نگه داریم و به طور موثر استفاده از الگوی Factory Method را از کاربران آن پنهان کنیم.
یک ساختار switch برای بازگرداندن نوع شکل مناسب استفاده میشود و در صورت انتقال یک نوع نامعتبر، null برمیگرداند.
این کلاس با یک اعلان پیادهسازی نشده از یک متد draw() به پایان میرسد، که فقط برای ایجاد یک رابط که کلاس های تابع باید آن را در کلاس خود پیاده سازی کنند.
دو کلاس Rectangle و Triangle هر کدام بصورت جداگانه متد draw را پیاده سازی میکنند.
استفاده از این کلاس به صورت زیر میتواند باشد.
final shape1 = Shape(ShapeType.triangle);
final shape2 = Shape(ShapeType.rectangle);
shape1.draw();
shape2.draw();
براساس قاعده polymorphism در برنامه نویسی شی گرایی برای هر شی متد صحیح draw() فراخوانی میشود.
هم shape1 و هم shape2 از نوع Shape هستند، اما در واقع یکی مثلث و دیگری مستطیل است. میتوان یک List<Shape> ایجاد کرد که حاوی ترکیبی از انواع شکل باشد.
یکی از کاربردهای واضح الگوی روش Factory در یک برنامه فلاتر، تولید عناصر رابط کاربری با استایل بومی برای پلتفرمهای مختلفه.
در این مثال، یه کارخانه دکمهساز هوشمند پلتفرمی میسازیم که دکمههای مناسب برای اندروید یا iOS را تحویل میدهد.
abstract class PlatformButton {
factory PlatformButton(TargetPlatform platform) {
switch (platform) {
case TargetPlatform.android: return AndroidButton();
case TargetPlatform.iOS: return IosButton();
default: return null;
}
}
Widget build({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
});
}
برای دسترسی به ویجتهای ElevatedButton با طراحی متریال و ویجتهای CupertinoButton با استایل iOS، ابتدا کتابخانههای مناسب فلاتر ایمپورت میکنیم.
درست همانند مثال اشکال از بخش قبلی، یه کلاس انتزاعی برای قرار دادن متد کارخانه ایجاد میکنیم.
constructor کارخانهای PlatformButton، بر اساس مقدار پارامتر platform، یه نمونه از کلاسی که PlatformButton رو پیادهسازی میکنه، برمیگردونه.
TargetPlatform یک enum هست که توسط فریمورک Flutter ارائه شده و برای هر کدوم از پلتفرمهای پشتیبانیشده فلاتر مقادیری داره.
بخش switch اینجا وظیفه داره که یه نمونه دکمه مطابق با ترجیح کاربر برگردونه. توجه داشته باشین که AndroidButton و IosButton هنوز ایجاد نشدن، اما نگران نباشین، به زودی میرسیم بهشون.
PlatformButton همچنین یه اعلان پیادهسازی نشده برای متد build() داره تا انتظار ایجاد کنه که پیادهکنندهها اون رو با یه signature سازگار override میکنند.
متد build() پارامترهایی رو میگیره که توسط ویجتهای دکمه خاص پلتفرم مورد نیاز هستند.
class AndroidButton implements PlatformButton {
@override
Widget build({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
}) {
return ElevatedButton(
child: child,
onPressed: onPressed,
);
}
}
class IosButton implements PlatformButton {
@override
Widget build({
@required BuildContext context,
@required Widget child,
@required VoidCallback onPressed
}) {
return CupertinoButton(
child: child,
onPressed: onPressed,
);
}
}
AndroidButton و IosButton اینترفیسی که توسط PlatformButton ایجاد شده پیادهسازی میکنن و متد build() هر کلاس، یه ویجت دکمه با استایل متناسب با اون پلتفرمها رو برمیگردونه.
آرگومانهای child و onPressed به اون ویجتها منتقل میشن. یه جایی توی برنامه، یه کارخانه PlatformButton میتونه اینجوری ایجاد بشه:
PlatformButton(TargetPlatform.android)
و یا به این شکل:
PlatformButton(Theme.of(context).platform)
با این روش، همه دکمههای یک برنامه میتونن بهطور خودکار با استایل پلتفرم میزبان رندر بشن و متدهای build برنامه هم با کدهای اضافی تشخیص پلتفرم شلوغ نمیشوند.
برای ساختن یه دکمه، فقط کافیه متد build() رو صدا بزنید:
PlatformButton(Theme.of(context).platform).build(
context: context,
child: Text('My Button'),
onPressed: () => print('Button pressed!'),
)
با کدی که فقط کمی بیشتر از ایجاد یک دکمه معمولی هست، میتونین یه دکمه داشته باشین که از استایل متریال دیزاین اندروید استفاده میکنه یا دکمهای که ظاهر و حس iOS رو داره، و این کاملاً بستگی به پلتفرمی داره که برنامه فلاتر شما روی اون اجرا میشه.
تا اینجا یاد گرفتیم که چطور از الگوی طراحی Factory برای کمک به برنامههامون در ایجاد یکپارچه دکمههایی با استایل متناسب با پلتفرم استفاده کنیم.
گیتهاب اکشن GitHub Actions یکی از ابزارهای گیتهاب است که به شما کمک میکنه تا…
اگر یک برنامه نویس فلاتر هستید و با از نسخه وب اپلیکیشن پروژتون استفاده میکنید…
به عنوان یک برنامه نویس فلاتر یا اندروید بعد از اتمام پروسه طراحی اپلیکیشن نیاز…
طراحی رابط کاربری اپلیکیشن پادکست خود را با استفاده از این کیت توسعه UI/UX فلاتر…
فایربیس، پلتفرمی قدرتمند از شرکت گوگل برای توسعه و مدیریت برنامههای موبایل و وب است.…
فلاتر یک فریم ورک برنامه نویسی چندسکویی است که این امکان را برای برنامه نویس…