重構系列整理-搭配Resharper(二)

重構

這系列是專門記錄在物件中進行物件中的搬移手法。

一、Move Method

用途:將一個類別某方法、搬移到另一個按照直則劃分該有方法的類別中。

 //前
 // 遺留的 Person 類別
 public class Person
 {
     public string Name { get; set; }
     public int Age { get; set; }
     //Step1 Ctrl+Shift+R 選擇 Move Instance Move
     public string GetPersonDetails(PersonManager personManager)
     {
         return $"Name: {Name}, Age: {Age}";
     }

  
 }

 // 遺留的 PersonManager 類別
 public class PersonManager
 {
    
 }
  //後
  // 遺留的 Person 類別
  public class Person
  {
      public string Name { get; set; }
      public int Age { get; set; }
  }

  // 遺留的 PersonManager 類別
  public class PersonManager
  {
      public string GetPersonDetails(Person person)
      {
          return $"Name: {person.Name}, Age: {person.Age}";
      }
  }

二、Move Field

用途:將某一段的屬性移動到另一個合適的類別中。

 //前
 public class Employee
 {
  
 }

 public class Salary
 {
     public  string employeeId { get; set; }
     public  string employeeName { get; set; }
 }
 //後
 public class Employee
 {
     public  string employeeId { get; set; }
     public  string employeeName { get; set; }
 }

 public class Salary
 {
    
 }

三、Extrace Class

用途:將一個類別某個字段或方法來抽取出來放到新的類別中,以提升系統的功能內聚。

 public class OrderService
 {
     public OrderService()
     {
     }
     //Step1:該方法 Ctrl+Shift+R 選取Extract Class
     public bool IsExistCustomer(string customerId)
     {
         // 判斷客戶是否存在
         return true;
     }

     public void CreateOrder(Customer customer)
     {
         // 建立訂單
          
     }
 }
 //後 
 public class customerService
 {
     public customerService()
     {
     }

     public bool IsExistCustomer(string customerId)
     {
         // 判斷客戶是否存在
         return true;
     }
 }

 public class OrderService
 {
     private readonly customerService _customerService;

     public OrderService()
     {
         _customerService = new customerService();
     }


     public void CreateOrder(Customer customer)
     {
         // 建立訂單
          
     }
 }

四、InLine Class

用途:當如果A類別是B類別一個屬性,將A類別刪除,並將A類別內容歸類到B類中(Extrace Class反向操作)。

    //前
    public class customerService
    {
        public customerService()
        {
        }

        public bool IsExistCustomer(string customerId)
        {
            // 判斷客戶是否存在
            return true;
        }
    }

    public class OrderService
    {
        // 在_customerService 執行Step1:Ctrl+Shift+R 選取InLine Class
        private readonly customerService _customerService;

        public OrderService()
        {
            _customerService = new customerService();
        }
        //Step1:Ctrl+Shift+R 選取Extract Class

        public void CreateOrder(Customer customer)
        {
            // 建立訂單
             
        }
    }
  //後
  public class OrderService
  {

      public OrderService()
      {
      }
    

      public void CreateOrder(Customer customer)
      {
          // 建立訂單
           
      }

      public bool IsExistCustomer(string customerId)
      {
          // 判斷客戶是否存在
          return true;
      }
  }

五、Hide Delegate

