Singleton с открытым (единичным) конструктором - PullRequest
3 голосов
/ 21 декабря 2008

В качестве упражнения я переводю части нашей большой и закаленной в битве Delphi-фреймворка на C #.

В эту структуру включен универсальный родительский класс-одиночка. Конечно, реализовать синглтон в C # довольно просто (есть даже статья Jon Skeet, так что еще я мог бы пожелать), но наш синглтон Delphi имеет несколько иной подход к шаблону: в отличие от публикации «экземпляра» свойство / метод, у него есть «фальшивый» конструктор, который всегда возвращает один и тот же экземпляр. Существенной характеристикой этого подхода является то, что пользователь класса синглтона не знает, что он имеет дело с синглтоном : насколько они знают, они просто создают любой старый класс и запрашивают у него некоторую информацию.

Я хочу выполнить то же самое в C # (в качестве упражнения, так что это не обязательно должен быть код производственного качества, злая хакерская атака - это хорошо), но пока я потерпел неудачу.

Любое предложение сделать простой myInstance = new MyClass(); всегда возвращать один и тот же экземпляр приветствуется!


Дополнительная информация

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

  • Меня не очень интересует вопрос о том, является ли это правильным способом борьбы с синглетами, а сейчас меня интересует более тонкое искусство твиков c #.

Ответы [ 7 ]

7 голосов
/ 21 декабря 2008

Вы бы сделали Прокси (Правка: как Том указывает ниже, правильный шаблон дизайна - Monostate):

public class MyClass {
  MyActualClass _actual;
  public MyClass() {
    _actual = MyActualClass. Instance;
  }
  public DoStuff() {
    _actual.DoStuff();
  }
}

internal class MyActualClass {
  private MyActualClass {
  }
  public DoStuff() {
    ...
  }
  MyActualClass _instance;
  public static Instance {
    get {
       if(_instance == null)
         _instance = new MyActualClass()
       return _instance;
    }
  }
}

....

public static void Main() {
  var my1 = new MyClass();
  var my2 = new MyClass();   
}

my1! = My2, но my1.DoStuff () вызывает тот же экземпляр метода, что и my2.DoStuff () Это упростится еще больше, если вы запрограммируете только интерфейс.

Изменить: Проблема равенства может быть частично решена путем создания _actual внутренняя защита и перезаписи MyClass.Equals (объект obj), чтобы проверить, является ли this._actual == obj._actual

4 голосов
/ 21 декабря 2008

Я верю, что шаблон Monostate даст вам то, что вам нужно:

" Моностат дает нам особенность состояния, которое мы так ценим в Синглтоне, но без всех статических головных болей, которые сопровождают его." Подробнее здесь: http://jeremyjarrell.com/archive/2008/04/21/88.aspx

2 голосов
/ 21 декабря 2008

Насколько я знаю, это не может быть сделано по-настоящему из-за того, как C # обрабатывает экземпляры объектов. Чтобы вызвать конструктор, экземпляр должен быть фактически создан, и вы не можете просто «вернуть» другой объект из конструктора.

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

В этой реализации синглтон не обязательно должен быть одним и тем же классом, но вы можете это сделать, если хотите сохранить содержимое.

Обновление: Один недостаток этого подхода состоит в том, что хотя каждый экземпляр ведет себя как одиночный объект, он все равно будет иметь собственную ссылку на объект, и поэтому вы также можете захотеть переопределить Equals() для сравнения на равенство.

0 голосов
/ 05 января 2009

Как насчет использования статической функции для возврата объекта, в котором используется ключевое слово new.

static private m_obj my_obj;
static private bool my_new_obj;
static public m_obj create_m_obj()
{
    if (my_new_obj == false)
    {
        my_new_obj = true;
        my_obj = new my_obj();
    }
    return my_obj;
}

Тогда у вас есть легкий полный контроль над созданием объекта, если я не ошибаюсь.

0 голосов
/ 21 декабря 2008

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

class SingletonWrapper {

    private static RealSingleton instance = new RealSingleton();

    public void methodA() {
        instance.methodA();
    }

    public String getA() {
        return instance.getA();
    }

}

(Это на самом деле Java-код, но я думаю, что C # достаточно похож.)

0 голосов
/ 21 декабря 2008

Я думаю, вы могли бы что-то накатить с Remoting.

Обновление:

Лучшим способом было бы обернуть правильный класс-одиночка в структуру или легкий класс.

0 голосов
/ 21 декабря 2008

Я не вижу, как вы можете, так как конструкторы не используют оператор возврата. Вы можете клонировать все соответствующие ссылки на синглтон, но он будет иметь локальные копии локальных переменных и быть очень грязным.

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

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