溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Immutable集合的示例分析

發(fā)布時(shí)間:2021-12-16 11:24:15 來源:億速云 閱讀:170 作者:小新 欄目:大數(shù)據(jù)

這篇文章主要為大家展示了“Immutable集合的示例分析”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Immutable集合的示例分析”這篇文章吧。

不可變集合,顧名思義就是說集合是不可被修改的。集合的數(shù)據(jù)項(xiàng)是在創(chuàng)建的時(shí)候提供,并且在整個(gè)生命周期中都不可改變。

為什么要用immutable對(duì)象?immutable對(duì)象有以下的優(yōu)點(diǎn):

  1. 對(duì)不可靠的客戶代碼庫來說,它使用安全,可以在未受信任的類庫中安全的使用這些對(duì)象

  2. 線程安全的:immutable對(duì)象在多線程下安全,沒有競(jìng)態(tài)條件

  3. 不需要支持可變性, 可以盡量節(jié)省空間和時(shí)間的開銷. 所有的不可變集合實(shí)現(xiàn)都比可變集合更加有效的利用內(nèi)存 (analysis)

  4. 可以被使用為一個(gè)常量,并且期望在未來也是保持不變的

immutable對(duì)象可以很自然地用作常量,因?yàn)樗鼈兲焐褪遣豢勺兊膶?duì)于immutable對(duì)象的運(yùn)用來說,它是一個(gè)很好的防御編程(defensive programming)的技術(shù)實(shí)踐。

微軟.NET團(tuán)隊(duì)已經(jīng)正式發(fā)布了不可變集合,可以通過Nuget添加,包括了下面的不可變集合:

System.Collections.Immutable.ImmutableArray

System.Collections.Immutable.ImmutableArray<T>

System.Collections.Immutable.ImmutableDictionary

System.Collections.Immutable.ImmutableDictionary<TKey,TValue>

System.Collections.Immutable.ImmutableHashSet

System.Collections.Immutable.ImmutableHashSet<T>

System.Collections.Immutable.ImmutableList

System.Collections.Immutable.ImmutableList<T>

System.Collections.Immutable.ImmutableQueue

System.Collections.Immutable.ImmutableQueue<T>

System.Collections.Immutable.ImmutableSortedDictionary

System.Collections.Immutable.ImmutableSortedDictionary<TKey,TValue>

System.Collections.Immutable.ImmutableSortedSet

System.Collections.Immutable.ImmutableSortedSet<T>

System.Collections.Immutable.ImmutableStack

System.Collections.Immutable.ImmutableStack<T>

MSDN的文檔參考 https://msdn.microsoft.com/zh-cn/library/system.collections.immutable.aspx ,怎么使用呢?我們來看一個(gè)例子,假設(shè)你已經(jīng)建立了一個(gè)計(jì)費(fèi)系統(tǒng),你需要一個(gè)不可變的設(shè)計(jì),在多線程操作的情況下不需要擔(dān)心數(shù)據(jù)損壞。例如,你需要通過一個(gè)輔助線程打印數(shù)據(jù)的一個(gè)快照,這種方式避免阻塞用戶的編輯操作,允許用戶繼續(xù)編輯而不影響打印。

可變的數(shù)據(jù)模型是這樣:

class Order
{
public Order()
{
Lines = new List<OrderLine>();
}

public List<OrderLine> Lines { get; private set; }
}

class OrderLine
{
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public float Discount { get; set; }

public decimal Total
{
get
{
return Quantity * UnitPrice * (decimal) (1.0f - Discount);
}
}
}

下面我們把它轉(zhuǎn)換為不可變的設(shè)計(jì):

class OrderLine
{
public OrderLine(int quantity, decimal unitPrice, float discount)
{
Quantity = quantity;
UnitPrice = unitPrice;
Discount = discount;
}

public int Quantity { get; private set; }

public decimal UnitPrice { get; private set; }

public float Discount { get; private set; }

public decimal Total
{
get
{
return Quantity * UnitPrice * (decimal) (1.0f - Discount);
}
}
}

這種新設(shè)計(jì)要求您創(chuàng)建一個(gè)訂單,每當(dāng)任何屬性值變化創(chuàng)建一個(gè)新實(shí)例。您可以通過添加 WithXxx 方法,使您可以更新單個(gè)屬性而無需顯式調(diào)用構(gòu)造函數(shù):

class OrderLine
{
// ...

public OrderLine WithQuantity(int value)
{
return value == Quantity
? this
: new OrderLine(value, UnitPrice, Discount);
}

public OrderLine WithUnitPrice(decimal value)
{
return value == UnitPrice
? this
: new OrderLine(Quantity, value, Discount);
}

public OrderLine WithDiscount(float value)
{
return value == Discount
? this
: new OrderLine(Quantity, UnitPrice, value);
}
}

這使得不可變使用起來比較簡(jiǎn)單:

OrderLine apple = new OrderLine(quantity: 1, unitPrice: 2.5m, discount: 0.0f);

OrderLine discountedAppled = apple.WithDiscount(.3f);

現(xiàn)在讓我們看看我們?nèi)绾温鋵?shí)訂單的不變性。Lines 屬性已經(jīng)是只讀的但它指的是可變對(duì)象。因?yàn)樗且粋€(gè)集合,它可以容易地通過簡(jiǎn)單地將它替換 ImmutableList <T>轉(zhuǎn)換:

class Order
{
public Order(IEnumerable<OrderLine> lines)
{
Lines = lines.ToImmutableList();
}

public ImmutableList<OrderLine> Lines { get; private set; }

public Order WithLines(IEnumerable<OrderLine> value)
{
return Object.ReferenceEquals(Lines, value)
? this
: new Order(value);
}
}

這種設(shè)計(jì)有一些有趣的屬性:

? 該構(gòu)造函數(shù)接受 IEnumerable <T>,允許傳遞任何集合中。

? 我們使用 ToImmutableList() 擴(kuò)展方法,將轉(zhuǎn)換為 ImmutableList <OrderLine>。如果該實(shí)例已經(jīng)是不可變的列表,它會(huì)簡(jiǎn)單地轉(zhuǎn)換而不是創(chuàng)建一個(gè)新的集合。

? 該 WithLines() 方法遵循 我們的訂單公約,如果新的列表和當(dāng)前列表是相同的就可以避免創(chuàng)建一個(gè)新的實(shí)例。

我們還可以加一些便利的方法來使它更易于更新訂單行:

class Order
{
//...

public Order AddLine(OrderLine value)
{
return WithLines(Lines.Add(value));
}

public Order RemoveLine(OrderLine value)
{
return WithLines(Lines.Remove(value));
}

public Order ReplaceLine(OrderLine oldValue, OrderLine newValue)
{
return oldValue == newValue
? this
: WithLines(Lines.Replace(oldValue, newValue));
}
}

增補(bǔ)訂單的代碼看起來是這樣子:

OrderLine apple = new OrderLine(quantity: 1, unitPrice: 2.5m, discount: 0.0f);
Order order = new Order(ImmutableList.Create(apple));

OrderLine discountedApple = apple.WithDiscount(discount);
Order discountedOrder = order.ReplaceLine(apple, discountedApple);

這種設(shè)計(jì)的好處是,它盡可能避免了不必要的對(duì)象創(chuàng)建。例如,當(dāng)折扣的值等于 0.0 f,即時(shí)沒有折扣,,discountedApple 和 discountedOrder 引用現(xiàn)有實(shí)例的蘋果和訂單。

這是因?yàn)?

1.apple.WithDiscount() 將返回蘋果的現(xiàn)有實(shí)例,因?yàn)樾碌恼劭凼窍嗤劭蹖傩缘漠?dāng)前值。

2.order.ReplaceLine() 如果兩個(gè)參數(shù)都相同,將返回現(xiàn)有實(shí)例。

我們不變的集合其他操作遵循這種最大化重用。例如,將訂單行添加到 1000 的訂單行的訂單與 1,001 訂單行不會(huì)創(chuàng)建整個(gè)的新列表。相反,它將重用現(xiàn)有列表一大塊。這是可能的因?yàn)榱斜韮?nèi)部結(jié)構(gòu)是為一棵樹,允許共享不同實(shí)例的節(jié)點(diǎn)。

以上是“Immutable集合的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI