OOP vs. prozedurale Programmierung - Seite 10

 
Реter Konow:
Ja, diese Geräte haben beides. Aber glauben Sie mir - sie sind maximal komprimiert und vielseitig, weil sie eine breite Palette von Problemen lösen.

Wenn es nicht viele Optionen gibt, können Sie mit Wenn und Aber auskommen.

 

Warum hat sich noch niemand dazu entschlossen, über "prozedurale Programmierung mit Funktionszeigern vs. prozedurale Programmierung ohne Funktionszeiger" zu diskutieren?

 
Dmitry Fedoseev:

Wenn es nicht viele Optionen gibt, können Sie mit Wenn und Aber auskommen.

Der springende Punkt ist die Arbeit, die geleistet werden muss, um Lösungen für eine große Anzahl von Aufgaben in Code zu komprimieren. Es geht um die Universalisierung des Codes, bei der jede zusätzliche Syntax und Shells einfach destruktiv sind. Das ist harte Arbeit, aber es befreit von allem Überflüssigen und ermöglicht es Ihnen, sich weiterzuentwickeln und immer wieder neue Höhen zu erreichen.
 

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

2. Es geht darum, den Code zu universalisieren, wobei alle zusätzlichen Syntaxtechniken und Shells einfach destruktiv sind. Das ist harte Arbeit, aber es befreit dich von allem Überflüssigen und ermöglicht dir, dich ständig weiterzuentwickeln und neue Höhen zu erreichen.


1. Warum sich die Arbeit machen, wenn man es sich leicht und einfach machen kann? Warum sollte man es schwierig machen, wenn man es einfach machen kann?

2. Wenn Sie OOP verwenden, ist die Universalisierung nicht destruktiv, sondern wird zu einer natürlichen Möglichkeit, die nichts belastet.

 
Dmitry Fedoseev:

1. Warum sollte man sich die Arbeit machen, wenn sie leicht und einfach erledigt werden kann? Warum sollte man etwas tun, das einfach zu erledigen ist, wenn es schwierig ist?

2. Wenn Sie OOP verwenden, ist die Universalisierung nicht ruinös, sondern wird zu einer natürlichen Möglichkeit, die nichts belastet.

Mit diesem Argument können wir noch lange weitermachen. Am Beispiel einer 100-er Aufgabe habe ich meine Einstellung zu dieser Lösungsmethode aufgezeigt. Ich glaube, dass dumme Aufgaben nicht gelöst, sondern behoben werden sollten. Wenn OOP denjenigen hilft, die schwächer darin sind, Aufgaben richtig zu stellen und sie effektiv zu lösen - dann soll es ihnen auch weiterhin helfen. Aber für Leute, die Aufgaben optimieren, bevor sie sie lösen, ist OOP vielleicht einfach nicht nötig.

 
Реter Konow:

Wir könnten dieses Argument immer weiter ausführen. Am Beispiel einer 100-er Aufgabe habe ich meine Einstellung zu dieser Lösungsmethode aufgezeigt. Ich glaube, dass dumme Aufgaben nicht gelöst, sondern behoben werden sollten. Wenn OOP denjenigen hilft, die schwächer darin sind, Aufgaben richtig zu stellen und sie effektiv zu lösen - dann soll es ihnen auch weiterhin helfen. Aber für Leute, die Aufgaben optimieren, bevor sie sie lösen, ist OOP vielleicht einfach nicht nötig.


Sie haben nicht viel programmiert (wahrscheinlich), OOP ist wie ein Hauch von Luft.

Die meisten Menschen programmieren nicht aus Interesse oder zur Selbstentfaltung, sondern weil es ihr Job ist und das Ergebnis zählt.

 
Dmitry Fedoseev:

Es ist nicht annähernd so bequem, aber in Bezug auf die Geschwindigkeit können Sie mit Zeigern allein auskommen.

Und Bequemlichkeit ist ein relativer Begriff.


Dmitry, natürlich verringert die Verwendung von OOP die Leistung ein wenig. Aber es sind Bruchteile von Prozent.

Aber wie OOP die Leistung eines Programmierers erhöht!

Hier ist ein kleines Beispiel aus einem meiner Projekte, es ist für die Wahrnehmung ausgeschnitten, aber eigentlich gibt es eine Menge anderer Dinge zu berücksichtigen.

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;

Nehmen wir zum Beispiel .NET, da alle APIs aus Klassen bestehen.

Ich mag das .NET-Paradigma sehr. Übrigens gibt es ein tolles Terminal cAlgo, das Sie direkt in Visual Studio in C# schreiben können

 
Alexey Volchanskiy:

Dimitri, natürlich verringert die Verwendung von OOP die Leistung ein wenig. Aber es sind Bruchteile von Prozent.

Wenn die Anzahl der Varianten gering ist, wird sie sich verlangsamen, aber wenn es zu viele Varianten gibt, wird es ein Vorteil sein.

Das Wichtigste ist, dass die Anzahl der Varianten in OOP keinen Einfluss auf die Leistung hat. Und bei der prozeduralen Programmierung gibt es eine Obergrenze über Ihrem Kopf.

 

Nun, du hast es vermasselt...

Es ist klar, dass jede Aufgabe sowohl im OOP-Stil, mit der Zuweisung von Schnittstellen, dem Aufbau einer Vererbungshierarchie und der Deklaration von virtuellen Funktionen, als auch im rein prozeduralen Stil gelöst werden kann - man kann sogar alles in eine einzige große Funktion stecken.

Die Frage ist die nach der Bequemlichkeit und Effizienz der Unterstützung.

In MT ist das Auftragssystem der geeignetste Ort für OOP. Ich persönlich habe virtuelle Schnittstellen für "Position" und "Positionskomponenten". Eine "Position" ist eine Reihe von Aufträgen in MT4 oder eine Reihe von Positionen in MT5. "Positionskomponente" ist ein einzelner Auftrag oder eine einzelne MT5-Position (Hedge oder Netting).

Hier ist die eigentliche Schnittstellendatei(Retag Konow, Sie können die Anzahl der Kommentare im Vergleich zur Menge des Codes schätzen, und ich füge sie regelmäßig hinzu, wenn ich auf einige Feinheiten stoße, an die ich mich nicht erinnere. Ich vergesse zum Beispiel regelmäßig, welche realen Objekte eine "Positionskomponente" darstellen. Ich brauche mir das nicht zu merken - der Expert Advisor arbeitet mit Komponenten entsprechend der Schnittstelle, und was sich in Wirklichkeit hinter dieser Schnittstelle befindet, spielt keine Rolle. Aber ich muss während der Änderung darauf zurückkommen - deshalb brauche ich den ersten Kommentar in dieser Datei sehr oft):

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

