小酌重構系列[6]——引入參數對象


簡述

如果方法有超過3個以上的參數,調用方法時就會顯得冗詞贅句。這時將多個參數封裝成一個對象,調用方法會顯得干凈整潔。
這就是本文要講的重構策略“引入參數對象”——將方法的參數封為類,並用這個類的對象替換方法中原有的參數。

引入參數對象

下圖演示了這個重構策略,OrderSerivce表示訂單服務,GetOrders()方法根據一些條件獲取訂單信息。
在重構前,GetOrders()方法看起來像長篇大論,調用時也頗為麻煩;在重構后,GetOrders()方法看起來言簡意賅,調用時僅需要傳入一個參數。

image

優點

這個策略在我看來至少有兩個優點:

1. 可以減少方法的參數個數,調用方法時會更加干凈整潔。
2. 當方法需要追加或者刪除參數時,不需要修改方法簽名。

注意點

1. 意味着你要在項目中追加新的class。
2. 並非死板地將所有的參數都放到一個參數對象中,需要確定這些參數屬於某一個“共同的概念”。
3. 方法調用參數減少了,給“參數對象”起個好名字也很重要。
4. 項目開發階段,如果方法的參數隨時可能變更,建議直接將參數設計為對象參數。

例如:在一個平面坐標系統中,基於坐標和半徑畫圓。

public void CreateCircle(double x, double y, double radius)
{
    // do work
}

如果使用參數對象,我們可以用兩種方式來表達。

方式1:將坐標封裝為參數對象
方式2:將坐標 + 半徑封裝為參數對象

使用合適的參數對象命名可以將這兩種方式區分開來。
方式1,提煉出“坐標”概念,於是就有了Point對象;方式2,提煉出“圓”概念,故使用了Circle對象作為參數。

public class ShapeTool
{
    // 方式1:封裝坐標
    public void CreateCircle(Point point, double radius)
    {
        // do work
    }

    // 方式1:封裝坐標 + 半徑
    public void CreateCircle(Circle circle)
    {
        // do work
    }
}

public class Point
{
    public double X { get; set; }
    public double Y { get; set; }
}

public class Circle
{
    public Point Point { get; set; }
    public double Radius { get; set; }
}

示例

重構前

這段代碼用於“學生注冊課程”。

public class Registration
{
    public void Create(decimal amount, Student student, IEnumerable<Course> courses, decimal credits)
    {
        // do work
    }
}

public class Student
{
    
}

public class Course
{

}

Create()方法的看起來難以理解,它的參數個數很多,並且沒有良好的分類,我們應將這些參數封裝起來。

重構后

針對“學生注冊課程”這個場景,我們提煉出一個概念——”注冊上下文“,這個上下文可以包含以上方法的所有參數。
重構后,Create()方法看起來簡潔易懂,"RegistrationContext"這個命名恰到好處,所有參數都放到RegistrationContext類里了。

public class RegistrationContext
{
    public decimal Amount { get; set; }
    public Student Student { get; set; }
    public IEnumerable<Course> Courses { get; set; }
    public decimal Credits { get; set; }
}


public class Registration
{
    public void Create(RegistrationContext registrationContext)
    {
        // do work
    }
}


public class Student
{

}

public class Course
{

}

在一些應用場景中,當你的方法擁有很多參數,且這些參數表示不同的意義時,我們很難通過這些參數的名稱提煉出一個合適的名詞。
例如:為了將HttpRequest和HttpResponse放到一個對象中,若將這個對象命名為"HttpRequestAndResponse"會顯得喋喋不休。
這時,我們可以用一種偷懶的做法,把這樣的對象命名為“xxx上下文”。
例如,在ASP.NET中HttpContext和ViewContext就是這樣的對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM