Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2013.10.06;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.63 MB
Время: 0.013 c
4-1267109067
davinchi
2010-02-25 17:44
2013.10.06
Отслеживание обращений к файловой системе?


15-1366925402
Юрий
2013-04-26 01:30
2013.10.06
С днем рождения ! 26 апреля 2013 пятница


15-1366917087
О-Сознание
2013-04-25 23:11
2013.10.06
VCL построена на "сигналах-слотах"?


15-1366947804
Genry_
2013-04-26 07:43
2013.10.06
Oracle between


2-1358420049
Burn
2013-01-17 14:54
2013.10.06
try..except





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский