OOP vs. programación procedimental - página 10

 
Реter Konow:
Sí, estas unidades tienen ambas cosas. Pero créanme: están comprimidos al máximo y son versátiles, porque resuelven una amplia gama de problemas.

Si no hay muchas opciones, puedes arreglártelas con los "si" y los "golpes".

 

¿Por qué nadie se ha decidido a discutir sobre "la programación procedimental con punteros de función frente a la programación procedimental sin punteros de función"?

 
Dmitry Fedoseev:

Si no hay muchas opciones, puedes arreglártelas con los "si" y los "golpes".

La cuestión está en el trabajo que hay que hacer para comprimir en código las soluciones de un gran número de tareas. Se trata de la universalización del código, donde cualquier sintaxis adicional y las conchas son simplemente destructivas. Es un trabajo duro, pero te libra de todo lo superfluo y te permite evolucionar, alcanzando siempre nuevas cotas.
 

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

2. Se trata de universalizar el código, en el que cualquier técnica de sintaxis adicional y las conchas son simplemente destructivas. Es un trabajo duro, pero se deshace de todo lo superfluo y te permite evolucionar todo el tiempo alcanzando nuevas cotas.


1. ¿Por qué hacer el trabajo cuando puedes hacerlo fácil y sencillo? ¿Por qué hacerlo difícil cuando puedes hacerlo fácil?

2. Si se utiliza la POO, la universalización no es destructiva, sino que se convierte en una posibilidad natural que no carga nada.

 
Dmitry Fedoseev:

1. ¿Por qué hacer el trabajo cuando se puede hacer de forma fácil y sencilla? ¿Por qué hacer algo que se puede hacer fácilmente cuando es difícil?

2. Si se utiliza la POO, la universalización no es ruinosa, sino que se convierte en una posibilidad natural que no carga nada.

Podemos seguir con este argumento durante mucho tiempo. Utilizando el ejemplo de una tarea de 100 trazos, mostré mi actitud ante este método de solución. Creo que las tareas estúpidas no deben resolverse, sino arreglarse. Si la POO ayuda a los que son más débiles a la hora de plantear y resolver tareas correctamente, que les ayude. Pero para las personas que optimizan las tareas antes de empezar a resolverlas, la POO puede no ser necesaria.

 
Реter Konow:

Podríamos seguir y seguir con este argumento. Utilizando el ejemplo de una tarea de 100 trazos, mostré mi actitud ante este método de solución. Creo que las tareas estúpidas no deben resolverse, sino arreglarse. Si la POO ayuda a quienes son más débiles a la hora de plantear las tareas correctamente y resolverlas con eficacia, que siga ayudándoles. Pero para las personas que optimizan las tareas antes de empezar a resolverlas, la POO puede no ser necesaria.


No has codificado mucho (probablemente), OOP es como un soplo de aire.

La mayoría de la gente no codifica por interés o por desarrollo personal, es su trabajo, y lo que cuenta es el resultado.

 
Dmitry Fedoseev:

No es ni mucho menos tan cómodo, pero en términos de capacidad de velocidad, puedes arreglártelas sólo con los punteros.

Y la comodidad es un concepto relativo.


Dmitry, por supuesto que el uso de la POO reduce un poco el rendimiento. Pero son fracciones de un porcentaje.

¡Pero cómo la POO aumenta el rendimiento de un programador!

Aquí hay un pequeño ejemplo de uno de mis proyectos, está recortado para la percepción, pero en realidad hay muchas otras cosas que se tienen en cuenta.

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 ejemplo, tomemos .NET, ya que todas las API consisten en clases.

Me gusta mucho el paradigma de .NET. Por cierto, hay un gran terminal cAlgo, se puede escribir directamente en Visual Studio en C#

 
Alexey Volchanskiy:

Dimitri, por supuesto que el uso de la POO reduce un poco el rendimiento. Pero son fracciones de un porcentaje.

Si el número de variantes es pequeño, lo ralentizará, pero si hay demasiadas variantes, será una ventaja.

Lo más importante es que el número de variantes en OOP no afecta al rendimiento. Y en la programación procedimental, hay un techo sobre tu cabeza.

 

Bueno, te has hecho un lío...

Está claro que cualquier tarea puede ser resuelta tanto al estilo OOP, con la asignación de interfaces, la construcción de la jerarquía de la herencia, la declaración de funciones virtuales, como al estilo procedimental puro - incluso se puede meter todo en una enorme función.

La cuestión está en la comodidad y la eficacia del apoyo.

En MT - el lugar más apropiado para la OOP es el sistema de pedidos. Personalmente, tengo interfaces virtuales para "posición" y "componentes de posición". "Posición" es un conjunto de órdenes en MT4 o un conjunto de posiciones en MT5. "Componente de la posición" es una orden individual o una posición individual de MT5 (cobertura o compensación).

Aquí está el archivo de la interfaz real(Retag Konow, se puede apreciar el número de comentarios en comparación con la cantidad de código, y periódicamente los agrego allí cuando encuentro algunas sutilezas que no recuerdo. Por ejemplo, suelo olvidar qué objetos reales constituyen un "componente de posición". Simplemente no necesito recordarlo - el Asesor Experto trabaja con componentes según la interfaz, y lo que hay detrás de esa interfaz en realidad no importa. Pero, tengo que volver a él durante la modificación - es por eso que necesito el primer comentario en este archivo muy a menudo):

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

