Форум: "Прочее";
Текущий архив: 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.021 c