Die Datei für die Schnittstelle der Handelskomponente sieht wie folgt aus (ich habe sie bereits oben angegeben, aber ich wiederhole sie hier:

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

Entsprechend dieser Schnittstellen habe ich sowohl das MT4- als auch das MT5-Ordersystem sowohl für reale als auch für historische Aufträge implementiert.

Der Expert Advisor, der eine Position anfordert, erhält diese Schnittstelle und muss den Unterschied zwischen MT4- und MT5-Aufträgen nicht berücksichtigen. Und wenn ein neuer Auftragstyp hinzugefügt oder die Reihenfolge der Arbeit mit ihnen geändert wird, ändert sich für den Expert Advisor nichts, nur die neue Auftragstypklasse wird hinzugefügt, und sie wird auch diese Schnittstelle unterstützen.

Das System war sehr sinnvoll, als die abgesicherten Konten eingeführt wurden. Die Experten haben sich überhaupt nicht verändert.

Reg Konow, wie gehen Sie mit dem Unterschied zwischen den Ordertypen in MT4 und MT5 um?

Wenn eine neue Kontoart eingeführt wird (zusätzlich zu Hedge und Netting) - welche Änderungen müssen dann vorgenommen werden, und zwar an derselben Stelle?

Ich bin der Meinung, dass, wenn Sie sich Ihren gesamten Code buchstabengetreu merken und Sie leicht sagen können, warum diese oder jene Zeile in Ihrem Code vor einem Jahr geschrieben wurde - dann stimmt es, dass all diese OOP-Verbesserungen nur unnötige Gesten sind.

OOP ist genau dann notwendig, wenn man sich nicht an alles erinnern kann, wenn man den Code ändert - OOP ermöglicht es, Blöcke voneinander zu isolieren und die Menge der zu einem bestimmten Zeitpunkt verfügbaren Einheiten auf eine bestimmte Stelle im Programm zu beschränken.

 
George Merts:

Nun, du hast es vermasselt...

1. Es ist klar, dass jede Aufgabe sowohl im OOP-Stil, mit der Zuweisung von Schnittstellen, dem Aufbau einer Vererbungshierarchie und der Deklaration virtueller Funktionen, als auch im rein prozeduralen Stil gelöst werden kann - wir können sogar alles in eine einzige große Funktion packen.

Die Frage ist die nach der Bequemlichkeit und Effizienz der Unterstützung.

2. In MT ist der am besten geeignete Ort für OOP das Auftragssystem. Ich persönlich habe virtuelle Schnittstellen "Positionen" und "Positionskomponenten". Eine "Position" ist eine Reihe von Aufträgen in MT4 oder eine Reihe von Positionen in MT5. "Positionskomponente" ist ein einzelner Auftrag oder eine einzelne MT5-Position (gehedgt oder netting).

3. Hier ist die eigentliche Schnittstellendatei(Retag Konow, Sie können die Anzahl der Kommentare im Vergleich zur Menge des Codes schätzen, und ich füge sie regelmäßig hinzu, wenn ich feststelle, dass ich mich an einige Feinheiten nicht erinnere. Ich vergesse zum Beispiel regelmäßig, welche realen Objekte eine "Positionskomponente" darstellen. Ich brauche mir das nicht zu merken - der Expert Advisor arbeitet mit Komponenten entsprechend der Schnittstelle, und was sich in Wirklichkeit hinter dieser Schnittstelle befindet, spielt keine Rolle. Aber ich muss während der Änderung darauf zurückkommen - deshalb brauche ich den ersten Kommentar in dieser Datei sehr oft):

Die Datei für die Schnittstelle der Handelskomponente sieht wie folgt aus (ich habe sie bereits oben angegeben, aber ich wiederhole sie hier:

Entsprechend dieser Schnittstellen habe ich sowohl das MT4- als auch das MT5-Ordersystem sowohl für reale als auch für historische Aufträge implementiert.

Der Expert Advisor, der eine Position anfordert, erhält diese Schnittstelle und muss den Unterschied zwischen MT4- und MT5-Aufträgen nicht berücksichtigen. Und wenn ein neuer Auftragstyp hinzugefügt oder die Reihenfolge der Arbeit mit ihnen geändert wird - für den Expert Advisor ändert sich nichts, es wird nur ein neuer Auftragstyp hinzugefügt, und er wird auch diese Schnittstelle unterstützen.

Das System erwies sich als sehr sinnvoll, als Hedging-Konten eingeführt wurden. Daran haben die Experten nichts geändert.

4. Reg Konow, wie gehen Sie mit dem Unterschied zwischen den Ordertypen in MT4 und MT5 um?

Wenn eine neue Kontoart eingeführt wird (zusätzlich zu Hedge und Netting) - welche Änderungen müssen dann vorgenommen werden, und zwar an derselben Stelle?

Ich denke, wenn Sie sich Ihren gesamten Code buchstabengetreu merken und leicht sagen können, warum diese oder jene Zeile vor einem Jahr in Ihrem Code geschrieben wurde, dann sind all diese OOP-Verbesserungen nur unnötige Gesten.

OOP ist gerade dann notwendig, wenn man sich nicht alles merken kann, wenn man den Code ändert - OOP ermöglicht es, Blöcke voneinander zu isolieren, um die Menge der zu einem bestimmten Zeitpunkt verfügbaren Einheiten auf eine bestimmte Stelle im Programm zu beschränken.

1. 1. ich stimme absolut zu. Der einzige Unterschied besteht in der Effektivität, mit der die Aufgaben auf die eine oder andere Weise gelöst werden.

2. Ich habe nicht wirklich mit dem Bestellsystem gearbeitet und kann keine technischen Probleme in seiner Konstruktion erkennen. Vielleicht gibt es die, aber wir brauchen eine konkrete Aufgabe und dann wird sich zeigen, wie effektiv ich sie ohne OOP lösen kann.

3. Meiner Meinung nach ist das angegebene Code-Beispiel von der Lesbarkeit her einfach furchtbar. Kein Wunder, dass so viele Kommentare erforderlich sind und dass man den Inhalt vergisst. Entschuldigung, aber das ist mein subjektiver erster Eindruck. Es ist einfach unheimlich.

Hier ist ein Beispiel für die Lesbarkeit meines Codes - die Funktion, die die Farbe des Elements eines Steuerelements definiert:

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

Wie Sie sehen können, sind Kommentare hier fast überflüssig. Mein gesamter Code ist in diesem Stil geschrieben. Ich kenne sie also sehr gut und kann mich an sie erinnern, egal welche Größe sie hat.


Meiner Meinung nach gibt es einen Fehler in Ihrem System zur Problemlösung. Das Problem selbst sollte glasklar und präzise sein, und damit auch seine Lösung. Wenn die Lösung unklar ist und mit den Worten "Das System hat sich als sehr vernünftig erwiesen" definiert wird (wie kann es in 270 KB Code vernünftig sein?!), bedeutet dies, dass der Autor eine grobe Vorstellung davon hat, wie sein System funktioniert. Und es sind schreckliche syntaktische Kunstgriffe und unnötige Einheiten in der Lösung, die ihn daran hindern, sie bis zum Ende zu verstehen.

Damit eine Lösung wirksam ist, müssen überflüssige Einheiten abgeschnitten werden, und das Problem muss ganz klar gesehen werden.