El archivo de la interfaz del componente comercial es el siguiente (ya lo he dado más arriba, pero lo repetiré:

// С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 acuerdo con estas interfaces - tengo implementado tanto el sistema de órdenes de MT4 como el de MT5 para órdenes reales e históricas.

El Asesor Experto que solicita una posición recibe esta interfaz y no tiene que tener en cuenta la diferencia entre las órdenes de MT4 y MT5. Y si se añade un nuevo tipo de orden o se cambia el orden de trabajo con ellos - nada cambiará para el Asesor Experto, sólo se añadirá la nueva clase de tipo de orden, y también soportará esta interfaz.

El sistema tuvo mucho sentido cuando se introdujeron las cuentas cubiertas. Los expertos no han cambiado en absoluto.

Reg Konow, ¿cómo se maneja la diferencia de tipos de órdenes en MT4 y MT5?

Si se introduce un nuevo tipo de cuenta (además de la cobertura y la compensación), ¿qué cambios habrá que hacer, y en el mismo lugar?

Mi opinión es que si recuerdas todo tu código al pie de la letra, y puedes decir fácilmente por qué tal o cual línea de tu código fue escrita hace un año - entonces es cierto, todos estos OOP-enhancers son sólo gestos innecesarios.

La POO es necesaria precisamente cuando no se recuerda todo al modificar el código - la POO permite aislar los bloques entre sí, limitar el conjunto de entidades disponibles en un momento dado a un lugar determinado del programa.

 
George Merts:

Bueno, te has hecho un lío...

1. Está claro que cualquier tarea puede ser resuelta tanto al estilo OOP, con asignación de interfaces, construcción de jerarquía de herencia, declaración de funciones virtuales, como al estilo procedimental puro - incluso podemos poner todo en una enorme función.

La cuestión está en la comodidad y la eficacia del apoyo.

2. En MT - el lugar más apropiado para la OOP es el sistema de pedidos. Personalmente, tengo interfaces virtuales "posiciones" y "componentes de posición". "Posición" es un conjunto de órdenes en MT4 o un conjunto de posiciones en MT5. "Componente de la posición" es una orden individual o una posición individual de MT5 (cubierta o neta).

3. Aquí está el archivo de la interfaz real(Retag Konow, se puede apreciar el número de comentarios en comparación con la cantidad de código, y periódicamente los agrego allí cuando me encuentro que no recuerdo algunas sutilezas. Por ejemplo, suelo olvidar qué objetos reales constituyen un "componente de posición". Simplemente no necesito recordarlo - el Asesor Experto trabaja con componentes según la interfaz, y lo que hay detrás de esa interfaz en realidad no importa. Pero, tengo que volver a él durante la modificación - es por eso que necesito el primer comentario en este archivo muy a menudo):

El archivo de la interfaz del componente comercial es el siguiente (ya lo he dado más arriba, pero lo repetiré:

De acuerdo con estas interfaces - tengo implementado tanto el sistema de órdenes de MT4 como el de MT5 para órdenes reales e históricas.

El Asesor Experto que solicita una posición recibe esta interfaz y no tiene que tener en cuenta la diferencia entre las órdenes de MT4 y MT5. Y si se añade un nuevo tipo de orden o se cambia el orden de trabajo con ellas - no cambiará nada para el Asesor Experto, sólo se añadirá un nuevo tipo de orden, y también soportará esta interfaz.

El sistema resultó ser muy razonable, cuando se introdujeron las cuentas de cobertura. Los expertos no han cambiado en absoluto desde entonces.

4. Reg Konow, ¿cómo se maneja la diferencia de tipos de órdenes en MT4 y MT5?

Si se introduce un nuevo tipo de cuenta (además de la cobertura y la compensación), ¿qué cambios habrá que hacer, y en el mismo lugar?

Creo que si recuerdas todo tu código al pie de la letra, y puedes decir fácilmente por qué se escribió tal o cual línea hace un año - entonces todos estos potenciadores de la POO son sólo gestos innecesarios.

La POO es necesaria precisamente cuando no se recuerda todo al modificar el código: la POO permite aislar los bloques entre sí para limitar el conjunto de entidades disponibles en un momento dado a un lugar concreto del programa.

1. 1. Estoy totalmente de acuerdo. La única diferencia está en la eficacia para resolver las tareas de una manera u otra.

2. No he trabajado realmente con el sistema de pedidos y no veo ningún problema técnico en su construcción. Tal vez los haya, pero necesitamos una tarea concreta y entonces se verá la eficacia con la que puedo resolverla sin la POO.

3. Desde mi punto de vista, el ejemplo de código dado es simplemente horrible desde el punto de vista de la legibilidad. No es de extrañar que se requieran tantos comentarios y que se olvide su contenido. Lo siento, pero esa es mi primera impresión subjetiva. Es simplemente espeluznante.

Aquí hay un ejemplo de legibilidad de mi código - la función que define el color de un elemento de control:

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 puede ver, los comentarios son casi innecesarios aquí. Todo mi código está escrito en este estilo. Así que lo conozco perfectamente y lo recuerdo sin importar el tamaño.


En mi opinión, hay algún defecto en su sistema de resolución de problemas. El problema en sí debe ser muy claro y preciso, y por lo tanto su solución también. Si la solución es turbia y se define con las palabras "El sistema resultó ser muy razonable" (¡¿cómo puede ser razonable en 270 Kb de código?!), significa que el autor tiene una comprensión aproximada de cómo funciona su sistema. Y son terribles los artificios sintácticos y las entidades superfluas en la solución que le impiden entenderla hasta el final.

Para que una solución sea eficaz, hay que cortar las entidades innecesarias y ver el problema con total claridad.