Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.10.06;
Скачать: CL | DM;

Вниз

Нужен третейский судья :)   Найти похожие ветки 

 
Dimka Maslov ©   (2013-04-23 09:07) [40]

Я всегда пользуюсь вторым вариантом, и только исходя из принципа "объект должен создаваться в тот момент, когда он впервые понадобился". Это значительно ускоряет начальную загрузку приложения, особенно в случаях, когда таких глобальных объектов множество и они потребляют значительные ресурсы. Что же касается соображения "функция вместо переменной", тот тут могут возникнуть некоторые сложности при отладке, не более того.


 
oxffff ©   (2013-04-23 09:13) [41]


> Rouse_ ©   (22.04.13 23:36) [25]
>
> > oxffff ©   (22.04.13 22:26) [20]
>
> Пфф, в аську стучись - а то всю интригу раскрою :)


Саша, аськанамана нету. Есть скайпанамана.
append 81 к нику.


 
Компромисс1 ©   (2013-04-23 09:52) [42]

Я вообще не вижу в чем проблема, ведь Delphi позволяет использовать полное имя (с именем модуля) для переменной.
Пишите
fooUnit.foo для оригинальной переменной и foo2unit.foo, если будет переменная foo, которая будет иметь класс Foo2.
Вот тут очень хорошо заметно, в чем преимущество Java - она заставляет писать имя "файла", Delphi-программисты слишком ленивы.

Первый вариант все же лучше, потому что при втором возможен одновременный вызов функции foo из двух потоков, тогда получим гонку.


> Мой код увидел разработчик на Java и обернул это все сеттерами
> и геттерами (напрямую работающие с каждым полем) и свел
> поля в private. Я его спросил, а зачем? Мне ответили бо
> инкапсуляция.


Если класс public, то он прав - лишишься возможности поменять реализацию (вдруг надо будет добавить какую-то проверку на права, например). Если же private, то можно и так оставить, для быстродействия.


 
Компромисс1 ©   (2013-04-23 09:57) [43]


> Я бы использовал синглтон, только не в такой редакции. В
> такой редакции это не синглтон, поскольку никто не мешает
> вызвать конструктор напрямую и насоздавать кучу экземпляров.
>  Чтобы этого не было, надо перекрыть NewInstance и FreeInstance.
>  И создавать экземпляр синглтона нужно при первом обращении
> к нему, а не в initialization.


При таком подходе будет невозможно создать потомка. Бывает, что нужен singleton предка и singleton потомка.


 
DevilDevil ©   (2013-04-23 10:01) [44]

Ребят, вы все всё путаете
Синглетоны, функции, классовые переменные и прочее...
Как я уже говорил, согласно специфике проекта, нахождение этого "синглетона" опционально. Например есть серверная библиотека, которая по идее может работать с несколькими клиентами. Но существуют задачи, когда предполагается взаимодействие одного лишь клиента с сервером. Для таких случаев библиотека предоставляет особый вариант компиляции.

Т.е. в данном случае, используя "синглетон" Розыча, получилось бы так:

{$IFDEF SELF_INITIALIZE}
function Foo: TFoo;
{$ENDIF}

implementation

{$IFDEF SELF_INITIALIZE}
var
_Foo: TFoo = nil;

function Foo: TFoo;
begin
if _Foo = nil then
  _Foo := TFoo.Create;
Result := _Foo;
end;
{$ENDIF}

...

initialization

finalization
 {$IFDEF SELF_INITIALIZE}
FreeAndNil(Foo);

 {$ENDIF}


 
Компромисс1 ©   (2013-04-23 10:15) [45]


> Но существуют задачи, когда предполагается взаимодействие
> одного лишь клиента с сервером.


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


 
DevilDevil ©   (2013-04-23 10:19) [46]

> Компромисс1 ©   (23.04.13 10:15) [45]

> Существуют задачи, когда клиент или сервер можен в runtime
> менять стратегию, поэтому перекомпиляция зло.


клиент и сервер в рантайме добавляют синглетон в код, перекомпилируют его и запускают новый экземпляр ?


 
DevilDevil ©   (2013-04-23 10:24) [47]

> перекомпиляция зло.

те многочисленные С++ проекты которые я видел, пестрят списком дифайнов, которыми можно задавать режим работы библиотеки. Видимо С++ программисты не знают, что перекомпиляция зло. Особенно это смешно на контрасте скорости компиляции Delphi-проектов и С++-проектов


 
Rouse_ ©   (2013-04-23 10:29) [48]


> DevilDevil ©   (23.04.13 10:01) [44]
> Т.е. в данном случае, используя "синглетон" Розыча, получилось
> бы так:

