设计模式-c静态getter应该是线程安全的吗
本文关键字:线程 安全 静态 getter 设计模式 | 更新日期: 2023-09-27 18:00:16
我想知道这个类是否是线程安全的
我可以在不执行锁的情况下访问Currencies
属性的getter吗?
我应该在GetLiveExchangeRates()
方法中锁定对Currencies
属性的访问吗?
public class CurrencyManager
{
public static List<CurrencyModel> Currencies { get; private set; }
private static readonly object LockObj = new object();
public CurrencyManager()
{
Currencies = new List<CurrencyModel>();
}
public static void GetLiveExchangeRates()
{
lock (LockObj)
{
Currencies = GetSomeFooLiveDataFromInternet();
}
}
}
编辑
你将如何重构它?
如果你必须使用静态类,我会像这样重构这个类:
public class CurrencyManager
{
private static readonly IEnumerable<CurrencyModel> currencies = Enumerable<CurrencyModel.Empty();
private static readonly object LockObj = new object();
public static void RefreshLiveExchangeRates()
{
lock (LockObj)
{
CurrencyManager.currencies = GetSomeFooLiveDataFromInternet();
}
}
public static IEnumerable<CurrencyModel> GetCurrencies()
{
return CurrencyManager.currencies;
}
}
将方法重命名为能够更好地描述实际发生的情况的方法。当你称之为GetLiveExchangeRates
时,我希望它能返回汇率,而不是无效。然后,我会一起删除构造函数,并创建一个返回集合的GetCurrencies()
方法,如果集合为null,则创建一个空方法。您正在公开的集合Currencies
似乎不应该以列表的形式公开,因为这允许消费者更改它。您还没有解释集合的意义,所以我通过您的命名约定来推断正在发生的事情。
如果我写这篇文章,我可能会把它藏在服务后面。删除了对静态类的需要。您在视图模型/控制器/服务中持有汇率参考。当您需要刷新它们时,请再次访问该服务。
服务
public class CurrencyService
{
public IEnumerable<CurrencyModel> GetLiveExchangeRates()
{
return GetSomeFooLiveDataFromInternet();
}
}
消费者(视图模型/控制器等)
public class MyController
{
private IEnumerable<CurrencyModel> currentRates;
public MyController()
{
// Instance a new service; or provide it through the constructor as a dependency
var currencyService = new CurrencyService();
this.currentRates = currencyService.GetLiveExchangeRates();
}
}
然后,您的消费类将使用它从服务中获取的集合。如果它愿意,它可以将该集合传递给依赖它的其他对象。当你觉得该集合过时时,你可以从服务中重新获取它们。在这一点上,您可能不需要进行任何锁定,因为只有使用者可以使用该属性,并可以控制何时可以和将要更改该属性。这允许多个实例查询最新汇率,而不必进行锁定,并让每个人都排队接收。
理想情况下,我希望看到它作为依赖项通过构造函数传递,隐藏在接口后面,并在需要时刷新速率。因此,我不会在构造函数中获取速率,而是在需要时懒洋洋地获取它们。这将允许您异步地完成工作(假设您的实际实现是异步的)。
编辑
如果出于缓存目的将集合存储在静态类中,则可以将集合存储到服务中,并且始终返回集合。唯一一次返回新的汇率集是在清除缓存时。
public class CurrencyService
{
private static IEnumerable<CurrencyModel> currencyRates;
private static object ratesLock = new object();
public IEnumerable<CurrencyModel> GetLiveExchangeRates()
{
if (currencyRates == null)
{
lock (ratesLock)
{
currencyRates = GetSomeFooLiveDataFromInternet();
}
}
return currencyRates;
}
public void ClearRates()
{
currencyRates = null;
}
}
这或多或少是一个实现更改。您的控制器/视图模型将继续命中GetLiveExchangeRates()
,但它只会从外部服务中获取一次。每次之后,它都只返回缓存。您只需支付一次锁定费,然后当其他对象同时访问您的服务时,您就不会再支付锁定费。