در باب factory constructor و static method در dart

به عنوان کسی که مدتی رو با dart و flutter کار کردم برام جای سوال بود فلسفه factory constructor چیه وقتی میشه همون کاری که factory انجام میده رو با static method هم انجام داد.با اندکی جستجو مواردی رو پیدا کردم که factory constructor میتونه مفیدتر واقع بشه.

در ابتدا با یه مثال شروع می کنیم که چرا این دو به هم شبیه هستن.

ابتدا یه کد ساده با استفاده از factory

https://gist.github.com/heftekharm/890f71c7de14b303b5990268990538ec

حالا همین کد با استفاده از static method

https://gist.github.com/heftekharm/ad915cc353440354a2bf5256e9271dcb

همانطور که می بینید نحوه صدا زدن fomJson از کلاس Circle کاملا یکسانه.


اولین مورد اینه که factory می تونه بدون نام باشه اما static method خیر

کد زیر رو ببینید.

https://gist.github.com/heftekharm/1f9438136fdb48a73a695d1615431de9

همینطور که می بینید factory constructor همانند یک constructor عادی صدا زده شده اما نکته اینجاست می توانیم رفتار اون رو در مقایسه با یک constructor عادی تغییر بدیم که مثلا در این مثال به جای اینکه Circle Object جدید ساخته بشه ابتدا در Map جستجو میشه که آیا پیش از این ، Circle با این size ساخته شده یا خیر ، در صورت وجود ، circle قبلا ساخته شده رو بر میگردونه ، در غیر این صورت یک Circle جدید رو میسازه ، داخل Map ذخیره میکنه و سپس اون رو بر میگردونه.

دومین مورد وقتیه که پای Generic Parameters ها میاد وسط

در ساخت شی از کلاس های ساده static method و factory تقریبا مزیتی نسبت به همدیگه ندارن اما اگه پای generic ها یه کلاس باز بشه مقداری قضیه فرق می کنه.این مثال رو ببینید.

https://gist.github.com/heftekharm/fcd1f28e0f7b7f8e0cbaf79f8f5f645b

اگه دقت کنید استفاده از factory اندکی از اضافات کد رو کمتر کرده . اگر در کلاس ، generic های بیشتر و تو در تو داشته باشیم این کاهش اضافات محسوس تر خواهد بود.

سومین مورد اینه که factory یک میانبر ویژه برای ارجاع به سایر constructor ها داره

فرض کنید دو کلاس داریم که از کلاس abstract Shape گسترش یافته اند و از آنجا که میخواهیم استفاده مستقیم از آن ها رو به library که در آن تعریف شده اند محدود کنیم ، در نام گذاری آن از پیشوند _ استفاده می کنیم.

class _Circle extends Shape {
  final int innerRadius;
  _Circle(int outerRadius, [this.innerRadius = 0]) : super(outerRadius);
  @override
  double area() => 3.14 * size * size;
}
class _Square extends Shape {
  _Square(int size) : super(size);
  @override
  double area() => size * size * 1.0;
}

اما میخواهیم کاربر از طریق کلاس والد بتواند به این کلاس ها دسترسی داشته باشد.

اولین روش استفاده از static method هاست. به این صورت که:

https://gist.github.com/heftekharm/9ee58af514e7d0a2b08bec96b0336c4c

همونطور که می بینید پارامتر ها باید دقیقا از متدها به constructor منتقل بشه. شاید برای یک یا دو پارامتر چندان مشکل ساز نباشه اما اگه تعداد پارامترها زیاد شود قطعا خسته کننده خواهد بود. اما حالا همین رو با استفاده factory انجام میدیم.

https://gist.github.com/heftekharm/0d0734ef507ce347e7cae9d9346d0e4d


همانطور که می بینید redirect syntax ویژه برای factory ها کار آسانتر کرده. در flutter جاهای زیادی از این قابلیت استفاده شده مثلا TextButton.icon.

منبع:https://dash-overflow.net/articles/factory