這個做法也是在對 Iterator Methods
與 yield return
進行延伸討論,並把做法 7 中的 delegate
概念加入進來。
我們已經知道 Iterator Methods
是用來處理集合中資料迭代的功能,但是一個只會進行迴圈的方法是沒什麼意義,通常還會有另一部分
就是對集合中的元素進行處理,例如在做法 31 中把資料去重複就是這樣的概念。
如果我們把這兩種職責寫在同一個方法裡面,那就會產生耦合會導致之後進行修改的時會很難找到問題點,跟 SRP 原則想表達的意思差不多。
也就是說最好是想辦法把這兩種職責分開來,長久來看是比較好的做法,要達到這樣的目的可以使用 做法 7 有提到的 delegate
。
我們在做法 7 有提到常用的 delegate
格式可以直接用微軟內建的就好,不用自己在建立一個類似的 delegate
。
namespace System
{
public delegate bool Predicate<T>(T obj);
public delegate void Action<T>(T obj);
public delegate TResult Func<T, TResult>(T arg);
}
例如今天我想要將傳入的集合過濾掉某一個數字,不依靠 delegate
可能會長的像這樣,這個方法同時有迭代跟比較兩種職責存在。
void Main()
{
var xx = new List<int>() {1, 2, 3, 4, 5, 6,};
Where<int>(xx, 6).Dump();
}
public static IEnumerable<T> Where<T>(IEnumerable<T> sequence, T filter)
{
if (sequence == null)
throw new ArgumentNullException(nameof(sequence), "sequence must not be null");
foreach (T item in sequence)
if (!item.Equals(filter))
yield return item;
}
改成 delegate
的版本會發現比較的職責被移出方法外了,也就是會透過 filterFunc 參數把 delegate
傳入進來,這樣方法就能維持一個職責。
public static IEnumerable<T> Where<T> (IEnumerable<T> sequence, Predicate<T> filterFunc)
{
if (sequence == null)
throw new ArgumentNullException(nameof(sequence), "sequence must not be null");
if (filterFunc == null)
throw new ArgumentNullException("Predicate must not be null");
foreach (T item in sequence)
if (filterFunc(item))
yield return item;
}
關鍵就是把其它職責透過參數的方式來傳入,也可以改用 Func
產生輸出。
public static IEnumerable<T> Select<T>(IEnumerable<T> sequence, Func<T, T> method)
{
foreach (T element in sequence)
yield return method(element);
}
使用起來會像下面這樣,會將我們寫的 Lambda 語法轉換成參數之後進行平方運算完成後輸出結果。
void Main()
{
var ll = new List<int>() { 1, 2, 3, 4, 5, 6 };
var r = Select<int>(ll, x => x * x);
Console.WriteLine(r);
}
也可以使用做法 31 提到 Iterator Methods
的組合特性,將兩個 Iterator Methods
進行結合。
void Main()
{
var ll = new List<int>() { 1, 2, 3, 4, 5, 6 };
var r = Select<int>(Where<int>(ll, x => x > 3), x => x * x);
Console.WriteLine(r);
}
Summary
這個做法在複習做法 7 有提到的內建三個 delegate
方法 Predicate<T>
、Action<T>
、Func<>
搭配 Iterator Methods
將不屬於方法的職責移出去來達到解耦的效果,
並且建議把職責都分開來讓每一個方法盡量都只有保持一個職責。