<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های MohammadReza jamali</title><link>https://virgool.ir/feed/@mohammadrezajamaali.s</link><description></description><language>fa</language><pubDate>2026-11-11 09:17:25</pubDate><image><url>https://files.virgool.ir/upload/users/203898/avatar/avatar.png</url><title>MohammadReza jamali</title><link>https://virgool.ir/@mohammadrezajamaali.s</link></image><item><title>دسته بندی اشیا با AI + Flutter</title><link>https://virgool.ir/@mohammadrezajamaali.s/دسته-بندی-اشیا-با-ai-flutter-uaiino8imlus</link><description>مثال های زیادی برای استفاده از AI در اپلیکیشن های فلاتری موجود هست برای مثال استفاده از کتابخانه google_mlkit_image_labeling, google_mlkit که برای شرکت گوگل هست و می توان از طریق آن کلاس بندی و یا تشخیص اجسام و یا برنامه هایی برای تولید محتوا با AI انجام دادولی قصد من از نوشتن این مقاله ایجاد برنامه ای برای کلاس بندی تصاویر برای هدفی مشخص توسط مدلی شخصی سازی شده یا ایجاد شده توسط خود شما می باشد برای مثال مدلی که در این برنامه از آن استفاده کرده ام مدلی برای تشخیص آتش سوزی می باشد. قصد من تولید یک Custom SLM(small language model) که با استفاده از ابزار ایجاد مدل گوگل است.به کد های پروژه و ریپازیتوری می توانید از طریق حساب گیت هابم دسترسی پیدا کنیدبرای ایجاد مدل نیاز هست تصاویر مختلفی از آتش و دود و حالت نرمال را جمع آوری کنیم و برای این منظور من از یک پروژه ایجاد شده بر روی گیتهاب استفاده کردم و با استفاده از ابزار یادگیری ماشین گوگل مدلمان را ایجاد می کنیم طبق تصویر زیر کلاسها را ایجاد کرده و تصاویر کلاسها را آپلود می کنیم.فایل پروژه مدل موجود در ریپازیتوری گیتهاب ٰproject.tm ٰ قرار داردبعد از اپلود تصاویر روی Train Model کلیک کرده و مدلمان را ایجاد می کنیم سپس بر روی Export Model کلیک کرده و خروجی مدلمان را بر پایه Floating point می گیریم در این قسمت دقت کنید که ما برای تفکیک اجزا نیاز به دانلود مدل بر پایه Tensorflow Lite داریم طبق تصویر زیر:حالا که مدلمان را ایجاد کرده ایم پروژه فلاترمان را ایجاد می کنیم و کتابخانه های camera , tflite_v2 را به فایل pubspec.yaml اضافه میکنیم و فایل مدل و لیبل دانلود شده را به فولدر assets پروژه اضافه کرده و مسیر آن را در فایل  popspec.yaml تنظیم می کنیم و سپس در فایل main.dart کدهای زیر را برای استفاده از مدل اضافه می کنیم.و بعد از این مرحله پروژه ما حاضر است و می توانیم آن را روی تلفنمان اجرا کرده و با تصاویر مختلف آتش سوزی دود و تصاویر طبیعی تست کنیم.امیدوارم که مقاله موجود مفید واقع شود و اگر از دوستان کسی نسبت به تکمیل آن در قسمت Object detection اقدام کند باعث خوشحالی بنده خواهد شد و مشتاق اشتراک گذاری این تجربه خواهم بود.</description><category>MohammadReza jamali</category><author>MohammadReza jamali</author><pubDate>Sat, 31 Aug 2024 20:57:17 +0330</pubDate></item><item><title>کدنویسی دیفنسیو(Defensive Codding)</title><link>https://virgool.ir/Rocket/کدنویسی-دیفنسیوdefensive-codding-s8awye9yg8ql</link><description>در ابتدا با این قانون مورفی شروع کنیم :If it can happen, it will happenاگر ممکن است اتفاق بیافتد پس اتفاق خواهد افتاد.همه ما می دانیم که یک کد را به هزار شکل مختلف می توان نوشت که کار کند. اگر در رابطه با آن کمی فکر کنیم اولین چیزی که به ذهنمان می آید این است که بعضی از این روش ها نگهداری راحت تری نسبت به بقیه دارند.بعضی از آنها انعطاف بیشتری نسبت به بقیه دارند.چرا کد نویسی تدافعی؟کد دیفنسیو کدی هست که اگر خطایی به صورت ناخواسته رخ دهد کد ما می تواند هنوز به شکل صحیح به اجرای خود ادامه دهدو این شکل کد نویسی به شما در شناسایی بسیاری از خطاها در زمان کامپایل کمک خواهد کرد.کد نویسی تدافعی مجموعه ای از تکنیک هاست که رفتار کد شما را در مقابله با خطاهای زمان اجرا کنترل خواهد کرد و کد شما را در مقابل این خطا ها منعطف تر خواهد نمود و باعث تداوم اجرای صحیح آن در مقابله با خطاهای ناخواسته خواهد بود. این تکنیک از رانندگی تدافعی الهام گرفته شده است اگر کمی فکر کنید شما هرگز از اینکه در ذهن راننده مقابل شما چه می گذرد اطمینان ندارد و نمی دانید سایر راننده ها قرار هست چه کاری انجام دهند پس شما نهایت دقت را می کنید تا اگر راننده دیگر کار خطرناکی انجام دهد آسیبی به شما وارد نشود. در برنامه نویسی تدافعی هم ایده اصلی این است که اگر داده غیر مناسبی وارد کد شما شود آسیبی به کد شما نرساند حتی اگر باعث خرابی کد های دیگر شود.مزایای کدنویسی دیفنسیو:- خوانایی بالاتر و بهتر کد- افزایش کیفیت کد- نگهداری و توسعه راحت ترنکات مهم در این تکنیک که باید به آنها اهمیت دهیم:به هیچ عنوان به دیتای وارد شده توسط کاربر اعتماد نکنید:اگر بخواهیم با یک مثال این مورد را بررسی کنیم فرض کنید شما یک وبسایت مارکت آنلاین طراحی نموده اید و می خواهید محصولاتی را از طریق آن بفروشید. فرض کنید از محصول ایکس تنها 3 عدد با قیمانده و شما برای کاربر حداکثر تعداد قابل سفارش را 3 نمایش می دهید . در این حالت کابر با یک دستکاری ساده می تواند لاجیک شما را دور زده و عددی بیشتر از 3 برای شما بفرستد و شما در سمت سرور مجبور به کنترل این حالت هستید به عبارت ساده تر اینکه شما بگویید من این کنترل را در سمت کاربر انجام داده ام و چه احتیاجی به کنترل سمت سرور هست شرایط را برای یک خطا به راحتی فراهم می کند و یک تصمیم اشتباه است.به توسعه دهنده ها اعتماد نکنید:توسعه دهنده ها به سبب طرز فکر توسعه دهندگیشان در زمان توسعه نرم افزار به راحتی خطا نخواهند کرد و این می تواند باعث ایجاد خطا در آینده شود جمله کمی گیج کننده به نظر می رسد بهتر است با یک مثال به ساده کردن آن بپردازیم فرض کنید شما در لایه سرویس یک متد ایجاد کرده اید و سپس در لایه کنترلر از آین متد استفاده کرده اید و کنترل های مربوز به لاجیک(Logic) را در کنترلر انجام داده اید تا اینجا همه چیز رو به راه است ولی مشکل زمانی رخ خواهد داد که یک برنامه نویس دیگر قرار باشد از متدی که شما در لایه سرویس نوشته اید استفاده کند او ممکن است به قوانین و لاجیکی که شما نوشته بودید دقت نکند و این باعث فاجعه خواهد شد پس شما نیاز است برای متد هایی که می نویسید لاجیک مربوط به کد نوشته شده را در لایه های مختلف و مناسب کنترل نمایید تا از رخ دادن خطا جلوگیری کنید شاید در بعضی مواقع نیاز باشد پارانوئیک به قضیه نگاه کنیم. ?سعی کنید همیشه به استاندارد سالید(SOLID) پایبند باشیداصول برنامه نویسی باعث افزایش کارایی و کاهش پیچیدگی کد ما خواهند بود کد ما را خوانا تر و قابل توسعه تر خواهند کرد. زمانی که با اصول سالید به توسعه نرم افزار بپردازید در اکثر مواقع شما خواسته و یا ناخواسته از خطاها جلوگیری خواهید نمود.تست بنویسیدکد را با کد تست کردن همیشه یکی از بهترین روش هاست.زمانی که توسعه دهنده در حال تست نویسی است برای ایجاد خطا در کد تمام احتمالات را در نظر خواهد گرفت و این کار باعث کارکرد صحیح کد خواهد شد</description><category>MohammadReza jamali</category><author>MohammadReza jamali</author><pubDate>Sat, 13 Aug 2022 20:38:00 +0430</pubDate></item><item><title>DependencyInjection/DI/IOC</title><link>https://virgool.ir/@mohammadrezajamaali.s/dependencyinjectiondiioc-isnxpgf9qlde</link><description>تزریق وابستگی(Dependency Injection) وارونگی وابستگی (Dependency Inversion) وارونگی کنترل(Inversion Of Control)در این مقاله تصمیم داریم در رابطه با این سه اصطلاح که در ارتباط با هم هستند، صحبت کنیم و ابتدا مفهوم هر کدام را بررسی خواهیم کرد.تزریق وابستگی(Dependency Injection) در رابطه با تزریق وابستگی یا دپندنسی اینجکشن این اصطلاح یک دیزاین پترن نرم افزار است که در رابطه با ساخت و ایجاد آبجکت ها مطرح می شود و هدف از آن ایجاد و ساخت وابستگی ها در خارج از کلاس استفاده کننده و دریافت آن از روش های متداول تزریق وابستگی است همه ما می دانیم که تعریف و ایجاد وابستگی ها در داخل کلاس استفاده کننده وابستگی، یعنی یک ارتباط سفت و سخت که در آینده نه چندان دور ما را در توسعه و تغییر نرم افزار به دردسر خواهد انداخت و همیشه به دنبال راهی برای سست کردن چنین وابستگی هایی هستیم و دپندنسی اینجکشن با خارج کردن وابستگی ها از کلاسهای ما این مشکل را برای ما مرتفع می کندروشهای تزریق وابستگی متداول عبارتند از :تزریق از طریق سازنده کلاس(Cunstructor Injection)تزریق از طریق اینترفیس ها(Interface Injection): وابستگی از طریق آرگومان تابع داخل کلاس به کلاس تزریق می شود.تزریق از طریق متد ست کننده(Setter Injection): وابستگی از طریق پراپرتی های پابلیک به کلاس تزریق می شود.هدف از دپندنسی اینجکشن قابلیت استفاده مجدد (Reusability) و قابلیت تست راحت تر است.وارونگی کنترل(Inversion of Control)وارونگی کنترل یکی از اصول برنامه نویسی است که جریان کنترل را در نرم افزار معکوس می کند.در برنامه نویسی پروسیجرال جریان اجرای دستورات در دست متد اصلی (Main Method) قرار دارد. ایجاد وابستگی ها، فراخوانی متد ها و حتی دریافت ورودی از کاربران که از طریق متد اصلی اتفاق می افتد و پس از اجرای دستورات از طریق همین متد به پایان می رسد.با وارونگی کنترل (IOC) این فریم ورک است که کنترل روال ایجاد وابستگی ها، فراخوانی متد ها، دریافت ورودی کاربران و اجرا و اتمام برنامه را در دست دارد و این مسئولیت را از تابع اصلی یا اپلیکیشن حذف می کند.با استفاده از وارونگی کنترل، وظیفه ایجاد وابستگی ها در شروع برنامه از طریق متد اصلی حذف شده و با استفاده از تنظیمات از پیش تعیین شده این ایجاد وابستگی در زمان نیاز به این وابستگی از طریق فریم ورک ایجاد خواهد شد.وارونگی وابستگی(Dependency Inversion)اصل وارونگی وابستگی در سال 1994 در مقاله معیار های کیفیت طراحی شی گرا (OO Design Quality Metrics) توسط روبرت مارتین (آنکل باب) مطرح شد سپس در سال 2002 در کتاب اصول، الگو ها و شیوه های توسعه نرم افزار چابک  (Agile Software Development Principles, Patterns and Practices) تعریف شد.مضمون تعریف دو نکته زیر است:-ماژول های سطح بالا(High Level Modules) نباید به ماژول های سطح پایین(Low Level Modules) وابسته باشند بلکه هر دوی این ماژول ها باید به انتزاعات(Abstraction) وابسته باشند.- انتزاعات نباید به جزئیات وابسته باشند بلکه این جزئیات هستند که به انتزاعات وابسته اند.در رابطه با نکته اول ماژول سطح بالا همان کلاسی است که به یک سرویس وابسته است پس کلاس، یک کلاینت برای سرویس و یک خدمت گیرنده از آن است.حال بدون در نظر گرفتن نکته فوق اگر کلاس ما به صورت مستقیم به این سرویس وابسته باشد با کوچکترین تغییر در سرویس، کلاس ما به همراه تست های نوشته شده برای آن نیاز به تغییر خواهد داشت حال اگر این وابستگی را معکوس کنیم و نکته فوق را به کار بگیریم کلاس ما به یک اینترفیس وابستگی خواهد داشت و ماژول سطح پایین یا سرویس ما ملزم به پیاده سازی جزئیات این اینترفیس خواهد بود پس تا زمانی که بتواند اینترفیس موجود را پیاده سازی کند بدون هیچ نقصی به سرویس گیرنده خود خدمت خواهد کرد و تغییر آن هیچ تاثیری بر ماژول سطح بالا یا کلاس سرویس گیرنده نخواهد گذاشت.در نظر داشته باشید وارونگی وابستگی نه تنها در وارونگی جهت وابستگی بلکه در وارونگی مالکیت انتزاع نیز هست.در تصویر زیر اصل وارونگی وابستگی نغض شده است و علت آن وابستگی ماژول های سطح بالا به ماژول های سطح پایین است.بیاید با معکوس کردن وابستگی مشکل موجود را رفع کنیم.پس از رفع مشکل موجود دستاوردی که از این انتزاع به دست می آوریم را بررسی کنیمسرویس گیرنده هیچ اطلاعی از کسی که به آن خدمت می کند ندارداین سرویس گیرنده یا ماژول سطح بالاست که رفتار سرویس دهنده را تعیین خواهد کرد.سرویس گیرنده به راحتی میتواند در جاهای مختلف مجددا به کار گرفته شودوابستگی همیشه قابلیت این را خواهد داشت که با پیاده سازی دیگری به راحتی جایگزین شود که همان قرارداد را بتواند تامین کند.بیاید با یک مثال به بررسی این سه اصطلاح بپردازیمدر پروژه نمونه که کدهای مربوط به آن را می توانید از صفحه گیتهابم دریافت کنید سه نوع از وابستگی را بررسی می کنیم در پروژه اول هیچ یک از موارد بالا رعایت نشده و وابستگی های سفت و سخت بین کلاسهای پروژه قابل مشاهده است در پروژه دوم فقط وارونگی جریان کنترل به همراه تزریق وابستگی انجام شده است و در پروژه سوم تمامی موارد ذکر شده در بالا پیاده سازی شده است.پروژه دارای یک دیتابیس لوکال اس کیو لایت با او آر ام (object-relational mapper) انتیتی فریمورک هست که شامل یک جدول ساده از اطلاعات کارمندان استمن بخش هایی از پروژه سوم را به عنوان نمونه در این مقاله قرار می دهم برای دسترسی به کد کامل پروژه ها می توانید به ریپازیتوری این پروژه در گیتهاب مراجعه کنید در سطح اینفرا استراکچر  دیتابیس اس کیو لایت برای سبکی با او آر ام انتیتی فریمورک به کار برده شده و یک جدول ساده از اطلاعات کارمندان در آن تعریف شده استpublic class EmployeeContext : DbContext    {        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)        {            optionsBuilder.UseSqlite(@&#34;Data Source=D:\Dependency\Dependency.sqlite&#34;);        }        protected override void OnModelCreating(ModelBuilder modelBuilder)        {            modelBuilder.Entity&lt;Employee&gt;().HasKey(x =&gt; x.Id);            modelBuilder.Entity&lt;Employee&gt;().Property(x =&gt; x.Id).ValueGeneratedOnAdd();        }        public DbSet&lt;Employee&gt; Employees { set; get; }    }در این سطح کلاس EfEmployeeDal در بر گیرنده متد های مربوط به دیتابیس از طریق انتیتی فریمورک است که از اینترفیس IEmployeeDal ارث بری کرده است. public class EfEmployeeDal:IEmployeeDal    {        private readonly EmployeeContext _context;        public EfEmployeeDal(EmployeeContext context)        {            _context = context;        }        public async Task Add(Employee employee)        {            await _context.Employees.AddAsync(employee);            await _context.SaveChangesAsync();        }        public async Task&lt;List&lt;Employee&gt;&gt; GetList(Expression&lt;Func&lt;Employee, bool&gt;&gt; filter = null)        {            return filter == null                ? await _context.Set&lt;Employee&gt;().ToListAsync()                : await _context.Set&lt;Employee&gt;().Where(filter).ToListAsync();        }    }اینترفیس IEmployeeDal شامل قرارداد های مورد نیاز برای سطح بالاتر هست .public interface IEmployeeDal    {        Task Add(Employee employee);        Task&lt;List&lt;Employee&gt;&gt; GetList(Expression&lt;Func&lt;Employee, bool&gt;&gt; filter = null);&#xA;    }کلاس EmployeeManager شامل متد های سطح اپلیکیشن که منطق برنامه در آن قرار دارد هست و درخواست های کاربر را بر اساس منطق برنامه با استفاده از دسترسی با اینترفیس IEmployeeDal تامین کرده و در اختیار کاربر قرار می دهد public class EmployeeManager:IEmployeeService    {        private readonly IEmployeeDal _employeeDal;        public EmployeeManager(IEmployeeDal employeeDal)        {            _employeeDal = employeeDal;        }        public async Task&lt;List&lt;Employee&gt;&gt; GetEmployees()        {            return await _employeeDal.GetList();        }        public async Task AddEmployee(AddEmployeeDto dto)        {            await _employeeDal.Add(new Employee            {                FirstName = dto.FirstName,                LastName = dto.LastName,                InsertedDateTime = DateTime.UtcNow            });        }    }این کلاس اینترفیس IEmployeeService را ارث بری می کند  public interface IEmployeeService    {        Task&lt;List&lt;Employee&gt;&gt; GetEmployees();        Task AddEmployee(AddEmployeeDto dto);    } و  کنترلر که درخواست های کاربر را دریافت می کند و از طریق اینترفیس IEmployeeService  تامین نموده و در اختیار کاربر قرار می دهدpublic class EmployeesController : ControllerBase    {        private readonly IEmployeeService _employeeService;        public EmployeesController(IEmployeeService employeeService)        {            _employeeService = employeeService;        }        [HttpGet(template: &#34;getlist&#34;)]        public async Task&lt;IActionResult&gt; GetList()        {            return Ok(await _employeeService.GetEmployees());        }        [HttpPost(template: &#34;addemployee&#34;)]        public async Task&lt;IActionResult&gt; AddEmployee(AddEmployeeDto dto)        {            await _employeeService.AddEmployee(dto);            return Ok();        }    }در رابطه با لایه وارونگی جریان کنترل هم کدهای موجود در کلاس IocTool که در آن یک اکستنشن متد برای سرویس کالکشن وجود دارد، قرار داده شدهpublic static class IocTool    {        public static void RegisterServices(this IServiceCollection services)        {            services.AddDbContext&lt;EmployeeContext&gt;();            services.AddScoped&lt;IEmployeeDal, EfEmployeeDal&gt;();            services.AddScoped&lt;IEmployeeService, EmployeeManager&gt;();        }    }و نحوه استفاده از وارونگی کنترل در کلاس پروگرم تعریف شده استusing DiWithIocAndInjectionDependency.Core;&#xA;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();builder.Services.RegisterServices();var app = builder.Build();&#xA;// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){    app.UseSwagger();    app.UseSwaggerUI();}app.UseAuthorization();app.MapControllers();app.Run(); امیدوارم توضیحاتم در رابطه با این سه اصطلاح پر کاربرد مفید واقع شود .</description><category>MohammadReza jamali</category><author>MohammadReza jamali</author><pubDate>Sun, 31 Jul 2022 03:04:09 +0430</pubDate></item><item><title>چرا مدیتور(Meditor)؟</title><link>https://virgool.ir/@mohammadrezajamaali.s/چرا-مدیتورmeditor-zs2tvbitjsnu</link><description>پترن مدیتور چیست و کاربرد آن در چه مواردی است؟پترن مدیتور جزء پترن های رفتاری (Behavioral Design Pattern) می باشد پترن های رفتاری برای ارتباط بین اجزا و هر چه منعطف بودن این ارتباط و ایجاد یک وابستگی سست بین اجزا به کار می روند و در رابطه با پترن مدیتور همانطور که از معنی لغوی آن مشخص است به عنوان یک واسط برای ارتباط بین اجزا استفاده می شود و هدفی که دنبال می کند مثل سایر پترن های رفتاری کم کردن وابستگی و پیچیدگی می باشد و ارتباط بین اجزا نه از چند جا بلکه از یک نقطه فراهم می شود و به جای ارتباط سخت بین اجزا ارتباط غیر مستقیم از طریق واسط را برای ما فراهم می کند.تصویر زیر حالتی است که ما از مدیتور استفاده نمی کنیم و زنجیر وابستگی را ایجاد می کنیمو تصویر دوم مربوط به حالتی است که از مدیتور استفاده کرده باشیمدر رابطه با موارد استفاده از مدیتور:در کل پترن مدیتور برای شرایطی کاربرد دارد که ما وابسطگی ها ی زیادی بین کلاس هایمان داریم و به اصطلاح ماکارونی(spaghetti code) درست کرده ایمپس زمانی ما از مدیتور استفاده می کنیم که :-می خواهیم به تعداد زیادی وابستگی بین کلاس ها دسترسی داشته باشیم.-زمانی که می خواهیم کلاس هایمان را اینکپسوله(encapsulate) کنیم و آنها از یکدیگر اطلاعی نداشته باشند و وابستگی های خود را از طریق مدیتور دریافت کنند.-زمانی که بخواهیم یک اینترفیس داشته باشیم که همه کلاس های ما با آن آرتباط داشته باشند.اکنون سوالی که پیش می آید این هست که چه نیازی به این پترن هست؟در چه شرایطی به این پترن نیاز داریم؟فرض کنید چند کلاس را داریم که به صورت سفت و سخت از هم استفاده می کنند و به هم وابسطه هستند اگر یک نگاه کلی به آنها بیاندازیم می بینیم که ما یک زنجیر از وابسطگی را داریم که از جنس وابستگی سخت(tightly-coupled) هستند. حالا ممکن است بپرسید خب ایراد این کار چیست؟چیزی که واضح است، این موضوع هست که ساختاری با این شکل در آینده نه چندان دور مشکلات فراوانی را برای توسعه دهنده و نرم افزار ایجاد خواهد کردد و این مشکلات عبارتند از:-در طول زمان تعداد کلاس ها و آبجک های ما بیشتر خواهند شد و این زنجیر همواره طولانی و طولانی تر خواهد شد و به کاهش انعطاف سیستم منجر خواهد شد.-مدیریت این ارتباط ها به تدریج سخت تر می شود.-هزینه نگهداری و زمان رفع مشکلات در آن آفزایش خواهد یافت.-تغییراتی که برای بهبود نرم افزار برنامه ریزی شده باعث بالا رفتن ریسک خرابی نرم افزار خواهد شد.طبیعتا چنین ساختار و چنین مشغله ای باب میل هیچ کدام از ما نیست.پترن مدیتور برای این مشکل راهکاری ارائه می دهد و ببینیم راهکار مدیتور برای این مشکل چیست؟پترن مدیتور به عنوان راهکار در مرکز ارتباط یک واسط را قرار می دهد و تمام ارتباط از طریق این واسط تحقق خواهد یافت به این صورت ارتباط سخت بین اجزا و کلاس ها به یک ارتباط سست (loosely-coupled) تبدیل خواهد شد . هیچ کلاسی برای ارتباط با کلاس دیگر نیازی به نگهداری رفرنس آن کلاس در بدنه خود ندارد و هیچ ارتباط مستقیمی وجود ندارد و ارتباط از طریق واسط انجام می شود.یکی از مهمترین اهداف معماران نرم افزار این هست که اجزای سیستم در ارتباط  سفت و سخت نباشند و در زمان لزوم بتوان به راحتی اجزا را با کمترین هزینه تغییر داد و یک سیستم کاملا منعطف را ایجاد کرد. از این رو مدیتور ارتباط سفت و سخت بین اجزای سیستم را از بین برده و هدف ذکر شده را به ارمغان می آورد.هدف پایه از این پترن به جای وابستگی سفت و سخت بین اجزا ،وابسطگی به یک واسط و ارتباط از طریق آن است.مزایای استفاده از مدیتور چیست؟خلاصه مطالب بالا، میدتور برای ایزوله کردن اجزا از هم دیگر به کار می رود و وابستگی بین اجزا و هزینه نگهداری سیستم را کاهش می دهد.-وابستگی بین کلاس ها را کاهش می دهد.-اصل تک وظیفگی را برای ما ایجاد می کند برای مثال کنترلر های شما نیازی به داشتن اطلاعات از سرویس های لایه پایین تر ندارند و کدی به مراتب تمیز تر در کنترلر های شما وجود دارد و کنترلر ها بر وظیفه اصلی خود متمرکز خواهند بود.-اصل اوپن/کلوز(Open/Close) را برای ما ایجاد می کند به این صورت که لزوما تغییراتی که در لایه پایین تر اتفاق می افتد باعث ایجاد تغییرات در لایه بالاتر نخواهد شد .معایب مدیتوردر صورت عدم دقت ممکن است مدیتور تا سطح یک ابر کلاس (god class) پیشرفت کند و به جزئی جدایی ناپذیر از سیستم تبدیل شود.طبیعتا ارتباط از طریق واسط به نسبت با ارتباط یک به یک از نظر پرفرمنس در برخی موارد ممکن است کمی پرفمنس پایین تری داشته باشد.مثال اول - ایجاد نرم افزار چت با استفاده از پترن مدیتور:فرض کنید تصمیم داریم یک اتاق صحبت مثل چیزی که در یاهو مسنجر در سالهای قبل شاهدش بودیم بسازیم. برای ارتباط شخصی با دیگر اشخاص ابتدا شخص وارد اتاق می شد و با اشخاص موجود در کلاس به صحبت می پرداخت. مشکلی که در اینجا وجود دارد این هست که هر کاربر اگر با سایر کاربران به صورت چند به چند(many-to-many) ارتباط برقرار کند پیچیدگی حاصل به شکل نمایی افزایش خواهد یافت . به همین علت اگر هر کاربر متن دلخواه خود را به یک نقطه ارسال می کند و پیام جدید را از آن نقطه دریافت کند، این باعث سادگی و مدیریت راحت تر سیستم می شود بیایید با مدیتور این مشکل را حل کنیم.هدف ما این است که کاربران به جای چت مستقیم با یکدیگر پیام را به اتاق ارسال و پیام های رسیده را از آنجا دریافت کنند . به این شکل دسترسی مستقیم هر کاربر به سایرین از میان برداشته شده و فقط کافیست پیام خود را به اتاق تحویل دهند.سیستممان به شکل زیر است:کلاس پارتیسیپنت (Participant) اطلاعات کاربران را نگهداری می کندکلاس چت روم (ChatRoom) مدیریت اتاق چت را بر عهده دارد.public class Participant    {        public ChatRoom ChatRoom { get; set; }        public string Name { get; }        public Participant(string name)        {            Name = name;        }        public void Send(string receiver, string message)        {            ChatRoom.Send(Name, receiver, message);        }        public void Receive(string sender, string message)        {            Console.WriteLine($&#34;{sender} to {Name}: &#39;{message}&#39;&#34;);        }    }متد سند(Send) برای ارسال و متد رسیو(Receive) برای دریافت پیام استفاده می شود .ابتدا اینترفیس کلاسمان را پیاده سازی می کنیمpublic interface IChatRoom    {        public void Register(Participant participant);        public void Send(string sender, string receiver, string message);    }و بعد کلاس چت روم که از این اینترفیس ارث بری می کند:public class ChatRoom : IChatRoom    {        private Dictionary&lt;string, Participant&gt; _participants = new Dictionary&lt;string, Participant&gt;();        public void Register(Participant participant)        {            if (!_participants.ContainsValue(participant))            {                _participants[participant.Name] = participant;            }            participant.ChatRoom = this;        }        public void Send(string sender, string receiver, string message)        {            Participant participant = _participants[receiver];            if (participant != null)            {                participant.Receive(sender, message);            }        }    }کلاس چت روم (ChatRoom) لیستی از پارتیسپنت ها را داخل خود نگهداری میکند و برای این کار برای هر کاربر وارد شده متد رجیستر(Register) فراخوانی می شود و اگر پیامی برای ارسال موجود باشد متد سند(Send) فراخوانی شده و پارتیسیپنت مربوطه از لیست واکشی شده و متد رسیو(Receive) پارتیسیپنت(Participant) فراخوانی شده و به کاربر اطلاع رسانی می شود.اکنون تست نرم افزارمان را انجام دهیم.ChatRoom chatroom = new ChatRoom();Participant mohammad = new Participant(&#34;Mohammad&#34;);Participant sara = new Participant(&#34;Sara&#34;);Participant ali = new Participant(&#34;Ali&#34;);chatroom.Register(mohammad);chatroom.Register(sara);chatroom.Register(ali);mohammad.Send(&#34;Sara&#34;, &#34;Hi, How are you?&#34;);sara.Send(&#34;Mohammad&#34;, &#34;Hi,I&#39;m great.What about you?&#34;);ali.Send(&#34;Sara&#34;, &#34;Did you compelete your work yesterday?&#34;);sara.Send(&#34;Ali&#34;, &#34;Of course.&#34;);کد های مثال فوق را می توانید از صفحه گیتهاب من دریافت کنید.این مثال ساده ای از نحوه کار مدیتور بود در دات نت کتابخانه مدیت آر (MediatR) پیاده سازی پترن مدیتور را برای ما به ساده کرده است. بیایید با کتابخانه مدیت آر (MediatR) یک پروژه سمپل را پیاده سازی کنیم . در این پروژه تصمیم داریم یک وب ای پی آی (WebApi) را پیاده سازی کنیم و چند عملیات ساده ریاضی را با آن انجام دهیم.ابتدا یک کنترلر وب ای پی آی (WebApi) ایجاد کرده و سپس کتابخانه مدیت آر(MediatR) را از ناگت بر روی پروژه سوار می کنیم بعد از آن کلاس عمل ضرب را در آن پیاده سازی می کنیم    public class MultiplyRequest:IRequest&lt;int&gt;    {        public int FirstNumber { get; set; }        public int SecondNumber { get; set; }    }کلاس ما از اینترفیس آی ریکوئست (IRequest) مدیت آر (MediatR) ارث بری میکند و مقداری که بر خواهد گرداند یک مقدار عدد صحیح است . خب بیاید کلاس هندلر رکوئستمان را پیاده سازی کنیم .کلاس هندلر رکوئست درخواست شده را دریافت کرده و عملیات مربوط به آن را انجام داده و نتیجه را به درخواست کننده بر می گرداند .    public class MultiplyRequestHandler : IRequestHandler&lt;MultiplyRequest, int&gt;    {        public async Task&lt;int&gt; Handle(MultiplyRequest request, CancellationToken cancellationToken)        {            return request.FirstNumber * request.SecondNumber;        }    }بعد از اتمام کد های کلاس هندلر اینک به پیاده سازی بدنه کنترلرمان می پردازیم ابتدا داخل کنترلر مدیتور را از طریق دپندنسی اینجکشن(Dependency Injection) دریافت کرده و اکشن های لازم را با استفاده از مدیتور پیاده سازی می کنیم[Route(&#34;api/[controller]&#34;)]    [ApiController]    public class CalculatorsController : ControllerBase    {        private readonly IMediator _mediator;        public CalculatorsController(IMediator mediator) =&gt; _mediator = mediator;        [HttpGet(template:&#34;multiply&#34;)]        public async Task&lt;ActionResult&gt; Multiply(int firstNumber, int secondNumber)        {            return Ok(await _mediator.Send(new MultiplyRequest() { FirstNumber = firstNumber, SecondNumber = secondNumber }));        }        [HttpGet(template: &#34;divide&#34;)]        public async Task&lt;ActionResult&gt; Divide(int firstNumber, int secondNumber)        {            return Ok(await _mediator.Send(new DevideRequest() { FirstNumber = firstNumber, SecondNumber = secondNumber }));        }    }کد های این مثال را نیز می توانید از صفحه گیتهاب من دریافت کنید.همانطور که مشخص است شما بدون وابستگی سفت و سخت به سرویس های مربوط به عملیات های مختلف، عملیات را با استفاده از مدیتور انجام دادید.قبل از به پایان رساندن مقاله یاد آوری کنم که مدیتور معمولا با پترن سی کیو آر اس (CQRS) استفاده می شود .پترن سی کیو آر اس (CQRS) برای جدا سازی عملیات خواندن و نوشتن در دیتابیس کاربرد داردامیدوارم مطالب نوشته شده مفید واقع شود.</description><category>MohammadReza jamali</category><author>MohammadReza jamali</author><pubDate>Sat, 23 Jul 2022 19:34:04 +0430</pubDate></item></channel></rss>