用途:當Clinet程式要調用A類別也要調用B類別,而A和B又是潛在委託關係,如A聚合B,讓Clinet程式不要直接呼叫A類別,透過B類別,訪問A類別。

 //前
 public class Person
 {
     private Department _department;

     public Department GetDepartment()
     {
         return _department;
     }

     public void SetDepartment(Department value)
     {
         _department = value;
     }
     // 使用 Hide Delegate,透過 Department 的方法存取相關屬性
     //public Person GetManager()
     //{
     //    return _department.GetManager();
     //}

 }

 public class Department
 {
     private string _chargeCode;
     private Person _manager;

     public Department(Person person)
     {
         _manager = person;
     }

     public Person GetManager()
     {
         return _manager;
     }


     public string ChargeCode
     {
         get { return _chargeCode; }
         set { _chargeCode = value; }
     }
 }


 class Client
 {
     public void Main()
     {
         var john = new Person();
         //原本
         var manager = john.GetDepartment().GetManager();
         //透過Hide Delegate 改呼叫Person的方法
         //var manager1 = john.GetManager();
     }
     
 }
  //後
  public class Person
  {
      private Department _department;

      // 使用 Hide Delegate,透過 Department 的方法存取相關屬性
      public Person GetManager()
      {
          return _department.GetManager();
      }

  }

  public class Department
  {
      private string _chargeCode;
      private Person _manager;

      public Department(Person person)
      {
          _manager = person;
      }

      public Person GetManager()
      {
          return _manager;
      }


      public string ChargeCode
      {
          get { return _chargeCode; }
          set { _chargeCode = value; }
      }
  }


  class Client
  {
      public void Main()
      {
          var john = new Person();
          //原本
          //var manager = john.GetDepartment().GetManager();
          //透過Hide Delegate 改呼叫Person的方法
          var manager1 = john.GetManager();
      }
      
  }

六、Remove Midele Man

用途:如果客戶程序再透過委託A類別調用B類別,則去掉這種委託直接訪問類別B(隱藏委託的反向操作)。

  
 public class Person
 {
     private Department _department;

     public Department GetDepartment()
     {
         return _department;
     }

     public void SetDepartment(Department value)
     {
         _department = value;
     }
     // 使用 Hide Delegate,透過 Department 的方法存取相關屬性
     //public Person GetManager()
     //{
     //    return _department.GetManager();
     //}

 }

 public class Department
 {
     private string _chargeCode;
     private Person _manager;

     public Department(Person person)
     {
         _manager = person;
     }

     public Person GetManager()
     {
         return _manager;
     }


     public string ChargeCode
     {
         get { return _chargeCode; }
         set { _chargeCode = value; }
     }
 }


 class Client
 {
     public void Main()
     {
         var john = new Person();
         //原本
         var manager = john.GetDepartment().GetManager();
         //透過Hide Delegate 改呼叫Person的方法
         //var manager1 = john.GetManager();
     }
     
 }

七、Introduce Foreign Method

用途:如果客戶端程式在調用A類別的某方法M時候,需增加一段程式碼,如果大量客戶端程式掉用這方法M時候,都要增加這一段程式碼,應在類別A中增加一個外加方法。

(註記:在大量程式增加這一段程式碼無疑是一種程式的重複,而在M編寫外加方法則實現大量程式碼的重用。)

有一個遺留程式碼的類別是Person類別

//Step1 確認遺留類別
public class Person
{
    public DateTime DateOfBirth { get; set; }
}
//Step2 創造方法的新類別
public static class PersonExtensions
{
    public static int CalculateAge(this Person person)
    {
        var today = DateTime.Today;
        var age = today.Year - person.DateOfBirth.Year;
        if (person.DateOfBirth.Date > today.AddYears(-age))
            age--;
        return age;
    }
}
//Step3 呼叫外部方法
Person person = new Person { DateOfBirth = new DateTime(1988, 1, 1) };
int age = person.CalculateAge();

八、Introduce Local Extension

用途:當系統需要修改一個類別提供某項功能,但你不能修改該類別,為該類別設計一個子類別,並在子類別當中提供這項功能,而讓要使用該功能的客戶端程式調用子類別。

Introduce Foreign Method與Introduce Local Extension區別在於不是簡單增加單獨方法,而是透過新增一個新類別,這個新類別必須繼承原始類別(子類別或包裝原始類別的實例,包裝類)。

  1. 子類別擴展:在這種方式,必須建立新的類別,繼承原始類別,然後在這個子類別增加你需要新方法或屬性,這種方法原始類別必須允許繼承。
  2. 包裝類:如果原始類別不予許繼承,可以透過類別透過注入方式來引入內部實例,增加新的方法和屬性。

以Date類別為例

1.子類別擴展

public class ExtendedDate : Date
{
    public ExtendedDate(int year, int month, int day) : base(year, month, day) { }

    public void AddDays(int days)
    {
        //自行加入邏輯
    }
}

2.包裝類別

public class DateWrapper
{
    private Date _date;

    public DateWrapper(Date date)
    {
        _date = date;
    }

    public void AddDays(int days)
    {
        
    }


}

  

老E隨手寫