مطالب
Design Pattern: Factory

الگوهای طراحی، سندها و راه حلهای از پیش تعریف شده و تست شده‌ای برای مسائل و مشکلات روزمره‌ی برنامه نویسی می‌باشند که هر روزه ما را درگیر خودشان می‌کنند. هر چقدر مقیاس پروژه وسیعتر و تعداد کلاسها و اشیاء بزرگتر باشند، درگیری برنامه نویس و چالش برای مرتب سازی و خوانایی برنامه و همچنین بالا بردن کارآیی و امنیت افزون‌تر می‌شود. از همین رو استفاده از ساختارهایی تست شده برای سناریوهای یکسان، امری واجب تلقی می‌شود.

الگوهای طراحی از لحاظ سناریو، به سه گروه عمده تقسیم می‌شوند:

1- تکوینی: هر چقدر تعداد کلاسها در یک پروژه زیاد شود، به مراتب تعداد اشیاء ساخته شده از آن نیز افزوده شده و پیچیدگی و درگیری نیز افزایش می‌یابد. راه حل‌هایی از این دست، تمرکز بر روی مرکزیت دادن به کلاسها با استفاده از رابط‌ها و کپسوله نمودن (پنهان سازی) اشیاء دارد. 

2- ساختاری: گاهی در پروژه‌ها پیش می‌آید که می‌خواهیم ارتباط بین دو کلاس را تغییر دهیم. از این رو امکان از هم پاشی اجزایِ دیگر پروژه پیش می‌آید. راه حلهای ساختاری، سعی در حفظ انسجام پروژه در برابر این دست از تغییرات را دارند.

3- رفتاری: گاهی بنا به مصلحت و نیاز مشتری، رفتار یک کلاس می‌بایستی تغییر نماید. مثلا چنانچه کلاسی برای ارائه صورتحساب داریم و در آن میزان مالیات 30% لحاظ شده است، حال این درصد باید به عددی دیگر تغییر کند و یا پایگاه داده به جای مشاهده‌ی تعدادِ معدودی گره از درخت، حال می‌بایست تمام گره‌ها را ارائه نماید.


الگوی فکتوری:

الگوی فکتوری در دستهء اول قرار می‌گیرد. من در اینجا به نمونه‌ای از مشکلاتی که این الگو حل می‌نماید، اشاره می‌کنم:

فرض کنید یک شرکت بزرگ قصد دارد تا جزییات کامل خرید هر مشتری را با زدن دکمه چاپ ارسال نماید. چنین شرکت بزرگی بر اساس سیاستهای داخلی، بر حسب میزان خرید، مشتریان را به چند گروه مشتری معمولی و مشتری ممتاز تقسیم می‌نماید. در نتیجه نمایش جزییات برای آنها با احتساب میزان تخفیف و به عنوان مثال تعداد فیلدهایی که برای آنها در نظر گرفته شده است، تفاوت دارد. بنابراین برای هر نوع مشتری یک کلاس وجود دارد.


یک راه این است که با کلیک روی دکمه‌ی چاپ، نوع مشتری تشخیص داده شود و به ازای نوع مشتری، یک شیء از کلاس مشخص شده برای همان نوع ساخته شود.

 

 

            // Get Customer Type from Customer click on Print Button
            int customerType = 0;

            // Create Object without instantiation
            object obj;


            //Instantiate obj according to customer Type
            if (customerType == 1)
            {
                obj = new Customer1();
            }
            else if (customerType == 2)
            {
                obj = new Customer2();
            }
            // Problem:
            //          1: Scattered New Keywords
            //          2: Client side is aware of Customer Type

 همانگونه که مشاهده می‌نمایید در این سبک کدنویسی غیرحرفه‌ای، مشکلاتی مشهود است که قابل اغماض نیستند. در ابتدا سمت کلاینت دسترسی مستقیم به کلاسها دارد و همانگونه که در شکل بالا قابل مشاهده است کلاینت مستقیما به کلاس وصل است. مشکل دوم عدم پنهان سازی کلاس از دید مشتری است.

راه حل: این مشکل با استفاده از الگوی فکتوری قابل حل است. با استناد به الگوی فکتوری، کلاینت تنها به کلاس فکتوری و یک اینترفیس دسترسی دارد و کلاسهای فکتوری و اینترفیس، حق دسترسی به کلاسهای اصلی برنامه را دارند.

گام نخست: در ابتدا یک class library  به نام Interface ساخته و در آن یک کلاس با نام ICustomer  می سازیم   که متد Report() را معرفی می‌نماید.

  //Interface

