ООП vs процедурное программирование - страница 10

 
Реter Konow:
Да, в этих блоках есть и то и другое. Но поверьте, - они сжаты до максимума и универсальны, потому что решают широкий спектр задач.

Если всего вариантов немного то можно обойтись ифами и свичами.

 

А почему так никто и не решил поспорить на тему "процедурное программирование с указателями на фунции против процедурного программирование без указателей на функции"?

 
Dmitry Fedoseev:

Если всего вариантов немного то можно обойтись ифами и свичами.

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

Реter Konow:
1. Дело в работе которую нужно провести чтобы сжать в коде решения огромного количества задач.

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


1. Зачем проводить эту работу, если можно сделать легок и просто? Зачем делать сложно то, что можно сделать легко?

2. Если использовать ООП, то универсализация не губительна, а становится естественной ничего не обременяющей возможностью.

 
Dmitry Fedoseev:

1. Зачем проводить эту работу, если можно сделать легок и просто? Зачем делать сложно то, что можно сделать легко?

2. Если использовать ООП, то универсализация не губительна, а становится естественной ничего не обременяющей возможностью.

Мы можем долго продолжать этот спор. На примере задачи 100 трейлингов, я показал свое отношение к такому методу решений. Считаю, что глупо поставленные задачи не должны решаться, а должны исправлятся. Если ООП помогает тем, кто слабее в умении правильно ставить и эффективно решать свои задачи, - то пусть он им и дальше помогает. Но для людей которые задачи оптимизируют еще до начала их решения, ООП может просто не понадобится.

 
Реter Konow:

Мы можем долго продолжать этот спор. На примере задачи 100 трейлингов, я показал свое отношение к такому методу решений. Считаю, что глупо поставленные задачи не должны решаться, а должны исправлятся. Если ООП помогает тем, кто слабее в умении правильно ставить и эффективно решать свои задачи, - то пусть он им и дальше помогает. Но для людей которые задачи оптимизируют еще до начала их решения, ООП может просто не понадобится.


Вы мало кодили (наверно), ООП это как глоток воздуха.

В основном люди кодят не для интереса и не с целью саморазвития, а работа у них такая, и на этой работе важен результат.

 
Dmitry Fedoseev:

По удобству не стоит рядом, но по возможностям обеспечения быстродействия - можно обойтись одними указателями. 

А удобство - понятие относительное.


Дмитрий, конечно использоваие ООП немного снижает быстродействие. Но это доли процента.

Зато как ООП повышает производительность программера!

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

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

Для примера, берем .NET, там же все API состоит из классов.

Мне парадигма .NET очень нравится, кстати, есть отличный терминал cAlgo, там можно напрямую писать в Visuaд Studio на C#

 
Alexey Volchanskiy:

Дмитрий, конечно использоваие ООП немного снижает быстродействие. Но это доли процента.

Если малое количество вариантов,то снизит, но если очень много, будет преимущество.

Самое важное, в ООП от количества вариантов не зависит быстродействие. А в процедурном программировании над головой потолок.

 

Ну, наворотили...

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

Вопрос - в удобстве и эффективности поддержки.

В МТ - наиболее ООП-подходящим местом является ордерная система. Лично у меня есть виртуальные интерфейсы "позиции" и  "компоненты позиции". "Позиция" - это набор ордеров в МТ4 или набор позиций МТ5. "Компонента позиции" - это отдельный ордер или отдельная МТ5-позиция (хеджевая или неттинговая).

Вот реальный файл интерфейса (Реter Konow, можешь оценить количество комментариев по сравнению с объемом кода, причем, я периодически их  туда добавляю, когда сталкиваюсь с тем, что некоторые тонкости не помню. Скажем, я регулярно забываю, какие реальные объекты представляют из себя "компоненту позиции". Мне это просто не надо помнить - эксперт работает с компонентами согласно интерфейсу, а что там в реальности стоит за этим интерфейсом - неважно. Но, при модификации к этому приходится возвращаться - поэтому мне первый комментарий в этом файле очень часто требуется):

// СTradePositionI переносимый интерфейс торговой позиции 

