OOP vs programmazione procedurale - pagina 10

 
Реter Konow:
Sì, queste unità hanno entrambi. Ma credetemi - sono compressi al massimo e versatili, perché risolvono una vasta gamma di problemi.

Se non ci sono molte opzioni, puoi cavartela con if e swipe.

 

Perché nessuno ha deciso di discutere di "programmazione procedurale con puntatori di funzione vs. programmazione procedurale senza puntatori di funzione"?

 
Dmitry Fedoseev:

Se non ci sono molte opzioni, puoi cavartela con if e swipe.

Il punto è nel lavoro che deve essere fatto per comprimere in codice le soluzioni di un numero enorme di compiti. La questione riguarda l'universalizzazione del codice, dove qualsiasi sintassi e shell aggiuntiva è semplicemente distruttiva. È un lavoro duro, ma ti libera di tutto il superfluo e ti permette di evolvere, raggiungendo sempre nuove altezze.
 

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

2. Il punto è l'universalizzazione del codice, in cui qualsiasi tecnica di sintassi e shell aggiuntiva è semplicemente distruttiva. È un lavoro duro, ma si sbarazza di tutto il superfluo e ti permette di evolvere sempre raggiungendo nuove vette.


1. Perché fare il lavoro quando puoi renderlo facile e semplice? Perché renderlo difficile quando si può renderlo facile?

2. Se si usa OOP, l'universalizzazione non è distruttiva, ma diventa una possibilità naturale che non grava su nulla.

 
Dmitry Fedoseev:

1. Perché fare il lavoro quando può essere fatto facilmente e senza problemi? Perché fare qualcosa che può essere fatto facilmente quando è difficile?

2. Se si usa OOP, allora l'universalizzazione non è rovinosa, ma diventa una possibilità naturale che non grava su nulla.

Possiamo continuare a lungo con questo argomento. Utilizzando l'esempio di un compito di 100 tracce, ho mostrato il mio atteggiamento verso questo metodo di soluzione. Credo che i compiti stupidi non debbano essere risolti ma aggiustati. Se l'OOP aiuta coloro che sono più deboli nel sollevare e risolvere correttamente i compiti, che li aiuti. Ma per le persone che ottimizzano i compiti prima di iniziare a risolverli, OOP può semplicemente non essere necessaria.

 
Реter Konow:

Potremmo continuare all'infinito con questo argomento. Utilizzando l'esempio di un compito di 100 tracce, ho mostrato il mio atteggiamento verso questo metodo di soluzione. Credo che i compiti stupidi non debbano essere risolti ma aggiustati. Se l'OOP aiuta coloro che sono più deboli nel sollevare e risolvere correttamente i compiti, che li aiuti. Ma per le persone che ottimizzano i compiti prima di iniziare a risolverli, OOP può semplicemente non essere necessaria.


Non hai codificato molto (probabilmente), OOP è come una boccata d'aria.

La maggior parte delle persone codifica non per interesse o autosviluppo, è il loro lavoro, ed è il risultato che conta.

 
Dmitry Fedoseev:

Non è così conveniente, ma in termini di capacità di velocità, si può andare avanti solo con i puntatori.

E la convenienza è un concetto relativo.


Dmitry, ovviamente usare OOP riduce un po' le prestazioni. Ma sono frazioni di percentuale.

Ma come OOP aumenta le prestazioni di un programmatore!

Ecco un piccolo esempio da uno dei miei progetti, è tagliato per la percezione, ma in realtà ci sono molte altre cose prese in considerazione.

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;

Per esempio, prendiamo .NET, poiché tutte le API sono costituite da classi.

Mi piace molto il paradigma .NET. A proposito, c'è un grande terminale cAlgo, si può scrivere direttamente in Visual Studio in C#

 
Alexey Volchanskiy:

Dimitri, ovviamente usare OOP riduce un po' le prestazioni. Ma sono frazioni di percentuale.

Se il numero di varianti è piccolo, lo rallenterà, ma se ci sono troppe varianti, sarà un vantaggio.

La cosa più importante è che il numero di varianti in OOP non influisce sulle prestazioni. E nella programmazione procedurale, c'è un tetto sopra la tua testa.

 

Beh, hai fatto un casino...

È chiaro che qualsiasi compito può essere risolto sia in stile OOP, con l'assegnazione di interfacce, la costruzione della gerarchia di ereditarietà, la dichiarazione di funzioni virtuali, sia in puro stile procedurale - si può anche infilare tutto in una funzione enorme.

La questione è nella convenienza e nell'efficienza del supporto.

In MT - il posto più adatto all'OOP è il sistema degli ordini. Personalmente, ho interfacce virtuali per "posizione" e "componenti di posizione". "Posizione" è un insieme di ordini in MT4 o un insieme di posizioni in MT5. "Componente della posizione" è un ordine individuale o una posizione MT5 individuale (hedge o netting).

Ecco il file di interfaccia attuale(Retag Konow, si può apprezzare il numero di commenti rispetto alla quantità di codice, e li aggiungo periodicamente quando incontro che non ricordo alcune sottigliezze. Per esempio, dimentico regolarmente quali oggetti reali costituiscono un "componente di posizione". Non ho bisogno di ricordarlo - l'Expert Advisor lavora con i componenti secondo l'interfaccia, e quello che c'è dietro quell'interfaccia in realtà non ha importanza. Ma, devo ritornarci durante la modifica - ecco perché ho bisogno molto spesso del primo commento in questo file):

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

Il file per l'interfaccia del componente commerciale è il seguente (l'ho già dato sopra, ma lo ripeto:

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

In base a queste interfacce - ho implementato sia il sistema di ordini MT4 che MT5 per ordini reali e storici.

