【问题标题】:Is this modified C# singleton pattern a good practice?这种修改后的 C# 单例模式是一个好习惯吗?
【发布时间】:2010-02-09 15:51:28
【问题描述】:

我正在开发一个由非营利组织共享的博客应用程序。我希望每个组织都能够更改自己的博客设置。我采用了单例模式(来自 BlogEngine.net)并对其进行了修改。 (我知道它不再是单例模式。)我已经测试过这种方法,它似乎在开发环境中运行良好。这种模式是一个好习惯吗?将其置于生产环境中时是否会出现问题?

public class UserBlogSettings
    {
    private UserBlogSettings()
    {
        Load();
    }

    public static UserBlogSettings Instance
    {
            get
            {
                string cacheKey = "UserBlogSettings-" + HttpContext.Current.Session["userOrgName"].ToString();
                object cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
                if (cacheItem == null)
                {
                    cacheItem = new UserBlogSettings();
                    HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, DateTime.Now.AddMinutes(1),
                                             Cache.NoSlidingExpiration);
                }
                return (UserBlogSettings) cacheItem;
            }
    }
}    

(为简洁起见,省略了部分代码。)

感谢您的任何帮助、评论等。

【问题讨论】:

    标签: c# asp.net design-patterns


    【解决方案1】:

    如果是每个会话,则将其存储在会话中而不是缓存中。

    此外,您在这里无缘无故地向上和向下转换:

    object cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
    

    这会删除不需要的演员表

    UserBlogSettings cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
    if (cacheItem == null)
    {
        cacheItem = new UserBlogSettings();
        HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, 
                             DateTime.Now.AddMinutes(1),
                             Cache.NoSlidingExpiration);
    }
    return cacheItem;
    

    【讨论】:

    • 它是按用户组织(而不是用户)——因此组织 xyz 可能有许多用户同时在网站上查看他们的博客。
    • @geri 这更有意义。除了演员问题,它还不错。你确定你只想缓存一分钟吗?在创建/插入缓存时考虑对象的生命周期。
    • 感谢选角建议——一分钟缓存仅用于开发。静态实例呢?有什么问题吗?
    • @Geri nope,只要您不声明任何类型范围的静态变量,您就可以在静态方法中触摸/修改。
    • 感谢 Will -- 感谢您的所有时间和帮助。
    【解决方案2】:

    您需要使用锁定来避免可能的竞争条件:

        private static Object lock_Instance = new Object ();
        public static UserBlogSettings Instance 
        { 
            get 
            { 
                string cacheKey = "UserBlogSettings-" + HttpContext.Current.Session["userOrgName"].ToString(); 
                UserBlogSettings cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
                if (cacheItem == null) 
                {
                    lock (lock_Instance)
                    {
                        // need to check again in case another thread got in here too
                        cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
                        if (cacheItem == null)
                        {
                            cacheItem = new UserBlogSettings();
                            HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, 
                                DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration);
                        }
                    }
                } 
                return cacheItem; 
            } 
        } 
    

    【讨论】:

      【解决方案3】:

      我认为你的总体上是好的,但如果有必要,我会建议提高性能(我知道......在你真正需要之前不要优化)。

      我可能会用这样的方法来实现这个来获取设置对象:

      public static UserBlogSettings getSettings(string orgName, Cache cache) {
        // do the same stuff here, except using the method parameters
      }
      

      原因是 HttpContext.Current 和 HttpRuntime.Cache 必须经过一些回转才能获得当前 Session 和 Cache 的句柄。如果您是从 asp.net 页面调用它,那么您已经掌握了这些东西。因此,请使用您已有的而不是再次查找它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-11
        • 2018-11-17
        • 2012-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多