در حال حاضر ما یک معماری AOP محور (Aspect-Oriented Programming) داریم که با استفاده از دکوراتورها رفتارهای قبل و بعد از اجرای تابع اصلی را کنترل میکنه. مثلا قبل از ایجاد یک فاکتور فروش دادههای مربوط به مشتری، محصولات و مالیاتها را بررسی میکند که به صورت مناسب تعریف شده باشد. حالا در کام بعد میخوام مرحلهی تولید پارامترها (input preparation) را هم به شکلی تمیز و قابلمدیریت در همین چارچوب طراحی و پیاده سازی کنیم.
قدمبهقدم بررسی میکنم که چطور این کار را میشود انجام داد و بعد چند راهحل پیشنهادی ارائه میکنم. همین سیستم رو توسعه میدیم و در ماژول connector_base اسفتاده میکنیم.
🧩 وضعیت فعلی (خلاصهای از سیستم مدیریت پردازشها)
مثلاً چیزی شبیه این داریم که قرار است یک فاکتور فروش را ایجاد کند.:
@process("create")
@pre_process("import_record_job_builder", "res.partner")
@post_process("import_record_job_builder", "product.product")
def create(self, **kwargs):
...
و در جایی مثلاً:
def prepare_res_partner_params(record):
return {"external_id": record.get("customer_id")}
الان میخواهید این تابع آمادهسازی را هم از طریق دکوراتور مشخص کنید تا کد به این شکل تمیز و صریح شود:
@process("create")
@pre_process("import_record_job_builder", "res.partner", init_function="prepare_res_partner_params")
@post_process("import_record_job_builder", "product.product")
def create(self, **kwargs):
...
✅ راهحل پیشنهادی ۱: پارامتر param_builder در خود دکوراتور
شما میتوانید دکوراتورهای pre_process و post_process را طوری بازنویسی کنید که نام تابع (یا خود تابع) سازندهی پارامتر را بپذیرند.
پیادهسازی پیشنهادی
در این پیاده سازی ابتدا ما تابع تعیین شده را در ساختار دادهای نگهداری پردازش ذخیره میکنیم. بعد زمانی که میخواهیم پردازش را مایجاد کنیم پارامترها را به آن پاس داده و نتایج جدید را ایجاد میکنم.
و استفاده از این روش به سادگی به صورت زیر خواهد بود
def prepare_res_partner_params(record):
return {"external_id": record.get("customer_id")}
@process("create")
@pre_process("import_record_job_builder", "res.partner", param_generator="prepare_res_partner_params")
@post_process("import_record_job_builder", "product.product")
def create(self, **kwargs):
...
✅ راهحل پیشنهادی ۲: دکوراتور اختصاصی برای تولید پارامترها
اگر بخواهید این مفهوم را از pre/post جدا کنید (یعنی منطق تولید پارامتر در یک لایه جدا باشد)، میتوانید دکوراتور جدیدی بسازید مثلاً @param_generator. این دکوراتور تعیین میکنه که مثلا برای یک مدل خاص چطور از پارامترهای ورودی میتوانیم دادههای مورد نیاز را ایجاد کنیم. این دکوراتور تولید کنندگان داده را در یک لیست جمع میکنم زمانی که لازم باشد دادهها تبدیل شوند از این لیست مبدل مورد نیاز استخراج میشود.
نکته اینکه مبدل داده باید سمتی استفاده شود که پردازش اصلی تعریف شده. چرا که هدف تبدیل دادههای ورودی آن پردازش به پردازشهای مورد نیاز قبل و بعد است.
استفاده از این روش به صورت زیر هست:
def prepare_res_partner_params(record):
return {"external_id": record.get("customer_id")}
@process("create")
@pre_process("import_record_job_builder", "res.partner")
@post_process("import_record_job_builder", "product.product")
@param_generator("res.partner", "prepare_res_partner_params")
def create(self, **kwargs):
...
این روش تمیزتر است چون دکوراتورها بهخوبی مسئولیتها را جدا میکنند.
✨ روش ترکیبی
گاهی برای یک پردازش نیاز به استفاده از یک تولید کننده پارامتر هست. و گاهی استفاده از این مبدلها برای تمام پردازشها مشابه هست. با استفاده از روش ترکیبی میتوان این کار را انجام داد. در زیر یک نمونه هست:
@param_generator(
apply_on="res.partner",
usage="exporter",
name="prepare_res_partner_params",
)
class ImporterComponent(Component):
def prepare_res_partner_params(record):
return {"external_id": record.get("customer_id")}
def prepare_res_partner_params_2(record):
return {"external_id": record.get("customer_id")}
@process("create")
@pre_process("import_record_job_builder", "res.partner")
def create(self, **kwargs):
...
@process("update")
@pre_process(
"import_record_job_builder",
"res.partner",
param_generator="prepare_res_partner_params_2"
)
def create(self, **kwargs):
...