Тема открыта по просьбе жителей Королевства и посвящена обсуждению вопросов оптимизации кода. Выставляйте свои лучшие и худшие тексты и не стесняйтесь их обсуждать. В споре рождается истина. Или, по крайней мере, оптимизация.
Всего в теме 737 сообщений
Добавить свое сообщение
Отслеживать это обсуждение
- Тестирование проекта. Отладка.
- Подводные камни
- Централизованная обработка ошибок
- Бета-тестирование
- Давайте учиться на ошибках.
- Почему программисты допускают ошибки?
- Автоматизированные тесты для GUI
- О системах контроля ошибок
№ 437 02-06-2008 02:51 | |
Ответ на »сообщение 435« (Ins)
___________________________
Первый паттерн - это классовая ссылка + виртуальный конструктор.
Только сейчас заметил, что здесь ошибка. Factory Method предполагает, что реальный тип создаваемого объекта определяется внутри метода. А если вы уже вызвали виртуальный конструктор, то все, поздно. Тип объекта жестко определен и поменять его нельзя.
№ 436 02-06-2008 02:49 | |
Ответ на »сообщение 434« (Бел Амор)
___________________________
Ну, в данном случае это легко исправляется путём замены явного указания класса на неявный Self... :)
Так вот вас и спрашивают: зачем вам пусть и неявный, но неиспользуемый параметр?
Ответ на »сообщение 435« (Ins)
___________________________
Первый паттерн - это классовая ссылка + виртуальный конструктор. Второй реализуется с помощью перекрывания виртуальных NewInstance/FreeInstance, а единственной точкой входа по прежнему может оставаться конструктор. Встречный вопрос, а чем в реализации данных паттернов нам помогут class static методы? :)
Если Delphi - единственный возможный язык в вашей организации (или у вас, как индивидуального разработчика), то конечно.
Просто мне бы хотелось видеть решения, которые без особых усилий можно переписать на C#, Java, Python.
№ 435 02-06-2008 01:57 | |
Ответ на »сообщение 433« (panda)
___________________________
И как тогда правильно реализовывать паттерны Factory Method и Singleton без class/static методов?
Насколько я понял, в контексте речь шла только о замене классовыми методами отдельно лежащих функций, которые в данном случае обычно выступают как class static - не используют Self. "Не размазывать логику по юниту" - это может являться оправданием такого подхода, но у него есть и обратная сторона - перегрузка класса дополнительными сущностями, которые по сути к классу могут иметь весьма косвенное отношение. Что касается того, как реализовать Factory Method и Singletone - а зачем здесь в класс добавлять классовые методы, которые используются как статические? Первый паттерн - это классовая ссылка + виртуальный конструктор. Второй реализуется с помощью перекрывания виртуальных NewInstance/FreeInstance, а единственной точкой входа по прежнему может оставаться конструктор. Встречный вопрос, а чем в реализации данных паттернов нам помогут class static методы? :)
Ответ на »сообщение 434« (Бел Амор)
Понимаете в чем была проблема... Вы же сами пишите, что удаляете переменную типа форма, чтобы не использовать ее внутри методов, а использовать вместо этого Self. Это правильно (не в смысле "удалять", а в смысле "использовать Self") В случае с классовым методом - все должно быть симметрично. Разница лишь в том, что классовый метод работает с классом, а не с экземпляром. Если вы отказываетесь от работы с конкретным экземпляром внутри instance-метода, то почему вы не отказываетесь работать с конкретным классом внутри class-метода? В общем, моя претензия была только в этом, у меня нет претензий к классовым методам как таковым, если они не class static. Просто вы намеренно объявили процедуру именно как метод, подчеркнули это, но не воспользовались тем различием, что существует между методом и обычной процедурой.
№ 434 02-06-2008 01:10 | |
Ответ на »сообщение 433« (panda)
___________________________
>>> А вот неиспользование переданного параметра - это уже серьезный признак "дурно пахнущего" ((c) М. Фаулер) кода.
Ну, в данном случае это легко исправляется путём замены явного указания класса на неявный Self... :)
class function TForm2.ChooseAbon(Mask: String; Field: TField): Boolean;
begin
with Create(nil) do
begin
Result := (ShowModal = mrOk);
if Result then
Field.AsInteger := Query1.FieldByName('ID').AsInteger;
Free;
end;
end;
№ 433 01-06-2008 23:33 | |
Ответ на »сообщение 428« (Ins)
___________________________
Хех :) А чем в приведенном случае классовый метод принципиально лучше, чем простая функция, не классовая и не метод?
Если процедура спроектирована так, чтобы работать только с одним классом, то помещение метода в этот класс уменьшит размазывание логики по программе.
Ответ на »сообщение 430« (Антон Григорьев)
___________________________
Это всё - следствие того влияния, которое оказвют на программирование неряшливы спроектированные C++ и C#. Там действительно класс нагружен совершенно несвойственной ему функцией - быть пространством имён.
Э... почему это? И как тогда правильно реализовывать паттерны Factory Method и Singleton без class/static методов?
Классовый метод имеет неявный параметр Self, через который ему передаётся ссылка на класс. Соответственно, при каждом вызове метода тратится дополнительное процессорное время и дополнительная память на передачу параметра, который потом не используется. Оно вам надо?
Если процессорное время в данном случае настолько критично, то надо переходить с Delphi на "более другой" язык.
А вот неиспользование переданного параметра - это уже серьезный признак "дурно пахнущего" ((c) М. Фаулер) кода.
№ 432 01-06-2008 09:04 | |
Ответ на »сообщение 431« (Бел Амор)
___________________________
Этот подход используется только при показе форм. При этом потеря такого количества времени совершенно некритична.
Это понятно. Но на мой взгляд смысл использования классового метода в приведенном примере притянут за уши. Достаточно трудно сформулировать общие рекомендации по использованию классовых методов, ситуации могут быть разными, боюсь, у меня это не получится. Но чисто мое субъективное мнение, что классовые методы по настоящему полезны тогда, когда они не повторяют поведение статик-методов из .NET или Java, а когда для них включается и начинает работать полиморфизм. Т.е. иерархия подразумевает наличие у класса потомков, чье поведение может отличаться, и к которым клиент обращается через интерфейс базового класса, имея на руках классовую ссылку:
type
TShape = class(...)
public
class function ClassAlias: String; virtual; abstract;
end;
TShapeClass = class of TShape;
TLine = class(TShape)
...
TRect = class(TShape)
...
...
procedure RegisterShape(ShapeClass: TShapeClass);
begin
RegisterClassAlias(ShapeClass, ShapeClass.ClassAlias);
end;
№ 431 31-05-2008 13:46 | |
Ответ на »сообщение 430« (Антон Григорьев)
___________________________
Классовый метод имеет неявный параметр Self, через который ему передаётся ссылка на класс. Соответственно, при каждом вызове метода тратится дополнительное процессорное время и дополнительная память на передачу параметра, который потом не используется. Оно вам надо?
Этот подход используется только при показе форм. При этом потеря такого количества времени совершенно некритична.
Классовый метод не может иметь доступа ко всем членам класса, потому что он не привязывается ни к какому объекту и не имеет ссылки Self (точнее, Self у него есть, но это ссылка на класс, а не на объект). Соответственно, к скрытым методам вы можете обращаться только если передали явно указатель на объект. И тут возникает вопрос: а этот метод точно должен быть классовым? Может, его проще сделать обычным?
Речь шла о применении классовх методов в контексте замены часто применяемой последовательности Create-ShowModal-Free на вызывающей стороне на всё то-же самое внутри классового метода. Объект создаётся внутри этого метода и речь шла о доступе к членам именно этого объекта. Продемонстрирую это примером из »вопрос КС №57348« Там как раз зашла речь о классовых методах. unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, DBTables, StdCtrls, Grids, DBGrids;
type
TForm2 = class(TForm)
DBGrid1: TDBGrid;
btnOk: TButton;
btnCancel: TButton;
Edit1: TEdit;
DataSource1: TDataSource;
Query1: TQuery;
public
constructor Create(AOwner: TComponent); override;
class function ChooseAbon(Mask: String; Field: TField): Boolean;
end;
implementation
constructor TForm2.Create(AOwner: TComponent);
begin
inherited;
end;
class function TForm2.ChooseAbon(Mask: String; Field: TField): Boolean;
begin
with TForm2.Create(Application) do
begin
Result := (ShowModal = mrOk);
if Result then
Field.AsInteger := Query1.FieldByName('ID').AsInteger;
Free;
end;
end;
end. Вызов: TForm2.ChooseAbon('Сидоров', Table1.FieldByName('AbonId')); Чем плох этот вариант? Python в том вопросе привёл свой вариант. Как бы сделали вы?
>>> Когда есть навыки работы с процедурами, такие вопросы тоже не возникают.
Ну почему сразу "отсутствие навыков работы с процедурами"? Хотим мы этого или не хотим, но в основном работа идёт с классами, и когда через некоторое время "после того, как...", встречается код: procedure TForm1.Button1Click(Sender: TObject);
begin
ChooseAbon('Сидоров', Table1.FieldByName('AbonId'));
end; ...то первая мысль - это "ChooseAbon - метод класса TForm1"...
Между тем, процедурное программирование тоже имеет свои сильные стороны, и надо не фанатично держаться за один подход, а в зависимости от ситуации использовать то или это.
Согласен...
№ 430 31-05-2008 12:20 | |
Ответ на »сообщение 429« (Бел Амор)
___________________________
Действительно, сейчас я использую классовые методы в основном как замену отдельнолежащим функциям. В этом контексте нет большой разницы что именно использовать, но мне классовые методы кажутся более удобными.
Это всё - следствие того влияния, которое оказвют на программирование неряшливы спроектированные C++ и C#. Там действительно класс нагружен совершенно несвойственной ему функцией - быть пространством имён.
1. Функция входит в состав класса и не вносит неоднородности. Всё объявлено в одном месте.
Классовый метод имеет неявный параметр Self, через который ему передаётся ссылка на класс. Соответственно, при каждом вызове метода тратится дополнительное процессорное время и дополнительная память на передачу параметра, который потом не используется. Оно вам надо?
2. Метод имеет доступ ко всем членам класса. Хотя доступ к закрытым членам в таких случаях требуется крайне редко, но тем не менее... И хотя в пределах модуля и действует полная видимость, но такой доступ из не-метода не очень красив. Кроме того, сейчас есть ключевое слово strict...
Классовый метод не может иметь доступа ко всем членам класса, потому что он не привязывается ни к какому объекту и не имеет ссылки Self (точнее, Self у него есть, но это ссылка на класс, а не на объект). Соответственно, к скрытым методам вы можете обращаться только если передали явно указатель на объект. И тут возникает вопрос: а этот метод точно должен быть классовым? Может, его проще сделать обычным?
3. При вызове не возникает вопросов "это метод или что?", "А где это объявлено?"
Когда есть навыки работы с процедурами, такие вопросы тоже не возникают.
Если указывать ещё и модуль, то нет большой разницы - указывать модуль или класс, и тогда вступает в силу пункт 1.
Во-во, именно это я и имел ввиду, когда говорил о том, что классу придают несвойственные ему функции пространства имён. Вообще, всё это следствие моды на ООП, всё засунуть в объекты - это типа хорошо (Java и C# - жертвы такой моды). Между тем, процедурное программирование тоже имеет свои сильные стороны, и надо не фанатично держаться за один подход, а в зависимости от ситуации использовать то или это.
№ 429 31-05-2008 11:37 | |
Ответ на »сообщение 428« (Ins)
___________________________
Хех :) А чем в приведенном случае классовый метод принципиально лучше, чем простая функция, не классовая и не метод?
Действительно, сейчас я использую классовые методы в основном как замену отдельнолежащим функциям. В этом контексте нет большой разницы что именно использовать, но мне классовые методы кажутся более удобными.
1. Функция входит в состав класса и не вносит неоднородности. Всё объявлено в одном месте.
2. Метод имеет доступ ко всем членам класса. Хотя доступ к закрытым членам в таких случаях требуется крайне редко, но тем не менее... И хотя в пределах модуля и действует полная видимость, но такой доступ из не-метода не очень красив. Кроме того, сейчас есть ключевое слово strict...
3. При вызове не возникает вопросов "это метод или что?", "А где это объявлено?" Если указывать ещё и модуль, то нет большой разницы - указывать модуль или класс, и тогда вступает в силу пункт 1.
А в принципе, вы правы, здесь есть над чем подумать...
№ 428 31-05-2008 06:38 | |
Ответ на »сообщение 427« (Бел Амор)
___________________________
12. Вместо отдельнолежащих процедур часто удобно использовать классовые методы (см. class methods) Пример использования можно посмотреть здес: »вопрос КС №50002« (class function CheckPassword: Boolean).
Хех :) А чем в приведенном случае классовый метод принципиально лучше, чем простая функция, не классовая и не метод?
function CheckPassword: Boolean;
begin
with TCheckPasswordForm.Create(Application) do
begin
AllowTryCount := 3;
Result := (ShowModal = mrOK);
Free;
end
end;
Это я к тому, что классовая функция - это прежде всего метод класса, а это значит, что ей передается в качестве параметра ссылка на класс, для которого он выполняется. Если этот параметр внутри функции никак не используется (явно или неявно), то смысла делать функцию классовой мало. Вот если бы у вас было как-нибудь так:
TPasswordFormClass = class of TCheckPasswordForm;
class function TCheckPasswordForm.CheckPassword: Boolean;
begin
with TPasswordFormClass(Self).Create(Application) do
begin
AllowTryCount := 3;
Result := (ShowModal = mrOK);
Free;
end
end;
То это бы в корне меняло дело :) Тогда от такой формы можно было бы и потомков породить, а клиент мог бы обращаться к ним через интерфейс класса TCheckPasswordForm
А еще классовые методы крайне полезны, когда они виртуальные. Эх, еще бы классовые конструкторы в язык добавить - точно не помешало бы... :)
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|