Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Процедуры и функции как метод класса, или...


Автор: Pcrepair 3.9.2013, 15:20
Добрый день. Есть программа, которая использует потоки (потомок TTread)
Код потока состоит из множества функций и процедур, которые в настоящий момент прописаны как методы класса
и все работает как предначертано.

Для улучшения восприятия кода(и удаления повторов кода Ф и П) в принципе можно вынести процедуры и функции в отдельный модуль
(подключив CoInitialize(nil); код CoUninitialize; с учетом вызова подпрограмм из потоков)

Вопрос: как правильно сделать? оставить подпрограммы методами классса или вынести в отдельный модуль? наверняка есть какието косяки

Автор: Illusion Dolphin 3.9.2013, 15:51
Цитата

в отдельный модуль
(подключив CoInitialize(nil); код CoUninitialize; с учетом вызова подпрограмм из потоков)

CoInitialize/CoUninitialize лучше делать в потоке, имхо

Цитата

ставить подпрограммы методами классса или вынести в отдельный модуль?

Зависит от логики. Если классы большие то лучше разбивать.

Автор: Poseidon 3.9.2013, 16:05
Цитата(Pcrepair @  3.9.2013,  15:20 Найти цитируемый пост)
как правильно сделать? оставить подпрограммы методами классса или вынести в отдельный модуль?
Если все сделано правильно, то оба варианта имеют право на существование. Но если мы бьемся за улучшение восприятия кода, то лучше (на мой взгляд) все подпрограммы, которые связаны с работой нити, оставить в методах нити.

Автор: Pcrepair 3.9.2013, 19:17
вопрос был: наверняка есть какието косяки???

так значит, косяков нет? 
просто обложить вызов процедуры CoInitialize(nil); CoUninitialize;(ну там используется АКтивХ и вызов Mlang.dll), а если нет АктивХ то можно обойтить и без(если компиллятор не скажет что нужно)

ту кое кто кое где утверждал идею о том что лучше чтоб все подпрограммы были методами класса

другие же утверждают: неважно где лежит подпрограмма, важно откуда она вызывается, что входит в противоречие с первым высказыванием

кто имеет опыт по этому вопросу?

Автор: Illusion Dolphin 3.9.2013, 21:08
Если работа идёт с ActiveX то каждый поток должен вызвать CoInitialize до работы с АКтивХ  и CoUninitialize после. Это лучше оставить в потоке, избавив функции он необходимости "думать" о том, стоит или не стоит делать CoInitialize. Остальное можно (<> нужно) выносить в любый другие модули. Конкретное решение о выносе кода принимается исходя из личного опыта и архитектуры программы, логики кода. 

Автор: Poseidon 4.9.2013, 07:41
Цитата(Pcrepair @ 3.9.2013,  19:17)
ту кое кто кое где утверждал идею о том что лучше чтоб все подпрограммы были методами класса

другие же утверждают: неважно где лежит подпрограмма, важно откуда она вызывается, что входит в противоречие с первым высказыванием

Первые правы в плане организации кода. Хотя тут конечно, как говорится, "на вкус и цвет...", но в большинстве своем гораздо удобнее когда код, с которым работает класс, является методом этого класса, а не лежит абы где и не понятно кто там еще его использует. 

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

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

Автор: Pcrepair 4.9.2013, 13:44
Цитата(Illusion Dolphin @ 3.9.2013,  21:08)
Если работа идёт с ActiveX то каждый поток должен вызвать CoInitialize до работы с АКтивХ  и CoUninitialize после.

что это значит? сейчас так:

Код

(*тут организация класса потока*)
implementation

function TLoader.LoadURL(const AUrl: String):string;
var
ServerCharset:string;
Buffer: RawByteString;
Lst:TStringList;
begin
  FIdHttp := TIdHTTP.Create(nil);                   (*создаем загрузчик*)
  FSSL := TIdSSLIOHandlerSocketOpenSSL.Create;      (*создаем секретный сокет*)
  FStream := TMemoryStream.Create;
  Lst:=TStringList.Create;
  try
    try
      FIdHttp.IOHandler:=FSSL;                
      (*---------настройка параметров закачки-----------*)
      FIdHttp.Request.UserAgent:=GetRandomUserAgent;
      FIdHttp.ConnectTimeout:=10000;
      FIdHttp.ReadTimeout:=10000;
      FIdHttp.HandleRedirects:=True;
      FIdHttp.Request.Connection :='keep-alive';
      FIdHttp.HTTPOptions:=FIdHttp.HTTPOptions+[hoNoParseMetaHTTPEquiv];
      FIdHttp.Get(AUrl,FStream);     
      FStream.Position:=0;            
      Lst.LoadFromStream(FStream);
      Buffer:=Lst.Text;

      CoInitialize(nil);                (*вызов нужен для использования в потоке СОМ-объектов*)
        Result:=DelJS(CodePageConvert(Buffer));
      CoUninitialize;

    except
      Result:=AnsiLowerCase(AUrl+(' = Total Error'));
      if (FIdHttp.Response.ResponseCode = 200)
      then
      Push(AUrl);                               
      Exit;                                          
    end;
  finally
    FreeAndNil(FIdHttp);
    FreeAndNil(FSSl);
    FreeAndNil(FStream);
    FreeAndNil(Lst);
  end;
end;


function TLoader.CodePageConvert(const Page:RawByteString):string;
var Charset: Cardinal;
begin
  try
    Charset := DetectHTMLCharset(Page);  (*это уже в отдельном модуле вне класса и работает с Mlang.dll*)
  except
    Charset:=1251;
  end;
  Result:= AnsiLowerCase(RawHTMLToHTML(Page, Charset));  (*это уже в отдельном модуле вне класса и работает с Mlang.dll*)
end;

то есть CoInitialize - CoUninitialize обложено только вызов функции использующей АктивХ
есть какие то другие варианты?

Автор: Illusion Dolphin 4.9.2013, 14:35
Если TLoader это поток, то это значит, что можно сделать так:

Код

TLoader.Execute;
begin
  CoInitialize(nil);
  try
    // тут всё остальное, в том числе LoadURL итд и это можно вынести куда угодно забыв про CoInitialize/CoUninitialize
  finally
    CoUninitialize;
  end;
end;


В таком случае если функции АктивХ вызываются несколько раз не тратятся ресурсы за поднятие и остановку АктивХ. В таком случае всё остальное можно вынести в другие модули и забыть об инициализации и остановке АктивХ. 

P.S. Возможны проблемы если АктивХ должен быть инициализирован по-разному (см. CoInitializeEx) для разных функций, а если всем хватает обычного CoInitialize от и нет проблем.

Автор: Pcrepair 4.9.2013, 18:08
теперь стало понятнее. спасибо

Автор: mes 4.9.2013, 21:21
Цитата(Poseidon @  4.9.2013,  06:41 Найти цитируемый пост)
Поэтому лично мен мнение - класс должен быть единым целым и его составляющие должны быть внутри его

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)