Programmation OOP vs programmation procédurale - page 10

 
Реter Konow:
Oui, ces unités ont les deux. Mais croyez-moi, ils sont compressés au maximum et polyvalents, car ils résolvent un large éventail de problèmes.

S'il n'y a pas beaucoup d'options, vous pouvez vous en sortir avec des "si" et des "swip".

 

Pourquoi personne n'a décidé de débattre de la "programmation procédurale avec pointeurs de fonction contre la programmation procédurale sans pointeurs de fonction" ?

 
Dmitry Fedoseev:

S'il n'y a pas beaucoup d'options, vous pouvez vous en sortir avec des "si" et des "swip".

Le point est dans le travail qui doit être fait pour comprimer dans le code les solutions d'un grand nombre de tâches. Il s'agit de l'universalisation du code, où toute syntaxe et toute coquille supplémentaires sont simplement destructrices. C'est un travail difficile, mais il permet de se débarrasser de tout ce qui est superflu et d'évoluer, en atteignant sans cesse de nouveaux sommets.
 

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

2. Le but est d'universaliser le code, dans lequel toute technique syntaxique et tout shell supplémentaires sont simplement destructeurs. C'est un travail difficile, mais il permet de se débarrasser de tout ce qui est superflu et d'évoluer sans cesse vers de nouveaux sommets.


1. Pourquoi faire le travail quand on peut le rendre facile et simple ? Pourquoi rendre les choses difficiles quand on peut les rendre faciles ?

2. Si vous utilisez la POO, l'universalisation n'est pas destructive, mais devient une possibilité naturelle qui n'alourdit rien.

 
Dmitry Fedoseev:

1. Pourquoi faire le travail quand il peut être fait facilement et aisément ? Pourquoi faire quelque chose qui peut être fait facilement alors que c'est difficile ?

2. Si vous utilisez la POO, alors l'universalisation n'est pas ruineuse, mais devient une possibilité naturelle qui n'alourdit rien.

Nous pouvons poursuivre cet argument pendant longtemps. À l'aide de l'exemple d'une tâche de 100 trajets, j'ai montré mon attitude vis-à-vis de cette méthode de solution. Je crois que les tâches stupides ne doivent pas être résolues mais réparées. Si la POO aide ceux qui sont plus faibles pour soulever et résoudre des tâches correctement, qu'elle les aide. Mais pour les personnes qui optimisent les tâches avant de commencer à les résoudre, la POO peut tout simplement ne pas être nécessaire.

 
Реter Konow:

Nous pourrions poursuivre cet argument à l'infini. À l'aide de l'exemple d'une tâche de 100 trajets, j'ai montré mon attitude vis-à-vis de cette méthode de solution. Je crois que les tâches stupides ne doivent pas être résolues mais réparées. Si la POO aide ceux qui sont plus faibles pour soulever et résoudre des tâches correctement, qu'elle les aide. Mais pour les personnes qui optimisent les tâches avant de commencer à les résoudre, la POO peut tout simplement ne pas être nécessaire.


Vous n'avez pas beaucoup codé (probablement), la POO est comme une bouffée d'air.

La plupart des gens ne codent pas par intérêt ou pour s'épanouir, c'est leur travail, et c'est le résultat qui compte.

 
Dmitry Fedoseev:

Ce n'est pas aussi pratique, mais en termes de rapidité, vous pouvez vous en sortir avec les pointeurs seuls.

Et la commodité est un concept relatif.


Dmitry, il est évident que l'utilisation de la POO réduit un peu les performances. Mais ce sont des fractions de pourcent.

Mais comment la POO augmente les performances d'un programmeur !

Voici un petit exemple tiré d'un de mes projets, il est découpé pour la perception, mais en réalité il y a beaucoup d'autres choses prises en compte.

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;

Par exemple, prenons .NET, car toutes les API sont constituées de classes.

J'aime beaucoup le paradigme .NET. D'ailleurs, il existe un excellent terminal cAlgo, que vous pouvez écrire directement dans Visual Studio en C#.

 
Alexey Volchanskiy:

