Light logo

کانتینرها

با اصول اولیه کانتینرها در ReArch آشنا شوید.

کانتینرها

بعد از کپسول‌ها، کانتینرها دومین بخش سطح بالایین که باید توی ReArch بفهمی.
کانتینرها اسمشون رو از این گرفتن که داده‌های کپسول‌ها رو "نگه می‌دارن".
حتی اگه فقط از فلاتر با flutter_rearch استفاده می‌کنی
(که ویجت RearchBootstrapper رو به جای استفاده مستقیم از کانتینرها ارائه می‌ده)،
باز هم بهتره بفهمی داده‌ها توی پس‌زمینه چطور مدیریت می‌شن.

پس کانتینر دقیقاً چیه؟

به‌طور خلاصه، کانتینرها فقط یه wrapper فانتزی برای HashMap هستن.
اونا کپسول‌ها رو به حالت‌ها و داده‌های داخلیشون نگاشت (map) می‌کنن.
کانتینرها به‌صورت تنبل (lazy) کار می‌کنن و داده‌ها رو تا جایی که ممکنه کش می‌کنن،
و کپسول‌ها رو (که یادتونه—just functions هستن) فراخوانی می‌کنن
تا کش کانتینر رو بسازن.

کانتینرها این امکانات رو ارائه می‌دن:

  • read() برای خوندن داده فعلی یه سری کپسول
  • listen() برای موقتاً گوش دادن به تغییرات یه سری کپسول

هر پیاده‌سازی ممکنه متدهای دیگه‌ای هم روی کانتینرها داشته باشه،
ولی می‌تونی برای اطلاعات بیشتر به مستندات API مراجعه کنی.
این متدها معمولاً برای موارد خیلی خاص و پیشرفته استفاده می‌شن.

خوندن کپسول‌ها

خوندن کپسول‌ها
int countCapsule(CapsuleHandle _) => 0;
int countPlusOneCapsule(CapsuleHandle use) => use(countCapsule) + 1;

final container = CapsuleContainer();
final count = container.read(countCapsule);
final countPlusOne = container.read(countPlusOneCapsule);

اطلاعات مهم فقط برای Rust

توجه کن که توی مثال بالا یه تاپل (tuple) به read() پاس دادیم؛ این خیلی مهمه.
این کار یه خوندن پایدار بین کپسول‌ها رو تضمین می‌کنه، و علاوه بر این، سربار (overhead) رو کم می‌کنه.
سناریوی زیر رو در نظر بگیر:

rust
let count = container.read(count_capsule);
let count_plus_one = container.read(count_plus_one_capsule);

فرض کن یه thread دیگه بعد از خط اول، مقدار count کانتینر رو افزایش بده؛
اون وقت count می‌شه 0 و count_plus_one می‌شه 2!
برای همین، تا جایی که می‌تونی همه خوندن‌های کانتینر رو با هم گروه‌بندی کن،
حتی اگه همیشه به حالت همه کپسول‌هایی که می‌خونی نیاز نداشته باشی!
(این با توی ساخت یه کپسول فرق داره،
که اونجا تشویق می‌شی به‌صورت شرطی get(some_capsule) رو فراخوانی کنی تا از بعضی بازسازی‌ها جلوگیری کنی.)

یه سری نکته مهم دیگه:

  • کانتینرها کپی ارزونی دارن (داخلاً از Arc استفاده می‌شه)، پس راحت کپی‌شون کن.
  • کانتینرها thread-safe هستن و برای اشتراک‌گذاری بین threadها طراحی شدن.

گوش دادن به تغییرات

برای موقتاً گوش دادن به کپسول‌ها، مثال زیر رو ببین.

موقتاً گوش دادن به کپسول‌ها
final container = CapsuleContainer();
final disposeListener = container.listen((use) => print(use(fooBarCapsule)));

// وقتی دیگه نیازی به گوش دادن به تغییرات نداری:  
disposeListener();

اگه بخوای توی طول عمر یه کانتینر به تغییرات کپسول‌ها گوش بدی،
از listen() استفاده نکن.
به جاش، یه کپسول غیرidempotent بساز (یه روش فانتزی برای گفتن کپسولی که یه اثر جانبی ثبت می‌کنه)
و یه بار بخونش تا مطمئن شی که مقداردهی شده و داره گوش می‌ده.

گوش دادن به کپسول‌ها به‌صورت نامحدود
void listener(CapsuleHandle use) {
  // asListener یه اثر جانبی no-op هست که می‌تونی  
  // برای تعریف کپسول‌ها به‌عنوان شنونده ازش استفاده کنی  
  use.asListener();

  // به داده‌هات مثل همیشه گوش بده  
  print(use(countCapsule));
}

// شنونده رو مقداردهی کن تا آپدیت‌ها رو بگیره  
final container = CapsuleContainer();
container.read(listener);