namespace Interface
{
    public interface ICustomer
    {
        void Report();
    }
}

گام دوم: یک class library  به نام MainClass  ساخته و با Add Reference کلاس Interface را اضافه نموده، در آن دو کلاس با نام Customer1, Customer2 می‌سازیم و using Interface را Import می‌نماییم. هر دو کلاس از ICustomer  ارث می‌برند و  سپس متد Report() را در هر دو کلاس Implement می‌نماییم.

// Customer1
using System;
using Interface;

namespace MainClass
{
    public class Customer1 : ICustomer
    {
        public void Report()
        {           
            Console.WriteLine("این گزارش مخصوص مشتری نوع اول است");           
        }
    }
}

//Customer2
using System;
using Interface;

namespace MainClass
{
   public class Customer2 : ICustomer
    {
        public void Report()
        {           
            Console.WriteLine("این گزارش مخصوص مشتری نوع دوم است");           
        }
    }
}

گام سوم: یک class library  به نام FactoryClass  ساخته و با Add Reference کلاس Interface, MainClass را اضافه نموده، در آن یک کلاس با نام clsFactory  می سازیم و using Interface, using MainClass را Import می‌نماییم. پس از آن یک متد با نام getCustomerType ساخته که ورودی آن نوع مشتری از نوع int است و خروجی آن از نوع Interface-ICustomer و بر اساس کد نوع مشتری object را از کلاس Customer1 و یا Customer2 می‌سازیم و آن را return می نماییم.

//Factory
using System;
using Interface;
using MainClass;

namespace FactoryClass
{
    public class clsFactory
    {
        static public ICustomer getCustomerType(int intCustomerType)
        {
            ICustomer objCust;
            if (intCustomerType == 1)
            {
                objCust = new Customer1();
            }
            else if (intCustomerType == 2)
            {
                objCust = new Customer2();
            }
            else
            {
                return null;
            }
            return objCust;
        }
    }
}

گام چهارم (آخر): در قسمت UI   Client، کد نوع مشتری را از کاربر دریافت کرده و با Add Reference کلاس Interface, FactoryClass را اضافه نموده (دقت نمایید هیچ دسترسی به کلاس‌های اصلی وجود ندارد)، و using Interface,  using FactoryClass را Import می‌نماییم. از clsFactory تابع  getCustomerType را فراخوانی نموده (به آن کد نوع مشتری را پاس می‌دهیم) و خروجی آن را که از نوع اینترفیس است به یک object از نوع ICustomer  نسبت می‌دهیم. سپس از این object  متد Report را فراخوانی می‌نماییم. همانطور که از شکل و کدها مشخص است، هیچ رابطه ای بین UI(Client) و کلاسهای اصلی برقرار نیست.

//UI (Client)
using System;
using FactoryClass;
using Interface;

namespace DesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            int intCustomerType = 0;
            ICustomer objCust;
            Console.WriteLine("نوع مشتری را وارد نمایید");           
            intCustomerType = Convert.ToInt16(Console.ReadLine());
            objCust = clsFactory.getCustomerType(intCustomerType);
            objCust.Report();
            Console.ReadLine();
        }
    }
}

نظرات اشتراک‌ها
چرا EF انتخاب خوبی برای پروژه های Domain-Driven نیست؟

زمانیکه متدهای Add و Remove به داخل entityها منتقل می‌شن، الگویی حاصل میشه به نام Active record. این الگو در اصل یک ضد الگو هست به این دلایل:

- متدهای CRUD به اینترفیس عمومی موجودیت‌ها منتقل شدن.

- تست پذیری این نوع اشیاء پایین هست.

- SRP را نقض می‌کنند.

اطلاعات بیشتر

اشتراک‌ها
بهینه سازی فونت های فارسی برای وب با بیفون

همانطور که میدانید بسیاری از فونت‌های فارسی برای وب اصلاح نشده اند و در سیستمهایی با تفکیک پذیری بالا دچاره شکستگی می‌شوند. برای همین برای فونت‌های انگلیسی از کتابخانه جاوااسکریپتی کافون استفاده میشه که فونت‌ها به صورت وکتور  در یک فایل js معرفی می‌شوند و با استفاده از svg یا canvas نمایش می‌دهد، بیفون همانند کافون هست و برای فونت‌های فارسی مناسب است. 

بهینه سازی فونت های فارسی برای وب با بیفون
اشتراک‌ها
دریافت کتاب Pro ASP.NET MVC 5
فریم ورک ASP.NET MVC 5، آخرین تحول پلتفرم وب Microsoft’s ASP.NET است. این فریم ورک، یک مدل برنامه نویسی  با بهره بری بالا  ارائه می‌دهد از جمله: معماری کد تمیز تر، توسعه مبتنی بر تست (Test-Driven Development)،  توسعه پذیری قدرتمند؛ که با تمام مزایای ASP.NET ترکیب شده است، فراهم می‌کند. 
دریافت کتاب Pro ASP.NET MVC 5
نظرات مطالب
Repository ها روی UnitOfWork ایده خوبی نیستند
ممنونم جناب نصیری. دلیل اشاره من به عدم تست پذیری قابل قبول در حالت استفاده مستقیم از Context به خاطر وجود دستوراتی نظیر Entry of T یا موارد مربوط به ChangeTracking است که با تست درون حافظه ای نتیجه مطلوب حاصل نمی‌شود، در نتیجه بهتر است از Effort برای تست لایه دسترسی استفاده شود که عملیات را در قالب یک دیتابیس SqlCE تست می‌کند و نسخه Effort.Ef6  آن نیز از Entity Framework 6 به خوبی پشتیبانی می‌کند.
نظرات مطالب
EF Code First #12
- باید از الگوی Service locator استفاده کنید در این موارد خاص فناوری‌های قدیمی که برای تزریق وابستگی‌ها طراحی نشده‌اند. پیشنیاز این بحث دوره «بررسی مفاهیم معکوس سازی وابستگی‌ها و ابزارهای مرتبط با آن » است.
- ضمن اینکه الان با بودن ASP.NET Web API که هم با وب فرم‌ها سازگار است و هم با MVC، دلیلی برای استفاده از وب متدهای استاتیک عهد عتیق وجود ندارد. ASP.NET Web API طوری طراحی شده تا تزریق وابستگی‌ها در آن ممکن و آزمون پذیری آن بالا باشد.
نظرات مطالب
ExtJs! رویا یا کابوس؟
دوست عزیز، استفاده از ext.net رو به شما توصیه می‌کنم. تا به حال تو 3 پروژه بزرگ و 3 تا پروژه متوسط استفاده کردم که عالیه. سرعت بالا در حجم اطلاعات زیاد و انعطاف پذیری فوق العاده و امکاناتی مثل راست به چپ، تقویم شمسی ... (حتی میتونی تو یه صفحه همزمان تقویم شمسی و میلادی داشته باشی یا اینکه فقط چند تا کامپوننتت راست به چپ باشه و بقیه چپ به راست)
فقط این مخصوص .Net که هم نسخه ASP داره هم MVC
نظرات مطالب
چک لیست تهیه یک برنامه ASP.NET MVC
با سلام جناب نصیری
عموما برای سادگی کار و تفکیک پذیری یک برنامه MVC پروژه به لایه هایی تقسیم بندی می‌شود لطفا در مورد لایه‌های زیر یک توضیح کلی بدهید و اینکه معمولا در این لایه‌ها چه قسمت هایی از پروژه قرار می‌گیرند :
Application.Web
Application.Manager
Application.Repository
Application.DAL
Application.DTO
Application.Core
Application.Common
و اینکه لایه‌های DomainClasses و DataLayer در دل این لایه‌ها قرار می‌گیرند یا بصورت لایه‌های مجزا هستند.
با تشکر
نظرات مطالب
مدیریت سفارشی سطوح دسترسی کاربران در MVC
خوبه ولی برای انعطاف پذیری بیشتر، من و تیمم با استفاده از Reflection، اسامی متدهایی که خروجی ActionResult دارند رو بازیابی می‌کنیم و در سیستم امنیت و پایه برای مدیر امنیت و برنامه نویس نشان میدیم و اونها می‌تونن دسترسی رو بر این مبنا تنظیم کنن. وجود یک Contoller پایه و یک فیلتر برای اون با override کردن متد OnActionExecuting از الزامات کار هست.
نظرات مطالب
آشنایی با NHibernate - قسمت هفتم
سیستم NHibernate از روز اول آن Code first بوده. EF هم در نگارش آخر آن به این نتیجه رسیده که روش Code first انعطاف پذیری بیشتری داره و دقیقا چیزی هست که برنامه نویس‌ها با آن راحت‌تر هستند.
البته برای NH یک سری ابزار تجاری توسط شرکت‌های ثالث درست شده که طراح دارد ولی ... فکر نمی‌کنم با استقبال مواجه شده باشد چون روش Code first یعنی رها شدن از انبوهی کد که توسط ابزارها نوشته می‌شن و عموما هم بهینه نیستند.