Dimitri, bien sûr que l'utilisation de la POO réduit un peu les performances. Mais ce sont des fractions de pourcent.

Si le nombre de variantes est faible, cela le ralentira, mais s'il y a trop de variantes, ce sera un avantage.

Le plus important, c'est que le nombre de variantes dans la POO n'affecte pas les performances. Et dans la programmation procédurale, il y a un plafond au-dessus de votre tête.

 

Eh bien, vous avez fait un gâchis...

Il est clair que toute tâche peut être résolue à la fois dans le style POO, avec l'attribution d'interfaces, la construction d'une hiérarchie d'héritage, la déclaration de fonctions virtuelles, et dans le style procédural pur - vous pouvez même tout mettre dans une énorme fonction.

La question est celle de la commodité et de l'efficacité du soutien.

Dans MT - l'endroit le plus approprié pour la POO est le système de commande. Personnellement, j'ai des interfaces virtuelles pour "position" et "composants de position". "Position" est un ensemble d'ordres dans MT4 ou un ensemble de positions dans MT5. La "composante de la position" est un ordre individuel ou une position MT5 individuelle (couverture ou compensation).

Voici le fichier d'interface actuel(Retag Konow, vous pouvez apprécier le nombre de commentaires par rapport à la quantité de code, et j'en ajoute périodiquement lorsque je rencontre des subtilités dont je ne me souviens pas. Par exemple, j'oublie régulièrement quels objets réels constituent un "composant de position". Je n'ai pas besoin de m'en souvenir - le conseiller expert travaille avec des composants selon l'interface, et ce qui se trouve derrière cette interface n'a pas d'importance en réalité. Mais, je dois y revenir pendant la modification - c'est pourquoi j'ai très souvent besoin du premier commentaire dans ce fichier) :

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

Le fichier de l'interface du composant commercial est le suivant (je l'ai déjà donné plus haut, mais je vais le répéter :

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

En fonction de ces interfaces, j'ai mis en place un système d'ordres MT4 et MT5 pour les ordres réels et historiques.

Le conseiller expert qui demande une position reçoit cette interface et ne doit pas tenir compte de la différence entre les ordres MT4 et MT5. Et si un nouveau type d'ordre est ajouté ou si l'ordre de travail avec eux est modifié - rien ne changera pour le conseiller expert, seule la nouvelle classe de type d'ordre sera ajoutée, et elle supportera également cette interface.

Le système a pris tout son sens lorsque les comptes couverts ont été introduits. Les experts n'ont pas changé du tout.

Reg Konow, comment gérez-vous la différence entre les types d'ordres dans MT4 et MT5 ?

Si un nouveau type de compte est introduit (en plus de la couverture et de la compensation), quels changements devront être apportés, et au même endroit ?

Mon opinion est que si vous vous souvenez de tout votre code à la lettre, et que vous pouvez facilement dire pourquoi telle ou telle ligne de votre code a été écrite il y a un an - alors c'est vrai, tous ces perfectionnements de la POO ne sont que des gestes inutiles.

La POO est nécessaire précisément lorsque vous ne vous souvenez pas de tout lorsque vous modifiez le code - la POO permet d'isoler les blocs les uns des autres, de limiter l'ensemble des entités disponibles à tout moment à un endroit particulier du programme.

 
George Merts:

Eh bien, vous avez fait un gâchis...

1. Il est clair que toute tâche peut être résolue à la fois dans le style POO, avec l'attribution d'interfaces, la construction d'une hiérarchie d'héritage, la déclaration de fonctions virtuelles, et dans le style procédural pur - nous pouvons même tout mettre dans une énorme fonction.

La question est celle de la commodité et de l'efficacité du soutien.

2. Dans MT - l'endroit le plus approprié pour la POO est le système de commande. Personnellement, j'ai des interfaces virtuelles "positions" et "composants de position". "Position" est un ensemble d'ordres dans MT4 ou un ensemble de positions dans MT5. La "composante de la position" est un ordre individuel ou une position MT5 individuelle (couverte ou compensée).