// Позиция состоит из компонент-наследников интерфейса CTradePosComponentI
// 
// Реально для МТ4 имплементацией интерфейса является объект CMT4PositionInfo, для МТ5 - объект CMT5PositionInfo
// CMT4PositionInfo представляет из себя массив объектов CMT4OrderInfo, наследников интерфейса CTradePosComponentI.
// Фактически это массив МТ4-ордеров.
// CMT5PositionInfo представляет из себя массив объектов CMT5PositionInfoCore, наследников интерфейса CTradePosComponentI.
// Объект CMT5PositionInfoCore не имеет прямого аналога в МТ5-терминах, это два массива ордеров и сделок, а также структура данных,
// имеющуая идентификатор позиции (m_lPosID или POSITION_IDENTIFIER), тикет магик, вид позиции, и так далее, по аналогии с МТ4-ордером,
// фактически, массивы ордеров и сделок - это аналоги ордеров и сделок обычной неттинговой МТ5-позиции, а структура данных - относится
// к хеджевой позиции, и имеет аналог МТ4-ордера. 
//
// Реально при запросе у позиции компоненты CTradePosComponentI в МТ4 мы получаем указатель на ордер (класс CMT4OrderInfo),
// а в МТ5 - на ядро позиции (класс CMT5PositionInfoCore) 



#include <MyLib\DebugOrRelease\DebugSupport.mqh>
#include <MyLib\Common\MyObject.mqh>
#include <MyLib\Common\CurSymEnum.mq5>
#include <MyLib\Common\TrendEnums.mqh>
#include <MyLib\Trade\TradePosComponentI.mqh>

class CTradePositionI: public CMyObject
{
public:
   void CTradePositionI() {    SetMyObjectType(MOT_TRADE_POSITION_I); };
   virtual void ~CTradePositionI() {};
   
   // Выбор существующей позиции. 
   // Указывается магик и символ, по которому выбираются действующие ордера.
   // Если ulMagic = 0 - выбираются все позиции по всем магикам.
   // Если ECurrencySymbol = CS_UNKNOWN - выбираются все позиции по всем символам
   // Если ECurrencySymbol = CS_CURRENT - запрашивается функция Symbol(), и выбираются все позиции по этому символу
   // Возвращает число компонент позиции внутри позиции (может быть нулевым если позиции нет) или WRONG_VALUE в случае ошибок
   // Каждая фабрика (наследник CEAPartsFactoryT) имеет одну позицию, которая на каждом CEAPartsFactoryT::OnRefresh()
   // обновляется в соответствии с магиком и рабочим символом фабрики. 
   virtual int Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT) = 0;

   virtual uint GetTotalComponents() const = 0;  // Получение общего числа компонент
   virtual uint GetNumOfComponentsOnDirection(ENUM_POSITION_TYPE etDirection) const = 0; // Получение числа компонент указанного направления (если tdDirection = TD_FLAT - то всех компонент)  и интерфейс отдельной компоненты
   virtual CTradePosComponentI* GetComponent(uint uiComponentIdx) const = 0;
   
   // Расширенный интерфейс
   
   // Функция исследует позицию, и возвращает ее направление:
   // Если все компоненты - лонги, то вверх.
   // Если все компоненты - шорты, то вниз.
   // Если компонент нет - то флет. 
   // Если компоненты обоих типов, то смотрим на флаг bFlatIfBoth. 
   // Если этот флаг установлен - то возвращаем флет.
   // Если этот флаг сброшен - то смотрим на флаг bConsiderVolume.
   // Если этот флаг установлен - то сравниваем общие объемы лонгов и шортов. Если сброшен - сравниваем количество лонгов и шортов.
   // Каких позиций (или объемов) больше - то направление и возвращаем. 
   // Если позиций (или объемов) одинаково - возвращаем флет.
   // NOTE !!! Функция не проверяет магик и символ компонент !
   virtual ETrendDirection GetDirection(bool bFlatIfBoth = true,bool bConsiderVolume = true) const = 0;
   
   // Функция ищет внутри позиции компоненту с указанным тикетом. 
   // В случае, если ее нет - возвращается false.
   // Если компонента найдена - возвращается true, и uiComponentIdx устанавливается на индекс компоненты внутри позиции.
   virtual bool FindComponentByTicket(long lTicket,uint &uiComponentIdx) const = 0;
};

Файл интерфейса торговой компоненты следующий (выше я его приводил уже, но повторю:

// СTradePositionComponentI переносимый интерфейс компоненты торговой позиции 

#include <MyLib\DebugOrRelease\DebugSupport.mqh>
#include <MyLib\Common\MyObject.mqh>
#include <MyLib\Common\CurSymEnum.mq5>
#include <MyLib\Common\EnumsMT5ForMT4.mqh>

// CTradePosComponentI - компонента позиции. Имеет определенный магик, определенный символ, определенный тикет.  
// Для МТ4 компонента позиции - это МТ4-ордер.
// Для МТ5 компонента позиции - это МТ5-позиция (одна для каждого символа при неттинге, и много для каждого символа при хедже).

class CTradePosComponentI: public CMyObject
{
public:
   void CTradePosComponentI() {    SetMyObjectType(MOT_TRADEPOS_COMPONENT_I); };
   virtual void ~CTradePosComponentI() {};
   
   // Основной интерфейс
   virtual long               GetTPCTicket()       const = 0;
   virtual long               GetTPCMagic()        const = 0;
   virtual ECurrencySymbol    GetTPCSymbol()       const = 0;
   virtual ENUM_POSITION_TYPE GetTPCType()         const = 0;
   virtual datetime           GetTPCOpenTime()     const = 0;
   virtual double             GetTPCVolume()       const = 0;
   virtual double             GetTPCOpenPrice()    const = 0;
   virtual double             GetTPCStopLoss()     const = 0;
   virtual double             GetTPCTakeProfit()   const = 0;
   virtual string             GetTPCCommentary()   const = 0;
   
   virtual bool               IsTPCInUnloss() const { if(GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE) return(false); if(GetTPCType() == POSITION_TYPE_BUY) { if(GetTPCStopLoss() >= GetTPCOpenPrice()) return(true); } else { if(GetTPCStopLoss() <= GetTPCOpenPrice())return(true); }; return (false); };
   virtual double             GetTPDistance() const { if(GetTPCTakeProfit() == 0 || GetTPCTakeProfit() == EMPTY_VALUE) return(EMPTY_VALUE); if(GetTPCType() == POSITION_TYPE_BUY) return(GetTPCTakeProfit() - GetTPCOpenPrice()); return(GetTPCOpenPrice() - GetTPCTakeProfit());  };
   virtual double             GetSLDistance() const { if(GetTPCStopLoss() == 0 || GetTPCStopLoss() == EMPTY_VALUE) return(EMPTY_VALUE); if(GetTPCType() == POSITION_TYPE_BUY) return(GetTPCOpenPrice()- GetTPCStopLoss()); return(GetTPCStopLoss() - GetTPCOpenPrice());  };
};

class CHistoryPosComponentI: public CTradePosComponentI
{
public:
   void CHistoryPosComponentI() {    SetMyObjectType(MOT_HISTORYPOS_COMPONENT_I); };
   virtual void ~CHistoryPosComponentI() {};

   virtual datetime           GetTPCCloseTime()    const = 0;
   virtual double             GetTPCClosePrice()   const = 0;
   virtual double             GetTPCProfit()       const = 0;  // Возвращает профит по исторической позиции
   
   virtual bool               IsProfitClosePrice() const = 0;   // Возвращает true, если цена зарытия отличается от цены открытия в прибыльную сторону   
   
   // Возвращает профит исторической позиции для случая, когда бы ход цены (в сторону профита) был бы равен dPriceMove, а лот был бы единичным.
   // Функция используется для расчета лота для такой же позиции с нужным ходом цены 
   // Рекомендуется отнимать от цены двойной спред.
   virtual double             CalculateOneLotProfit(double dPriceMove) const = 0;  
  
};

Согласно этим интерфейсам - у меня реализована и ордерная система МТ4, и МТ5, как для реальных, так и для исторических ордеров.

Эксперт, запросив позицию - получает данный интерфейс, и ему совершенно не надо учитывать разницу в работе с ордерами МТ4 и МТ5. Причем, если будет добавлен новый тип ордера, или изменится порядок работы с ними - для эксперта - ничего не изменится, добавится только класс нового типа ордера, который будет также поддерживать данный интерфейс.

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

Реter Konow, как у тебя решается вопрос с различием типов ордеров в МТ4 и МТ5  ?

Если будет введен новый тип счета (вдобавок к хеджевому и неттинговому) - какие изменения потребуется вносить, и в одном ли месте ?

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

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

 
George Merts:

Ну, наворотили...

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

Вопрос - в удобстве и эффективности поддержки.

2. В МТ - наиболее ООП-подходящим местом является ордерная система. Лично у меня есть виртуальные интерфейсы "позиции" и  "компоненты позиции". "Позиция" - это набор ордеров в МТ4 или набор позиций МТ5. "Компонента позиции" - это отдельный ордер или отдельная МТ5-позиция (хеджевая или неттинговая).

3. Вот реальный файл интерфейса (Реter Konow, можешь оценить количество комментариев по сравнению с объемом кода, причем, я периодически их  туда добавляю, когда сталкиваюсь с тем, что некоторые тонкости не помню. Скажем, я регулярно забываю, какие реальные объекты представляют из себя "компоненту позиции". Мне это просто не надо помнить - эксперт работает с компонентами согласно интерфейсу, а что там в реальности стоит за этим интерфейсом - неважно. Но, при модификации к этому приходится возвращаться - поэтому мне первый комментарий в этом файле очень часто требуется):

Файл интерфейса торговой компоненты следующий (выше я его приводил уже, но повторю:

Согласно этим интерфейсам - у меня реализована и ордерная система МТ4, и МТ5, как для реальных, так и для исторических ордеров.

Эксперт, запросив позицию - получает данный интерфейс, и ему совершенно не надо учитывать разницу в работе с ордерами МТ4 и МТ5. Причем, если будет добавлен новый тип ордера, или изменится порядок работы с ними - для эксперта - ничего не изменится, добавится только класс нового типа ордера, который будет также поддерживать данный интерфейс.

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

4. Реter Konow, как у тебя решается вопрос с различием типов ордеров в МТ4 и МТ5  ?

Если будет введен новый тип счета (вдобавок к хеджевому и неттинговому) - какие изменения потребуется вносить, и в одном ли месте ?

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

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

1. Полностью согласен. Разница только в эффективности решения задач тем или иным способом.

2. С ордерной системой работал мало, и технических проблем ее построения сейчас не вижу. Возможно они есть, но нужна конкретная задача, и тогда станет ясно насколько эффективно я могу решить ее без ООП.

3. Приведенный пример кода (с моей точки зрения) просто ужасен с точки зрения читабельности. Не удивительно, что требуется столько комментариев и почему ты забываешь его содержание. Прости, но это мое субъективное первое впечатление. Просто жуть какая то.

Вот пример читабельности моего кода - функция определяющая цвет детали элемента управления:

int Цвет_детали(int Окно, int Деталь_полотна, int Ячейка_состояния, int GAC = 0)
{
 int Alfa;
 int Цвет_детали;
 int Конечный_цвет;
 int Непрозрачность_детали;
 //--------------------------------------------------------------------------
 int Элемент                     =  G_CORE[Окно][Деталь_полотна][_MAIN_ELEMENT];
 int Состояние_детали            =  G_CORE[Окно][Элемент][_CURRENT_STATE]; 
 int Категория_детали            =  G_CORE[Окно][Деталь_полотна][_OBJECT_CATEGORY];
 int Подкатегория_детали         =  G_CORE[Окно][Деталь_полотна][_OBJECT_SUBCATEGORY];
 int Составной_элемент           =  G_CORE[Окно][Деталь_полотна][_OBJECT_IN_ELEMENT_NUMBER];
 int Тип_элемента                =  G_CORE[Окно][Деталь_полотна][_OBJECT_GROUP];
 int Тип_детали                  =  G_CORE[Окно][Деталь_полотна][_SUB_ELEMENT_GROUP];
 int Элемент_под_курсором        =  G_CORE[Окно][Элемент]       [_ELEMENT_POINTED];
 int Состояние_элемента          =  G_CORE[Окно][Элемент]       [_CURRENT_STATE];
 int Пиксель_детали              =  G_CORE[Окно][Деталь_полотна][_PIXEL_INDEX];
 int Канвас_детали               =  G_CORE[Окно][Деталь_полотна][_DROWING_CANVAS];
 int Пиксель_канваса_детали      =  G_CORE[Окно][Канвас_детали][_PIXEL_INDEX];
 int Состояние_канваса_детали    =  G_CORE[Окно][Канвас_детали][_CURRENT_STATE];
 int Ячейка_состояния_канваса    =  G_CORE[Окно][Канвас_детали][_NEUTRAL_STATE];
 //-------------------------------------
 int Цвет_пикселя_канваса_детали =  STANDART_GROUPS[Ячейка_состояния_канваса + 3 + Пиксель_канваса_детали*2];
 //-------------------------------------
 if(
       (Состояние_элемента == _NEUTRAL_BLOCKED || Состояние_элемента == _ACTIVATED_BLOCKED)
    && (Тип_элемента == BUTTON || Тип_элемента == TB_BUTTON || Тип_элемента == H_TAB || Тип_элемента == V_TAB || Тип_элемента == VIEW_BOX) 
   )
   {
    if(Тип_детали != _VIEW_BOX_VR_SCROLL_BAR && Тип_детали != _VIEW_BOX_HR_SCROLL_BAR)
      {
       Alfa = 255 + GAC;
       if(Alfa < 0)Alfa = 0;      
       return(ColorToARGB(Цвет_пикселя_канваса_детали,Alfa));
      }
    if(Тип_детали == _VIEW_BOX_VR_SCROLL_BAR || Тип_детали == _VIEW_BOX_HR_SCROLL_BAR)
      {
       Alfa = 255 + GAC;
       if(Alfa < 0)Alfa = 0;        
       return(ColorToARGB(clrLightGray,Alfa));
      }   
   }
 //-------------------------------------
 if(!Состояние_элемента)Состояние_элемента = _NEUTRAL_STATE;
 //-------------------------------------
 int Цвет_пикселя           = Данные_пикселя[Пиксель_детали][Цвет];
 int Непрозрачность_пикселя = Данные_пикселя[Пиксель_детали][Непрозрачность];
 //-------------------------------------
 if(G_CORE[Окно][Деталь_полотна][_CUSTOM_BACKGROUND_COLOR]  && Состояние_элемента == _NEUTRAL_STATE) 
   {
    Цвет_детали = G_CORE[Окно][Деталь_полотна][_CUSTOM_BACKGROUND_COLOR];
   } 
 //-------------------------------------
 if(!G_CORE[Окно][Деталь_полотна][_CUSTOM_BACKGROUND_COLOR] || Состояние_элемента != _NEUTRAL_STATE) 
   {
    Цвет_детали = Данные_пикселя[Пиксель_детали][Цвет];
   } 
 //-------------------------------
 if(G_CORE[Окно][Деталь_полотна][_ELEMENT_POINTED]) 
   {
    if(
          (ТИП_ЭЛЕМЕНТА ==  C_HEADER && МЕНЯЕМАЯ_ШИРИНА_СТОЛБЦОВ) 
       || (((Тип_элемента == _C_CELL || Тип_элемента == _D_CELL)   && G_CORE[Окно][Деталь_полотна][_R_HEADER] == РЯД_В_ФОКУСЕ) && ТАБЛИЦА_ИНТЕРАКТИВНА)
       || ((Тип_элемента == _CELL    || Тип_элемента ==  R_HEADER) && ТАБЛИЦА_ИНТЕРАКТИВНА)
      )
      { if(Тип_элемента == _C_CELL && ТАБЛИЦА_ИНТЕРАКТИВНА)Alert(__FUNCTION__,"  Деталь_полотна   ",Деталь_полотна);
       Цвет_детали = C'210,224,237';
      }
    //------------------------------------------------
    if(ТИП_ЭЛЕМЕНТА == _SIMPLE_BUTTON)if(Состояние_элемента == _NEUTRAL_STATE)Цвет_детали = C'250,250,250';
    //------------------------------------------------ 
    if(ТИП_ЭЛЕМЕНТА == TS_BUTTON)
      {
       Цвет_детали =  C'210,224,237';
       Непрозрачность_детали = 100;
       Alfa = Непрозрачность_детали + GAC;
       if(Alfa < 0)Alfa = 0;    
       Конечный_цвет = ColorToARGB(Цвет_детали,Alfa);
       //--------------------------------------------------------------------------
       return(Конечный_цвет);
      } 
    //------------------------------------------------  
    if(Тип_элемента == M_CHECKBOX)
      {
       Цвет_детали = C'210,224,237';
      }
    //------------------------------------------------ 
   }    
 //--------------------------------------------------------------------------
 if(!G_CORE[Окно][Деталь_полотна][_CUSTOM_BACKGROUND_TRANSPERANCY]) Непрозрачность_детали = Данные_пикселя[Пиксель_детали][Непрозрачность];
 else Непрозрачность_детали = G_CORE[Окно][Деталь_полотна][_CUSTOM_BACKGROUND_TRANSPERANCY];
 //--------------------------------------------------------------------------
 if(
       Тип_детали == CHECKBOX 
    || Тип_детали == RADIO_BUTTON 
    || Тип_детали == DROP_LIST 
    || Тип_детали == EDIT_BOX 
    || Тип_детали == SPIN_EDIT 
    // 
    ||((/*Тип_детали == TV_ITEM ||*/Тип_детали == TV_CHECKBOX
    || Тип_детали == G_FOLDER
    || Тип_детали == TV_MENU)  && (Составной_элемент == BASE_SUB_ELEMENT || (Составной_элемент == BASE_SUB_ELEMENT_2 && Состояние_детали != _ACTIVATED_HIGHLIGHTED && Состояние_детали != _NEUTRAL_HIGHLIGHTED)))
   )
   {
    Цвет_детали = Цвет_пикселя_канваса_детали;  
    Непрозрачность_детали = 255;
   }
 //--------------------------------------------------------------------------
 //Определение цвета ползунка на различных событиях.
 //--------------------------------------------------------------------------
 if(Категория_детали == _SCROLL_BAR_HANDLE && ((КАТЕГОРИЯ_ОБЪЕКТА == _SCROLL_BAR_HANDLE || КАТЕГОРИЯ_ОБЪЕКТА == _SCROLL_BAR || КАТЕГОРИЯ_ОБЪЕКТА == _SCROLL_BAR_BUTTON) || СОБЫТИЕ_ИНТЕРФЕЙСА == _SCROLLER_EVENT))
   {
    if((КАТЕГОРИЯ_ОБЪЕКТА == _SCROLL_BAR_HANDLE && Деталь_полотна == ОБЪЕКТ) || (СОБЫТИЕ_ИНТЕРФЕЙСА == _SCROLLER_EVENT && Подкатегория_детали == _VERTICAL_SCROLL_BAR_HANDLE))
      {
       if(СОБЫТИЕ_ИНТЕРФЕЙСА == _OBJECT_POINTED || СОБЫТИЕ_ИНТЕРФЕЙСА == _OBJECT_RELEASED)      Цвет_детали = C'166,166,166'; 
       if(Ползунковая_прокрутка) Цвет_детали = C'96,96,96'; //|| СОБЫТИЕ_ИНТЕРФЕЙСА == _SCROLLER_EVENT 
      } 
    //--------------------------  
   if(СОБЫТИЕ_ИНТЕРФЕЙСА == _OBJECT_POINTED || СОБЫТИЕ_ИНТЕРФЕЙСА == _OBJECT_RELEASED ||  СОБЫТИЕ_ИНТЕРФЕЙСА == _OBJECT_LEFT_CLICKED || Кнопочная_прокрутка)
      {
       if(КАТЕГОРИЯ_ОБЪЕКТА == _SCROLL_BAR && Деталь_полотна == ОБЪЕКТ + 2)Цвет_детали = C'200,200,200';  
       //-------------------------- && Деталь_полотна == ОБЪЕКТ - 3 && Деталь_полотна == ОБЪЕКТ - 1
       if(
             КАТЕГОРИЯ_ОБЪЕКТА == _SCROLL_BAR_BUTTON 
          && (
               (
                  (ПОДКАТЕГОРИЯ_ОБЪЕКТА == _SBUB && Подкатегория_детали == _VSBH)
               || (ПОДКАТЕГОРИЯ_ОБЪЕКТА == _SBDB && Подкатегория_детали == _VSBH)
               ) 
              ||   
               (
                  (ПОДКАТЕГОРИЯ_ОБЪЕКТА == _SBLB && Подкатегория_детали == _HSBH)
               || (ПОДКАТЕГОРИЯ_ОБЪЕКТА == _SBRB && Подкатегория_детали == _HSBH)
               )               
             )
             
         )
         {//Alert(__FUNCTION__,"  Деталь_полотна   ",Деталь_полотна,"  Непрозрачность_детали   ",Непрозрачность_детали);
          Цвет_детали = C'200,200,200'; 
         } 
      }
    }  
 //--------------------------------------------------------------------------
// 
 Alfa = Непрозрачность_детали + GAC;
 if(Alfa < 0)Alfa = 0;    
 Конечный_цвет = ColorToARGB(Цвет_детали,Alfa);
 //--------------------------------------------------------------------------
 return(Конечный_цвет);
}
//--------------------------------------------------------------------------

Как видишь, комментарии здесь почти не нужны. В таком стиле у меня написан весь код. Поэтому я его отлично знаю и помню, независимо от того, какой размер он имеет.


По моему мнению, в твоей системе решения задач есть какой то деффект. Сама задача должна быть кристальнно ясной и четкой, а следовательно ее решение тоже. Если решение мутное и определяемое словами "Система показала себя очень даже разумной" (какая может быть разумность в 270 кб-ах кода?!), то это означает, что автор приблизительно понимает как его система работает. И понять до конца ему мешают страшные навороты синстксиса и лишние в решении сущности.

Для эффективности решения лишние сущности нужно отсекать, а проблему видить идеально ясно.

Причина обращения: