مشخصات مقاله
-
1174
-
0.0
-
4511
-
0
-
0
آموزش سرویسها و تزریق وابستگی(Dependency Injection)
معرفی سرویسها و تزریق وابستگی(Dependency Injection)
سرویسها دستهی گستردهای هستند که تمامی مقادیر، توابع و یا ویژگیهایی که یک برنامه نیاز دارد را شامل میشوند. یک سرویس معمولاً کلاسی است که برای یک هدف کاملاً مشخص و محدود تعریف شده است. سرویس باید یک کار کاملاً مشخصی را به بهترین شکل انجام دهد.
Angular برای افزایش پیمانهای بودن و قابلیت استفادهی مجدد برنامه، کامپوننت ها را از سرویسها جدا میکند. با تفکیک کارکردهای مربوط به view در کامپوننت از دیگر کارکردها میتوانید کلاسهای کامپوننت خود را کم حجم و کارامد کنید.
در حالت ایده آل کار یک کامپوننت تنها فعال کردن تجربهی کاربر است و نه بیشتر. کامپوننت باید بتواند ویژگیها و متدها را برای مقیدسازی داده فراهم کند تا بتواند نقش واسطه را میان view (که توسط قالب رندر شده است) و منطق برنامه (که اغلب شامل مفهومی از یک مدل است) ایفا کند.
کامپوننت میتواند کارهای مشخصی را به سرویسها محول کند، مانند دریافت داده از سرور، تأیید اعتبار ورودی کاربر و یا ارائهی گزارش مستقیم به کنسول. شما میتوانید با تعریف چنین وظایف پردازشی در یک کلاس سرویس قابل تزریق این وظایف را در اختیار تمامی کامپوننت ها قرار دهید. همچنین میتوانید با تزریق انواع مختلفی از ارائه کنندههای سرویسهای هم نوع برنامهی خود را انطباق پذیرتر کنید. این حالت در موقعیتهای مختلف مناسب است.
Angular این اصول را اجبار نمیکند؛ بلکه با تسهیل تفکیک منطق برنامهی خود به سرویسها و قرار دادن آنها در اختیار کامپوننت ها از طریق تزریق وابستگی، به شما کمک میکند از این اصول پیروی کنید.
نمونههایی از سرویسها
در زیر میتوانید مثالی از کلاس سرویس را مشاهده کنید. کار این کلاس ارائهی گزارش به کنسول مرورگر است.
src/app/logger.service.ts (class)
export class Logger {
log(msg: any) { console.log(msg); }
error(msg: any) { console.error(msg); }
warn(msg: any) { console.warn(msg); }
}
سرویسها میتوانند به سرویسهای دیگر وابسته باشند. برای مثال، در ادامه HeroService را مشاهده میکنید که به سرویس Logger وابسته است و در عین حال برای دریافت hero ها از BackendService استفاده میکند. همچنین این سرویس ممکن است برای دریافت hero ها از یک سرور به صورت ناهمگام، به سرویس HttpClient وابسته باشند.
src/app/hero.service.ts (class)
export class HeroService {
private heroes: Hero[] = [];
constructor(
private backend: BackendService,
private logger: Logger) { }
getHeroes() {
this.backend.getAll(Hero).then((heroes: Hero[]) => {
this.logger.log(`Fetched $ {heroes.length} heroes.`);
this.heroes.push(...heroes); // fill cache
});
return this.heroes;
}
}
تزریق وابستگی (DI)
DI رابطهی بسیار نزدیکی با فریمورک Angular دارد و برای قرار دادن سرویسها وچیزهای لازم دیگر در اختیار کامپوننت های جدید، در همه جا کاربرد دارد. کامپوننت ها از سرویسها استفاده میکنند. به این معنی که شما میتوانید سرویسی را داخل یک کامپوننت تزریق کنید و به این کامپوننت امکان دسترسی به این کلاس سرویس را بدهید.
برای تعریف یک کلاس به عنوان سرویس در Angular از دکوراتور @Injectable() استفاده کنید تا بتوانید متادیتاها را فراهم کنید و به دنبال آن Angular بتواند این متادیتا ها را به صورت وابستگی داخل یک کامپوننت تزریق کند.
به طور مشابه برای آن که نشان دهید کامپوننت و یا کلاس دیگری (مانند سرویس، پایپ و یا NgModule دیگر) دارای وابستگی است، باز هم میتوانید از دکوراتور @Injectable() استفاده کنید.
- تزریق کننده سازوکار اصلی است. Angular طی فرآیند بوت استرپ یک تزریق کنندهی در سطح برنامه را ایجاد میکند و در صورت نیاز تزریق کنندههای دیگر را اضافه میکند. نیازی به ایجاد تزریق کنندهها توسط شما نیست.
- تزریق کنندهها وظیفهی ایجاد وابستگیها را برعهده دارند و از نگهدارنده ای از نمونههای وابستگی نگهداری میکنند که در صورت امکان میتوانند از آن استفادهی مجدد کند.
- ارائه کنندهها اشیائی هستند که به یک تزریق کننده می گویند چگونه یک وابستگی را ایجاد کند و یا به دست آورد.
برای هر وابستگیای که برنامهی شما به آن نیاز دارد، باید ارائه کنندهای را با تزریق کنندهی برنامهی خود ثبت کنید. به گونهای که تزریق کننده بتواند برای ایجاد نمونههای جدید از این ارائه کننده استفاده کند. در سرویسها معمولاً این ارائه کننده خود کلاس سرویس است.
وابستگی حتماً نباید یک سرویس باشد، بلکه میتواند مثلاً یک تابع و یا یک مقدار نیز باشد.
زمانی که Angular نمونهی جدیدی از یک کلاس کامپوننت را ایجاد میکند، با نگاه کردن به نوع پارامترهای constructor مشخص میکند که کامپوننت به چه سرویسها و وابستگیهای دیگری نیاز دارد. برای مثال سازندهی HeroListComponent به HeroService نیاز دارد.
src/app/hero-list.component.ts (constructor)
constructor(private service: HeroService) { }
زمانی که Angular پی میبرد کامپوننتی به سرویسی وابسته است، ابتدا بررسی میکند که تزریق کننده نمونههای موجودی از آن سرویس را دارد یا ندارد. اگر هنوز نمونهی سرویس درخواست شدهای به وجود نیامده باشد، در این صورت تزریق کننده با استفاده از ارائه کنندهی ثبت شده، یک نمونه را ایجاد میکند و آن را قبل از برگشت دادن سرویس به Angular به تزریق کننده اضافه میکند.
پس از آن که تمامی سرویسهای درخواست شده حل و فصل شدند و برگشت داده شدند، Angular میتواند constructor را به همراه این سرویسها به صورت آرگومانهایی فراخوانی کند.
فرآیند تزریق HeroService چیزی مانند شکل زیر است.
ارائهی سرویس
از هر تعداد سرویسی که بخواهید استفاده کنید، باید حداقل یک ارائه کننده از آن را ثبت کنید. این ارائه کننده میتواند بخشی از متادیتای خود سرویس باشد تا این سرویس از همه جا در دسترس باشد؛ یا میتوانید ارائه کنندهها را به همراه کامپوننت ها یا ماژولهای مشخصی ثبت کنید. مکان ثبت این ارائه کنندهها در متادیتای سرویس (در دکوراتور @Injectable()) یا در @NgModule() و یا متادیتای @Component() است.
- به صورت پیش فرض دستور Angular CLI، ng generate service، یک ارائه کننده را به همراه تزریق کنندهی اصلی سرویستان را ثبت میکند. این دستور این کار را با لحاظ کردن متادیتای ارائه کننده در دکوراتور @Injectable() انجام میدهد. در این آموزش برای ثبت ارائه کنندهی تعریف کلاس HeroService از این روش استفاده شده است.
@Injectable({ providedIn: 'root', })
زمانی که شما در سطح ریشه سرویسی را فراهم میکنید، Angular تنها یک نمونهی مشترک از HeroService را ایجاد میکند و آن را در هر کلاسی که به آن نیاز داشته باشد، تزریق میکند. ثبت ارائه کننده در متادیتای @Injectable() نیز Angular را قادر میسازد تا با حذف سرویس از برنامهی کامپایل شده در صورت استفاده نشدن از آن، برنامه را بهینه کند. - زمانی که به کمک NgModule مشخصی ارائه کنندهای را ثبت میکنید، نمونهی یکسانی از یک سرویس در اختیار تمامی کامپوننت های موجود در این NgModule قرار میگیرد. برای ثبت این ارائه کننده در این سطح از ویژگی providers مربوط به دکوراتور @NgModule() استفاده کنید.
@NgModule({ providers: [ BackendService, Logger ], ... }) - • زمانی که ارائه کنندهای را در سطح کامپوننت ثبت کنید، نمونهی جدیدی از این سرویس را به همراه هر یک از نمونههای جدید این کامپوننت دریافت میکنید. در این سطح ارائه کنندهی سرویس را در ویژگی providers مربوط به متادیتای @Component() ثبت کنید.
src/app/hero-list.component.ts (component providers) @Component({ selector: 'app-hero-list', templateUrl: './hero-list.component.html', providers: [HeroService] })
برای دریافت اطلاعات بیشتر به بخش «تزریق وابستگی» مراجعه کنید.