Не, в данном случае использование директив не нужно.
В случае их использования и глобальной переменной в памяти всегда висит созданный обьект - нужен он или нет.
В случае синглтона, он создается по факту обращения к нему.
Это принципиальная разница.


 
Ega23 ©   (2013-04-23 10:32) [49]

Есть некий класс с каким-то там функционалом. Допустим, он работает только в рамках какого-то одного проекта. Допустим, логика проекта такова, что он должен существовать в одном экземпляре. Вот тогда (и, ИМХО, и только тогда) синглтон (в любых его реализациях) имеет право на существование.

Появился второй проект. В рамках его логики экземпляр данного класса должен существовать в единственном экземпляре в рамках одного треда.

Появился третий проект, серия юнит-тестов данного класса. На разные тест-кейсы в SignUp должен создаваться экземпляр данного класса (пусть единственный), а на TearDowm - гарантированно прибиваться.

Вопрос: нахрена в юните с описанием данного класса городить какие-то глобальные переменные под директивами или лепить функции-синглтоны?


 
Rouse_ ©   (2013-04-23 10:43) [50]


> Ega23 ©   (23.04.13 10:32) [49]

Синглтон в данном случае ничем не мешает.


 
Юрий Зотов ©   (2013-04-23 10:52) [51]


> Компромисс1 ©   (23.04.13 09:57) [43]
> При таком подходе будет невозможно создать потомка.

Примите мой маленький подарок к наступающими майскими праздникам:

unit Unit2;

interface

type
 TSingleton1 = class
 public
   class function NewInstance: TObject; override;
   procedure FreeInstance; override;
 end;

 TSingleton2 = class(TSingleton1)
 public
   class function NewInstance: TObject; override;
   procedure FreeInstance; override;
 end;

 function Singleton1: TSingleton1;
 function Singleton2: TSingleton2;

implementation

var
 _Singleton1: TObject = nil;
 _Singleton2: TObject = nil;

{ TSingleton1 }

function Singleton1: TSingleton1;
begin
 if _Singleton1 = nil then
   _Singleton1 := TSingleton1.Create;
 Result := TSingleton1(_Singleton1)
end;

procedure TSingleton1.FreeInstance;
begin
 inherited;
 _Singleton1 := nil
end;

class function TSingleton1.NewInstance: TObject;
begin
 if _Singleton1 = nil then
   _Singleton1 := inherited NewInstance;
 Result := _Singleton1
end;

{ TSingleton2 }

function Singleton2: TSingleton2;
begin
 if _Singleton2 = nil then
   _Singleton2 := TSingleton2.Create;
 Result := TSingleton2(_Singleton2)
end;

procedure TSingleton2.FreeInstance;
begin
 inherited;
 _Singleton2 := nil
end;

class function TSingleton2.NewInstance: TObject;
var
 P: Pointer;
begin
 if _Singleton2 = nil then
 begin
   GetMem(P, InstanceSize);
   try
     _Singleton2 := InitInstance(P)
   except
     FreeMem(P, InstanceSize);
     raise
   end
 end;
 Result := _Singleton2
end;

end.


PS

Надеюсь, реализация метода TSingleton2.NewInstance развеет все сомнения по поводу нашей недавней дискуссии - стоит ли давать программисту возможность прямой работы с памятью, или не стоит.

Спички и ножи надо прятать от детей, а для взрослого человека они в миллион раз более полезны, чем опасны. А бывает даже и так, что без них и не прожить просто.


 
Pit   (2013-04-23 10:58) [52]


>
> var
>  _Foo: TFoo = nil;

эхей, камрады! А я что-то пропустил и глобальные переменные теперь не инициализируется по-умолчанию?


 
Ega23 ©   (2013-04-23 10:59) [53]


> Синглтон в данном случае ничем не мешает.

Но и не полезен ничем. А раз так, то нафига козе баян?


 
Компромисс1 ©   (2013-04-23 11:01) [54]

Ega23 ©   (23.04.13 10:32) [49]

+1.


 
Юрий Зотов ©   (2013-04-23 11:10) [55]

Небольшая поправка к [51]. Хотя работает и без нее, но с нею лучше.

procedure TSingleton2.FreeInstance;
begin
 CleanupInstance;
 FreeMem(Pointer(Self), InstanceSize);
 _Singleton2 := nil
end;


 
Компромисс1 ©   (2013-04-23 11:12) [56]

Юрий Зотов ©   (23.04.13 10:52) [51]

Это, конечно, замечательно, но я нигде не вижу, чтобы из Singleton2 вызывался конструктор (NewInstance) Singleton1. А потом будем удивляться, почему код, добавленный Singleton1.NewInstance, не срабатывает для Singleton2. А как же наследование?


> Надеюсь, реализация метода TSingleton2.NewInstance развеет
> все сомнения по поводу нашей недавней дискуссии - стоит
> ли давать программисту возможность прямой работы с памятью,
>  или не стоит.


Отнюдь. Ведь может оказаться, что у нас даже нет исходников Singleton1, когда мы пишем Singleton2. Как же убедиться, что мы не пропустили ничего важного, что было в Singleton1.NewInstance? Конечно, мы можем надеяться, что в Singleton1.NewInstance нет ничего важного, потому что опытный разработчик этого класса вынес все важное в новый (желательно virtual) метод DoInit, но я бы на это не надеялся :)

Кстати, указанная проблема есть не только в Delphi, поэтому с некоторых пор я считаю singleton антипаттерном. Сервис типа SingletonFactory.getInstance() был бы гораздо лучше, особенно учитывая, что он может вернуть вовсе не Singleton1, а какой-нибудь Singleton2. А Singleton2Factory.getInstance()  - и вовсе Singleton359 :)


 
Romkin ©   (2013-04-23 11:13) [57]

Что тут спорить? уже сколько лет есть нормальный класс, он же и является синглетоном. Делайте конструктор класса, и все получится. Это оно и есть, синглетон :)


 
Владислав ©   (2013-04-23 11:13) [58]

var
 _Foo: TFoo = nil;


:= nil во всех вариантах лишнее.

А по сути любой вариант, кроме первого. В первом варианте объявление переменной внутри {$IFDEF SELF_INITIALIZE}. Это при каждом обращении к ней писать IFDEF? А что писать, если SELF_INITIALIZE не объявлено?
Я делал так, как в [51], и как в варианте с функцией, в зависимости от ситуации.


 
DVM ©   (2013-04-23 11:14) [59]


> Юрий Зотов ©   (23.04.13 11:10) [55]

Единственный недостаток - не потокобезопасно. Interlocked функции надо применить.


 
Компромисс1 ©   (2013-04-23 11:14) [60]


> Небольшая поправка к [51]. Хотя работает и без нее, но с
> нею лучше.


Надеюсь, реализация этого метода развеет все сомнения по поводу нашей недавней дискуссии - стоит ли давать программисту возможность ошибиться (или неоптимально сделать), или не стоит.

:)


 
DevilDevil ©   (2013-04-23 11:16) [61]

> Rouse_ ©   (23.04.13 10:43) [50]
>
> > Ega23 ©   (23.04.13 10:32) [49]
> Синглтон в данном случае ничем не мешает.


он мешает своим присутствием


 
DevilDevil ©   (2013-04-23 11:23) [62]

> Юрий Зотов ©   (23.04.13 10:52) [51]

а какой практический смысл перехвата NewInstance?
если избежать повторного выделения памяти - то получается не очень хорошо. Ибо Вы не вызываете InitInstance. А если вызовете - то возможны утечки памяти (если в экземпляре были строки/варианты/интерфейсы/массивы/сложные структуры)


 
Romkin ©   (2013-04-23 11:25) [63]


> Единственный недостаток - не потокобезопасно. Interlocked
> функции надо применить.

Любой синглетон изначально небезопасен.


 
Компромисс1 ©   (2013-04-23 11:28) [64]


> Любой синглетон изначально небезопасен.
>