3. Voici le fichier d'interface proprement dit(Retag Konow, vous pouvez apprécier le nombre de commentaires par rapport à la quantité de code, et j'en ajoute périodiquement lorsque je rencontre que je ne me souviens pas de certaines subtilités. Par exemple, j'oublie régulièrement quels objets réels constituent un "composant de position". Je n'ai pas besoin de m'en souvenir - le conseiller expert travaille avec des composants selon l'interface, et ce qui se trouve derrière cette interface n'a pas d'importance en réalité. Mais, je dois y revenir pendant la modification - c'est pourquoi j'ai très souvent besoin du premier commentaire dans ce fichier) :

Le fichier de l'interface du composant commercial est le suivant (je l'ai déjà donné plus haut, mais je vais le répéter :

En fonction de ces interfaces, j'ai mis en place un système d'ordres MT4 et MT5 pour les ordres réels et historiques.

Le conseiller expert qui demande une position reçoit cette interface et ne doit pas tenir compte de la différence entre les ordres MT4 et MT5. Et si un nouveau type d'ordre est ajouté ou si l'ordre de travail avec eux est modifié - rien ne changera pour le conseiller expert, seul un nouveau type d'ordre sera ajouté, et il supportera également cette interface.

Le système s'est avéré très raisonnable, lorsque les comptes de couverture ont été introduits. Les experts n'ont pas du tout changé depuis.

4. Reg Konow, comment gérez-vous la différence entre les types d'ordres dans MT4 et MT5 ?

Si un nouveau type de compte est introduit (en plus de la couverture et de la compensation), quels changements devront être apportés, et au même endroit ?

Je pense que si vous vous souvenez de tout votre code à la lettre, et que vous pouvez facilement dire pourquoi telle ou telle ligne a été écrite il y a un an - alors tous ces perfectionnements de la POO ne sont que des gestes inutiles.

La POO est nécessaire précisément lorsque vous ne vous souvenez pas de tout lorsque vous modifiez le code - la POO vous permet d'isoler les blocs les uns des autres pour limiter l'ensemble des entités disponibles à un moment donné à un endroit particulier du programme.

1. 1. Je suis tout à fait d'accord. La seule différence réside dans l'efficacité à résoudre les tâches d'une manière ou d'une autre.

2. Je n'ai pas vraiment travaillé avec le système de commande et je ne vois pas de problèmes techniques dans sa construction. Peut-être qu'il y en a, mais nous avons besoin d'une tâche concrète et alors il sera clair à quel point je peux la résoudre efficacement sans la POO.

3. De mon point de vue, l'exemple de code donné est tout simplement affreux du point de vue de la lisibilité. Il n'est pas étonnant que tant de commentaires soient nécessaires et que vous en oubliiez le contenu. Désolé, mais c'est ma première impression subjective. C'est juste effrayant.

Voici un exemple de lisibilité de mon code - la fonction qui définit la couleur de l'élément d'un contrôle :

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

Comme vous pouvez le constater, les commentaires sont presque inutiles ici. Tout mon code est écrit dans ce style. Je le connais donc parfaitement et je m'en souviens quelle que soit sa taille.


A mon avis, il y a un défaut dans votre système de résolution des problèmes. Le problème lui-même doit être parfaitement clair et précis, et donc sa solution aussi. Si la solution est nébuleuse et définie par les mots "Le système s'est avéré très raisonnable" (comment peut-il être raisonnable dans 270 Ko de code ? !), cela signifie que l'auteur a une compréhension approximative du fonctionnement de son système. Et ce sont les terribles contrivances syntaxiques et les entités inutiles de la solution qui l'empêchent de la comprendre jusqu'au bout.

Pour qu'une solution soit efficace, les entités inutiles doivent être coupées et le problème doit être perçu de manière parfaitement claire.