L'Expert Advisor che richiede una posizione riceve questa interfaccia e non deve tenere conto della differenza tra gli ordini MT4 e MT5. E se viene aggiunto un nuovo tipo di ordine o viene cambiato l'ordine di lavorare con essi - non cambierà nulla per l'Expert Advisor, solo la nuova classe del tipo di ordine verrà aggiunta, e supporterà anche questa interfaccia.

Il sistema ha avuto molto senso quando sono stati introdotti i conti coperti. Gli esperti non sono cambiati affatto.

Reg Konow, come ti occupi della differenza dei tipi di ordine in MT4 e MT5?

Se viene introdotto un nuovo tipo di conto (oltre alla copertura e al netting) - quali cambiamenti dovranno essere fatti, e nello stesso posto?

La mia opinione è che se ti ricordi tutto il tuo codice alla lettera, e puoi facilmente dire perché questa o quella linea nel tuo codice è stata scritta un anno fa - allora è vero, tutti questi miglioramenti OOP sono solo gesti inutili.

L'OOP è necessaria proprio quando non si ricorda tutto quando si modifica il codice - l'OOP permette di isolare i blocchi l'uno dall'altro, limitare l'insieme delle entità disponibili in qualsiasi momento in un posto particolare del programma.

 
George Merts:

Beh, hai fatto un casino...

1. È chiaro che qualsiasi compito può essere risolto sia in stile OOP, con l'assegnazione di interfacce, la costruzione della gerarchia di ereditarietà, la dichiarazione di funzioni virtuali, sia in puro stile procedurale - possiamo anche mettere tutto in una funzione enorme.

La questione è nella convenienza e nell'efficienza del supporto.

2. In MT - il posto più adatto all'OOP è il sistema degli ordini. Personalmente, ho interfacce virtuali "posizioni" e "componenti di posizione". "Posizione" è un insieme di ordini in MT4 o un insieme di posizioni in MT5. "Componente della posizione" è un ordine individuale o una posizione MT5 individuale (con copertura o netting).

3. Ecco il file di interfaccia attuale(Retag Konow, si può apprezzare il numero di commenti rispetto alla quantità di codice, e li aggiungo periodicamente quando incontro che non ricordo alcune sottigliezze. Per esempio, dimentico regolarmente quali oggetti reali costituiscono un "componente di posizione". Non ho bisogno di ricordarlo - l'Expert Advisor lavora con i componenti secondo l'interfaccia, e quello che c'è dietro quell'interfaccia in realtà non ha importanza. Ma, devo ritornarci durante la modifica - ecco perché ho bisogno molto spesso del primo commento in questo file):

Il file per l'interfaccia del componente commerciale è il seguente (l'ho già dato sopra, ma lo ripeto:

In base a queste interfacce - ho implementato sia il sistema di ordini MT4 che MT5 per ordini reali e storici.

L'Expert Advisor che richiede una posizione riceve questa interfaccia e non deve tenere conto della differenza tra gli ordini MT4 e MT5. E se viene aggiunto un nuovo tipo di ordine o viene cambiato l'ordine di lavoro con essi - non cambierà nulla per l'Expert Advisor, solo un nuovo tipo di ordine verrà aggiunto, e supporterà anche questa interfaccia.

Il sistema si è dimostrato molto ragionevole, quando sono stati introdotti i conti di copertura. Gli esperti non sono cambiati affatto da allora.

4. Reg Konow, come ti occupi della differenza dei tipi di ordine in MT4 e MT5?

Se viene introdotto un nuovo tipo di conto (oltre alla copertura e al netting) - quali cambiamenti dovranno essere fatti, e nello stesso posto?

Penso che se ti ricordi tutto il tuo codice alla lettera, e puoi facilmente dire perché questa o quella linea è stata scritta un anno fa - allora tutti questi miglioratori OOP sono solo gesti inutili.

L'OOP è necessaria proprio quando non si ricorda tutto quando si modifica il codice - l'OOP permette di isolare i blocchi l'uno dall'altro per limitare l'insieme delle entità disponibili in un dato momento in un posto particolare del programma.

1. 1. Sono assolutamente d'accordo. L'unica differenza è nell'efficacia di risolvere i compiti in un modo o nell'altro.

2. Non ho lavorato molto con il sistema degli ordini e non vedo alcun problema tecnico nella sua costruzione. Forse ci sono, ma abbiamo bisogno di un compito concreto e allora sarà chiaro quanto efficacemente posso risolverlo senza l'OOP.

3. Dal mio punto di vista, l'esempio di codice dato è semplicemente terribile dal punto di vista della leggibilità. Non c'è da stupirsi che siano necessari così tanti commenti e che si dimentichi il suo contenuto. Scusa, ma questa è la mia prima impressione soggettiva. È semplicemente inquietante.

Ecco un esempio di leggibilità del mio codice - la funzione che definisce il colore dell'elemento di un controllo:

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

Come potete vedere, i commenti sono quasi inutili qui. Tutto il mio codice è scritto in questo stile. Quindi la conosco perfettamente e la ricordo a prescindere dalle dimensioni.


Secondo me, c'è qualche difetto nel vostro sistema di risoluzione dei problemi. Il problema stesso dovrebbe essere chiaro e preciso, e quindi anche la sua soluzione. Se la soluzione è nebulosa e definita dalle parole "Il sistema si è dimostrato molto ragionevole" (come può essere ragionevole in 270 Kb di codice?!), significa che l'autore ha una comprensione approssimativa di come funziona il suo sistema. E sono terribili gli artifizi di sintassi e le entità inutili nella soluzione che gli impediscono di capirla fino in fondo.

Affinché una soluzione sia efficace, le entità inutili devono essere tagliate e il problema deve essere visto perfettamente.

Motivazione: