Объект, который необходим во всем приложении - PullRequest
1 голос
/ 18 декабря 2009

У меня есть приложение, которое получает некоторые данные от пользователя, когда приложение загружается и требуется по всему приложению, каков наилучший способ сохранить объект, который хранит эти данные в течение всего срока службы приложения?

Эти данные должны быть доступны большинству других объектов, созданных за время существования приложения.

На днях я узнал, что синглтоны не обязательно хорошая идея. Особенно в многопоточных средах, которыми является мое приложение.

Я использовал Singletons для решения этой проблемы, но мне было интересно, если это хороший способ справиться с этим?

EDIT:

Позвольте мне выразить свое восхищение: я спрашиваю имя пользователя и пароль при запуске приложения, теперь я знаю, что хранение пароля в памяти - это безопасность и плохая практика, но в процессе входа в систему достаточно мест, где мне это нужно Данные для проверки различных вещей, так что именно здесь я использовал Singleton.

Ответы [ 6 ]

2 голосов
/ 18 декабря 2009

Я бы не советовал использовать класс, который определяет свой собственный синглтон, просто потому, что это обычно означает, что у вас будут проблемы во время модульного тестирования.

Если вы используете универсальный синглтон, у вас будет та же функциональность, но с дополнительными преимуществами позже при тестировании / отходе от шаблона синглтона (например, для нескольких пользователей).

Обратите внимание, что синглтон инициализируется делегатом. Обоснование здесь заключается в том, что делегат будет вызываться только один раз, даже если два потока каким-то образом одновременно регистрируют синглтон ...

Использование интерфейса облегчает вашу жизнь при написании юнит-тестов, поскольку вы можете смоделировать интересующую вас часть синглтона (или вашу сверхбыструю - за 2 минуты до перехода на сеанс патча / отладки CEO).

Это может быть излишним для хранения кортежа входа в систему / прохода, но этот шаблон спас мой бекон больше раз, чем я хочу сосчитать.

public static class Singleton<T>
{
    private static T instance;
    private static readonly object sync = new object();
    static bool registered = false;

    public static T Instance
    {
        get
        {
            return instance;
        }
    }

    public static void Register(Func<T> constructor)
    {
        lock (sync)
        {
            if (!registered)
            {
                instance = constructor();
                registered = true;
            }
        }
    }
}

class Demo
{
    class Data
    {
        public string Pass { get; set; }
        public string Login { get; set; }
    }

    void SimpleUsage()
    {
        string login = "SEKRIT";
        string pass = "PASSWORD";

        // setup 
        Singleton<Data>.Register(() => new Data { Login = login, Pass = pass });

        // 
        var ltCommander = Singleton<Data>.Instance;
    }

    /// <summary>
    /// Using an interface will make the singleton mockable for tests! 
    /// That's invaluable when you'll want to fix something FAST without running the whole app!
    /// </summary>
    interface IData
    {
        string Login { get; }
        string Password { get; }
    }

    class UnitTestFriendlyData : IData
    {
        public UnitTestFriendlyData(string login, string password)
        {
            Login = login;
            Password = password;
        }


        public string Login { get; private set; }
        public string Password { get; private set; }
    }

    void SmarterUsage()
    {
        // same setup, but through the interface. 
        Singleton<IData>.Register(() => new UnitTestFriendlyData("login", "pass"));

        // and same for the retrieval
        var data = Singleton<IData>.Instance;

    }


    void UnitTestSetupWithMoq()
    {
        // Register a mock.
        var mock = new Mock<IData>();
        mock.SetupProperty(x => x.Login, "Login");
        mock.SetupProperty(x => x.Pass, "Pass");
        Singleton<IData>.Register(() => mock.Object);

        // and same for the retrieval
        var data = Singleton<IData>.Instance;

    }

}
1 голос
/ 18 декабря 2009

Из того, как вы описали свою ситуацию, похоже, что вы просто хотите сохранить строку один раз при запуске, а затем она всегда будет доступна только для чтения везде. Если это так, вы можете просто сделать что-то вроде:

internal static class LoginInfo
{
    internal static string Username;
    internal static string Password;
}

Тогда из любого места в вашем приложении вы можете просто сказать:

var usr = LoginInfo.Username;
var pwd = LoginInfo.Password;

Теперь я уверен, что все прокомментируют, что это ужасная практика проектирования, но я готов с этим смириться:)

Теперь, если вы планируете все время менять значение, и если это не просто строка, а какой-то более сложный объект, то безопасность потоков наверняка может стать проблемой. Вы всегда можете создать потокобезопасный метод получения свойства.

1 голос
/ 18 декабря 2009

Моя первая реакция на это заключается в том, что если у вас есть часть данных, которая требуется большинству других типов в приложении, вы можете лучше инкапсулировать ее. Это звучит как нарушение принципа одиночной ответственности . Однако, не зная больше о вашем сценарии, трудно сказать, каким может быть лекарство.

1 голос
/ 18 декабря 2009

В этом случае синглтон является правильным выбором. Вы просто не хотите начинать толкать там множество несвязанных вещей - вы хотите, чтобы класс оставался сплоченным, а не просто «мешком свойств», который сидит без дела. Что касается многопоточности, вы можете поместить соответствующие элементы управления в ваш синглтон-класс, без проблем. Однако какие типы блокировок и защит вы используете, зависит от вашей реализации (хотя в вашем вопросе недостаточно подробностей, чтобы ответить на этот вопрос).

1 голос
/ 18 декабря 2009

См. Это для некоторых объяснений

Реализация Singleton в C # , глядя на Многопоточный Singleton .

Также Первый способ реализации синглтон-паттерна в C #: рассмотрение III-й способ реализации синглтон-паттерна в C #: простой многопоточный шаблон синглтона и IV-й способ реализации синглтон-паттерна в C #: многопоточный шаблон синглтона

0 голосов
/ 18 декабря 2009

Причина, по которой люди говорят, что Singleton не всегда хорошая идея, заключается в том, что он поощряет сценарий, подобный вашему. Необходимость в статическом объекте является плохой частью - синглтон рассматривается только как активатор.

Тем не менее, я не могу прокомментировать, является ли это необходимым в вашем приложении, потому что вы его не детализировали. Но если вам ДЕЙСТВИТЕЛЬНО нужны статические данные, хранящиеся в объекте в течение всего срока службы приложения, продолжайте и используйте singleton. Вы также можете сделать их поточно-ориентированными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...