Точно? Неужели нет безопасного способа на Delphi? :(

The Java programming language solutions provided here are all thread-safe but differ in supported language versions and lazy-loading. Since Java 5.0, the easiest way to create a Singleton is the enum type approach, given at the end of this section.

http://en.wikipedia.org/wiki/Singleton_pattern


 
DVM ©   (2013-04-23 11:30) [65]


> Romkin ©   (23.04.13 11:25) [63]


> Любой синглетон изначально небезопасен.

Что значит изначально? Все зависит от того, как написать его реализацию.
Опасное место всегда одно и то же - проверка наличия экземпляра - создание экземпляра, все остальное вторично.


 
DVM ©   (2013-04-23 11:32) [66]


> Компромисс1 ©   (23.04.13 11:28) [64]


> Точно? Неужели нет безопасного способа на Delphi? :(

Есть конечно, посмотрите например класс TEncoding как там создаются стандартные кодировки, которые и есть синглтоны по сути.


 
DVM ©   (2013-04-23 11:33) [67]


> DVM ©   (23.04.13 11:32) [66]

class function TEncoding.GetUTF8: TEncoding;
var
 LEncoding: TEncoding;
begin
 if FUTF8Encoding = nil then
 begin
   LEncoding := TUTF8Encoding.Create;
   if InterlockedCompareExchangePointer(Pointer(FUTF8Encoding), LEncoding, nil) <> nil then
     LEncoding.Free;
 end;
 Result := FUTF8Encoding;
end;


 
Компромисс1 ©   (2013-04-23 11:35) [68]

DVM ©   (23.04.13 11:33) [67]

Спасибо.


 
Romkin ©   (2013-04-23 11:38) [69]


> > Точно? Неужели нет безопасного способа на Delphi? :(Есть
> конечно, посмотрите например класс TEncoding как там создаются
> стандартные кодировки, которые и есть синглтоны по сути.
>

Я имел в виду что надо "ручками" защищать. А Java нам не указ, в Parallel Fortran, если память не изменяет, вообще можно цикл по потокам распихать.


 
_oxffff   (2013-04-23 11:41) [70]

И уносит кого и уносит кого в блестящую снежную даль.....


 
Romkin ©   (2013-04-23 11:43) [71]

Во-во. Уже несется. Отсюда простой вердикт: оба способа в корзину, делайте класс и не спорьте :)


 
Компромисс1 ©   (2013-04-23 11:48) [72]


> Я имел в виду что надо "ручками" защищать. А Java нам не
> указ, в Parallel Fortran, если память не изменяет, вообще
> можно цикл по потокам распихать.
>


Давайте еще GPSS вспомним :)
Извините, если что, я просто на Delphi и Java примерно одинаковое время работал, поэтому обычно их и сравниваю.


 
Romkin ©   (2013-04-23 12:40) [73]

Во, нашел демонстрашку синглетона на 2010.

type
 EManagerError = class(Exception);

 TFoo = class(TObject)
 public
   class function GetName: string; virtual;
   constructor Create; virtual;
 end;

 TFooClass = class of TFoo;

 TFooManager = class
 strict private
   class var FFooList: TDictionary<string, TFooClass>;
   class destructor Done;
 public
   class function RegisterFoo(AFoo: TFooClass; const Key: string): boolean;
   class function GetFoo(Key: string): TFooClass;
   class function CreateFoo(Key: string): TFoo;

 end;


 
Компромисс1 ©   (2013-04-23 12:42) [74]

Это мультитон, не синлтон. Для каждого key свой экземпляр.


 
Ega23 ©   (2013-04-23 12:53) [75]

Где-ж это синглтон-то? кто мне мешает стопицот экземпляров создать?


 
_oxffff   (2013-04-23 13:02) [76]

три белых коня ....


 
брат Птибурдукова   (2013-04-23 13:07) [77]

Саня, в твоей статье на хабре СТОЛЬКО опечаток… :-(


 
Romkin ©   (2013-04-23 13:11) [78]


> Где-ж это синглтон-то? кто мне мешает стопицот экземпляров
> создать?

TFooManager - синглетон. Ну можешь развлечься созданием экземпляров, конструктор в приват я не убирал. Но это ничего не изменит :)


 
Компромисс1 ©   (2013-04-23 13:16) [79]

Romkin ©   (23.04.13 13:11) [78]

В таком случае любой класс, в котором только class functions и нет instance functions, можно назвать singleton. Хотя можно назвать и utility class, если даже создавать экземпляры необязательно :)


 
Romkin ©   (2013-04-23 13:22) [80]


> В таком случае любой класс, в котором только class functions
> и нет instance functions, можно назвать singleton. Хотя
> можно назвать и utility class, если даже создавать экземпляры
> необязательно :)

Естественно. Если что-то ведет себя как синглетон, то это синглетон и есть :)



Страницы: 1 2 3 4 5 6 7 вся ветка

Текущий архив: 2013.10.06;
Скачать: CL | DM;

Наверх




Память: 0.65 MB
Время: 0.02 c
15-1367267405
Юрий
2013-04-30 00:30
2013.10.06
С днем рождения ! 30 апреля 2013 вторник


2-1358417243
Pcrepair
2013-01-17 14:07
2013.10.06
Замена указателей на Локал.Перем при работе функции в потоке


15-1366883286
О-Сознание
2013-04-25 13:48
2013.10.06
Наглядная настройка параметров.


2-1358341960
McLotos
2013-01-16 17:12
2013.10.06
Разбросать результат SQL-запроса по переменным


4-1267109067
davinchi
2010-02-25 17:44
2013.10.06
Отслеживание обращений к файловой системе?