Programação OOP vs procedimento - página 10

 
Реter Konow:
Sim, estas unidades têm ambas. Mas confie em mim - eles são comprimidos ao máximo e versáteis, porque resolvem uma ampla gama de problemas.

Se não houver muitas opções, você pode se safar com "ses" e "swipes".

 

Por que ninguém decidiu argumentar sobre "programação procedural com apontadores de funções versus programação procedural sem apontadores de funções"?

 
Dmitry Fedoseev:

Se não houver muitas opções, você pode se dar bem com os ifs e swipes.

A questão está no trabalho que precisa ser feito para compactar em soluções de código um grande número de tarefas. O assunto é a universalização do código, onde qualquer sintaxe e conchas adicionais são simplesmente destrutivas. É um trabalho duro, mas se livra de tudo que é supérfluo e permite que você evolua, alcançando novas alturas o tempo todo.
 

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

2. O objetivo é universalizar o código, no qual quaisquer técnicas de sintaxe e conchas adicionais são simplesmente destrutivas. É um trabalho duro, mas se livra de tudo que é supérfluo e permite que você evolua o tempo todo alcançando novas alturas.


1. Por que fazer o trabalho quando você pode torná-lo fácil e simples? Por que dificultar quando você pode facilitar as coisas?

2. Se você usa OOP, a universalização não é destrutiva, mas se torna uma possibilidade natural que não sobrecarrega nada.

 
Dmitry Fedoseev:

1. Por que fazer o trabalho quando ele pode ser feito de forma fácil e fácil? Por que fazer algo que pode ser feito facilmente, quando é difícil?

2. Se você usa OOP, então a universalização não é ruinosa, mas se torna uma possibilidade natural que não sobrecarrega nada.

Podemos continuar com este argumento por muito tempo. Utilizando o exemplo de uma tarefa de 100 trilhas, mostrei minha atitude em relação a este método de solução. Acredito que tarefas estúpidas não devem ser resolvidas, mas sim consertadas. Se o OOP ajuda aqueles que são mais fracos na definição correta das tarefas e na sua resolução eficaz - que continue ajudando-os. Mas para as pessoas que otimizam tarefas antes de começar a resolvê-las, o OOP pode simplesmente não ser necessário.

 
Реter Konow:

Poderíamos continuar com este argumento. Utilizando o exemplo de uma tarefa de 100 trilhas, mostrei minha atitude em relação a este método de solução. Acredito que tarefas estúpidas não devem ser resolvidas, mas sim consertadas. Se o OOP ajuda aqueles que são mais fracos em levantar e resolver as tarefas corretamente, deixe que ele os ajude. Mas para as pessoas que otimizam tarefas antes de começar a resolvê-las, o OOP pode simplesmente não ser necessário.


Você não codificou muito (provavelmente), o OOP é como uma lufada de ar.

A maioria das pessoas não codifica por interesse ou autodesenvolvimento, é seu trabalho, e é o resultado que conta.

 
Dmitry Fedoseev:

Não é tão conveniente, mas em termos de capacidade de velocidade, você pode passar por isso apenas com indicações.

E a conveniência é um conceito relativo.


Dmitry, é claro, usando o OOP reduz um pouco o desempenho. Mas são frações de um por cento.

Mas como o OOP aumenta o desempenho de um programador!

Aqui está um pequeno exemplo de um dos meus projetos, ele é cortado para percepção, mas na verdade há muitas outras coisas levadas em conta.

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;

Por exemplo, tomemos .NET, pois todas as API's consistem em classes.

Eu gosto muito do paradigma .NET. A propósito, existe um grande terminal cAlgo, você pode escrever diretamente no Visual Studio em C#

 
Alexey Volchanskiy:

Dimitri, é claro, o uso de OOP reduz um pouco o desempenho. Mas são frações de um por cento.

Se o número de variantes for pequeno, ele irá desacelerá-lo, mas se houver muitas variantes, será uma vantagem.

O que é mais importante, o número de variantes no OOP não afeta o desempenho. E na programação de procedimentos, há um teto sobre sua cabeça.

 

Bem, você fez uma bagunça...

É claro que qualquer tarefa pode ser resolvida tanto no estilo OOP, com alocação de interfaces, construção de hierarquia de herança, declaração de funções virtuais, como em puro estilo procedimental - você pode até mesmo colar tudo em uma enorme função.

A questão está na conveniência e eficiência do apoio.

Em MT - o lugar mais apropriado para o OOP é o sistema de pedidos. Pessoalmente, tenho interfaces virtuais para "posição" e "componentes de posição". "Posição" é um conjunto de ordens em MT4 ou um conjunto de posições em MT5. "Posição componente" é um pedido individual ou uma posição MT5 individual (hedge ou netting).

Aqui está o arquivo de interface real(Retag Konow, você pode apreciar o número de comentários em comparação com a quantidade de código, e eu os adiciono periodicamente lá quando encontro que não me lembro de algumas sutilezas. Por exemplo, eu esqueço regularmente quais objetos reais constituem um "componente de posição". Só não preciso lembrar - o Expert Advisor trabalha com componentes de acordo com a interface, e o que está por trás dessa interface na realidade não importa. Mas, eu tenho que voltar a ele durante a modificação - é por isso que eu preciso do primeiro comentário neste arquivo com muita freqüência):

// С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;
};

O arquivo para a interface do componente comercial é o seguinte (eu já o dei acima, mas vou repeti-lo:

// С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;  
  
};

De acordo com estas interfaces - tenho o sistema de pedidos MT4 e MT5 implementado tanto para pedidos reais como para pedidos históricos.

O Expert Advisor que solicita uma posição recebe esta interface e não precisa levar em conta a diferença entre as ordens MT4 e MT5. E se um novo tipo de pedido for adicionado ou a ordem de trabalho com eles for alterada - nada mudará para o Expert Advisor, apenas a nova classe de tipo de pedido será adicionada, e ele também suportará esta interface.

O sistema fazia muito sentido quando as contas cobertas foram introduzidas. Os especialistas não mudaram em nada.

Reg Konow, como você lida com a diferença nos tipos de pedidos em MT4 e MT5 ?

Se um novo tipo de conta for introduzido (além de hedge e netting) - quais mudanças precisarão ser feitas, e no mesmo lugar ?

Minha opinião é que se você se lembra de todo seu código à letra, e pode facilmente dizer por que esta ou aquela linha em seu código foi escrita há um ano - então é verdade, todos estes aperfeiçoamentos do OOP são apenas gestos desnecessários.

OOP é necessário exatamente quando você não se lembra de tudo ao modificar o código - OOP permite isolar blocos uns dos outros, limitar o conjunto de entidades disponíveis em um determinado momento a um determinado lugar no programa.

 
George Merts:

Bem, você fez uma bagunça...

1. É claro que qualquer tarefa pode ser resolvida tanto no estilo OOP, com alocação de interfaces, construção de hierarquia de herança, declaração de funções virtuais, como em puro estilo processual - podemos até mesmo colocar tudo em uma enorme função.

A questão está na conveniência e eficiência do apoio.

2. Em MT - o lugar mais apropriado para o OOP é o sistema de pedidos. Pessoalmente, eu tenho interfaces virtuais "posições" e "componentes de posição". "Posição" é um conjunto de ordens em MT4 ou um conjunto de posições em MT5. "Componente de posição" é um pedido individual ou uma posição MT5 individual (hedged ou netting).

3. Aqui está o arquivo de interface real(Retag Konow, você pode apreciar o número de comentários em comparação com a quantidade de código, e eu os adiciono periodicamente lá quando encontro que não me lembro de algumas sutilezas. Por exemplo, eu esqueço regularmente quais objetos reais constituem um "componente de posição". Só não preciso lembrar - o Expert Advisor trabalha com componentes de acordo com a interface, e o que está por trás dessa interface na realidade não importa. Mas, eu tenho que voltar a ele durante a modificação - é por isso que eu preciso do primeiro comentário neste arquivo com muita freqüência):

O arquivo para a interface do componente comercial é o seguinte (eu já o dei acima, mas vou repeti-lo:

De acordo com estas interfaces - tenho o sistema de pedidos MT4 e MT5 implementado tanto para pedidos reais como para pedidos históricos.

O Expert Advisor que solicita uma posição recebe esta interface e não precisa levar em conta a diferença entre as ordens MT4 e MT5. E se um novo tipo de pedido for adicionado ou a ordem de trabalho com eles for alterada - nada mudará para o Expert Advisor, apenas um novo tipo de pedido será adicionado, e ele também suportará esta interface.

O sistema provou ser muito razoável, quando as contas de cobertura foram introduzidas. Os especialistas não mudaram em nada em relação a isso.

4. Reg Konow, como você lida com a diferença nos tipos de pedidos em MT4 e MT5 ?

Se um novo tipo de conta for introduzido (além de hedge e netting) - quais mudanças precisarão ser feitas, e no mesmo lugar ?

Eu acho que se você se lembrar de todo seu código à letra, e puder facilmente dizer por que esta ou aquela linha foi escrita em seu código há um ano - então todos estes aperfeiçoamentos do OOP são apenas gestos desnecessários.

OOP é necessário precisamente quando você não se lembra de tudo ao modificar o código - OOP permite isolar blocos uns dos outros para limitar o conjunto de entidades disponíveis em um determinado momento a um determinado lugar no programa.

1. 1. eu concordo plenamente. A única diferença está na eficácia de resolver tarefas de uma forma ou de outra.

2. Eu não trabalhei realmente com o sistema de pedidos e não consigo ver nenhum problema técnico em sua construção. Talvez haja, mas precisamos de uma tarefa concreta e então ficará claro como posso resolvê-la eficazmente sem o OOP.

3. Do meu ponto de vista, a amostra de código dada é simplesmente horrível do ponto de vista da legibilidade. Não é à toa que são necessários tantos comentários e por que você esquece seu conteúdo. Desculpe, mas essa é a minha primeira impressão subjetiva. É simplesmente assustador.

Aqui está um exemplo de legibilidade do meu código - a função que define a cor de um item de controle:

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(Конечный_цвет);
}
//--------------------------------------------------------------------------

Como você pode ver, os comentários são quase desnecessários aqui. Todo meu código está escrito neste estilo. Portanto, eu o conheço perfeitamente bem e o lembro não importa o tamanho.


Na minha opinião, há algum defeito em seu sistema de solução de problemas. O problema em si deve ser cristalino e preciso e, portanto, sua solução também. Se a solução estiver nublada e definida pelas palavras "O sistema provou ser muito razoável" (como pode ser razoável em 270 Kb de código?!), isso significa que o autor tem uma compreensão grosseira de como seu sistema funciona. E são terríveis artifícios de sintaxe e entidades desnecessárias na solução que o impedem de compreendê-la até o fim.

Para que uma solução seja eficaz, as entidades desnecessárias devem ser cortadas, e o problema deve ser visto de forma perfeitamente clara.

Razão: