۱۳۹۰/۰۷/۲۱

آشنايي با Refactoring - قسمت 8


يكي از اشتباهاتي كه همه‌ي ما كم و بيش به آن دچار هستيم ايجاد كلاس‌هايي هستند كه «زياد مي‌دانند». اصطلاحا به آن‌ها God Classes هم مي‌گويند و براي نمونه، پسوند يا پيشوند Util دارند. اين نوع كلاس‌ها اصل SRP را زير سؤال مي‌برند (Single responsibility principle). براي مثال يك فايل ايجاد مي‌شود و داخل آن از انواع و اقسام متدهاي «كمكي» كار با ديتابيس تا رسم نمودار تا تبديل تاريخ ميلادي به شمسي و ... در طي بيش از 10 هزار سطر قرار مي‌گيرند. يا براي مثال گروه بندي‌هاي خاصي را در اين يك فايل از طريق كامنت‌هاي نوشته شده براي قسمت‌هاي مختلف مي‌توان يافت. Refactoring مرتبط با اين نوع كلاس‌هايي كه «زياد مي‌دانند»، تجزيه آن‌ها به كلاس‌هاي كوچكتر، با تعداد وظيفه‌ي كمتر است.
به عنوان نمونه كلاس CustomerService زير، دو گروه كار متفاوت را انجام مي‌دهد. ثبت و بازيابي اطلاعات ثبت نام يك مشتري و همچنين محاسبات مرتبط با سفارشات مشتري‌ها:

using System;
using System.Collections.Generic;

namespace Refactoring.Day8.RemoveGodClasses.Before
{
    public class CustomerService
    {
        public decimal CalculateOrderDiscount(IEnumerable<string> products, string customer)
        {
            // do work
            throw new NotImplementedException();
        }

        public bool CustomerIsValid(string customer, int order)
        {
            // do work
            throw new NotImplementedException();
        }

        public IEnumerable<string> GatherOrderErrors(IEnumerable<string> products, string customer)
        {
            // do work
            throw new NotImplementedException();
        }

        public void Register(string customer)
        {
            // do work
        }

        public void ForgotPassword(string customer)
        {
            // do work
        }
    }
}

بهتر است اين دو گروه، به دو كلاس مجزا بر اساس وظايفي كه دارند، تجزيه شوند. به اين ترتيب نگهداري اين نوع كلاس‌هاي كوچكتر در طول زمان ساده‌تر خواهند شد:

using System;
using System.Collections.Generic;

namespace Refactoring.Day8.RemoveGodClasses.After
{
    public class CustomerOrderService
    {
        public decimal CalculateOrderDiscount(IEnumerable<string> products, string customer)
        {
            // do work
            throw new NotImplementedException();
        }

        public bool CustomerIsValid(string customer, int order)
        {
            // do work
            throw new NotImplementedException();
        }

        public IEnumerable<string> GatherOrderErrors(IEnumerable<string> products, string customer)
        {
            // do work
            throw new NotImplementedException();
        }
    }
}

namespace Refactoring.Day8.RemoveGodClasses.After
{
    public class CustomerRegistrationService
    {
        public void Register(string customer)
        {
            // do work
        }

        public void ForgotPassword(string customer)
        {
            // do work
        }
    }
}