OOP与程序化编程 - 页 10

Реter Konow:
是的,这些单位都有。但相信我--它们被压缩到最大,而且用途广泛,因为它们能解决广泛的问题。

如果没有很多选择,你可以用ifs和swipe来解决。

为什么没有人决定争论 "带函数指针的程序化编程与不带函数指针的程序化编程"?

Dmitry Fedoseev:

如果没有很多选择,你可以用ifs和swipe来解决。

问题的关键在于需要做的工作,即在代码中压缩大量任务的解决方案。这件事是关于代码的通用化,在这里任何额外的语法和外壳都是简单的破坏性的。这是艰苦的工作,但它摆脱了一切多余的东西,使你能够不断发展,一直达到新的高度。

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

2.关键是要普及代码,其中任何额外的语法技术和外壳都只是破坏性的。这是一项艰苦的工作,但它摆脱了一切多余的东西,使你能够不断发展,达到新的高度。


1.如果你能让工作变得轻松简单,为什么还要做这些工作?如果你能让它变得简单,为什么还要让它变得困难?

2.如果你使用OOP,通用化就不是破坏性的,而是成为一种自然的可能性,不会给任何东西带来负担。

Dmitry Fedoseev:

1.既然可以轻松自如地完成工作,为什么还要做呢?为什么要做一些容易做的事,而做起来却很困难?

2.如果你使用OOP,那么通用化就不会被破坏,而是成为一种自然的可能性,不会给任何东西带来负担。

我们可以继续这个论点很长时间。用一个100个拖曳任务的例子,我表明了我对这种解决方法的态度。我认为,愚蠢的任务不应该被解决,而应该被修复。如果OOP能帮助那些在提出和正确解决任务方面比较弱的人,就让它帮助他们吧。但是对于那些在开始解决任务之前就对任务进行优化的人来说,可能根本不需要OOP。

Реter Konow:

我们可以不断地进行这种争论。用一个100个拖曳任务的例子,我表明了我对这种解决方法的态度。我认为,愚蠢的任务不应该被解决,而应该被修复。如果OOP能帮助那些在提出和正确解决任务方面比较弱的人,就让它帮助他们吧。但是对于那些在开始解决任务之前就对任务进行优化的人来说,可能根本不需要OOP。


你没怎么编过代码(可能),OOP就像一股空气。

大多数人编码不是为了兴趣或自我发展,这是他们的工作,而结果才是最重要的。

Dmitry Fedoseev:

它没有那么方便,但就速度能力而言,你可以只用指针就能搞定。

而方便是一个相对的概念。


Dmitry,当然使用OOP 会降低一些性能。但这是百分之一的几分之一。

但是,OOP是如何提高程序员的性能的!?

这是我的一个项目中的一个小例子,它是为了感知而切割的,但实际上还有很多其他的东西被考虑在内。

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;

例如,让我们以.NET为例,因为所有的API都由类组成。

我非常喜欢.NET范式。 顺便说一下,有一个伟大的终端cAlgo,你可以直接在Visual Studio中用C#编写

Alexey Volchanskiy:

Dimitri,当然使用OOP 会降低一些性能。但这是百分之一的零头。

如果变体数量少,就会减慢速度,但如果变体数量太多,就会成为一种优势。

最重要的是,OOP中变体的数量并不影响性能。而在程序化编程中,你的头顶上有一个天花板。

好吧,你把事情搞得一团糟......。

很明显,任何任务都可以用OOP风格来解决,包括分配接口、建立继承层次、声明虚拟函数,也可以用纯程序风格来解决--你甚至可以把所有东西都放在一个巨大的函数中。

问题在于支持的便利和效率。

在MT--最适合OOP的地方是订单系统。就个人而言,我有 "位置 "和 "位置组件 "的虚拟接口。"头寸 "在MT4中是一组订单,在MT5中是一组头寸。"头寸组成部分 "是指单个订单或单个MT5头寸(对冲或净值)。

这是实际的界面文件(Retag Konow,你可以欣赏到与代码量相比,注释的数量,当我遇到我不记得一些细微之处,我定期在那里添加注释。例如,我经常忘记哪些真实物体构成了 "位置组件"。我只是不需要记住它--专家顾问根据界面与组件一起工作,现实中界面后面是什么并不重要。但是,我必须在修改过程中回到它 - 这就是为什么我经常需要这个文件中的第一个注释)。

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

贸易组件接口的文件如下(我已经在上面给出了,但我要重复一下。

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

根据这些接口--我同时实现了MT4和MT5的订单系统,用于真实和历史订单。

请求建仓的专家顾问收到这个界面,不必考虑MT4和MT5订单之间的差异。如果增加了一个新的订单类型,或者改变了与它们的工作顺序--对专家顾问来说不会有任何改变,只会增加新的订单类型类,它也将支持这个接口。

在引入对冲账户时,该系统有很大的意义。专家们一点也没有改变。

Reg Konow,你是如何处理MT4和MT5中订单类型的差异的?

如果引入一个新的账户类型(除了套期保值和净额结算外)--需要做哪些改变,而且是在同一个地方?

我的看法是,如果你把所有的代码都记得一清二楚,而且你可以很容易地说出为什么你的代码中的这一行或那一行是一年前写的--那么,这是真的,所有这些OOP的改进都只是不必要的姿态。

当你在修改代码时不记得所有的事情时,OOP是必要的--OOP允许将区块相互隔离,将任何特定时刻可用的实体集合限制在程序的特定位置。

George Merts:

好吧,你把事情搞得一团糟......。

1.很明显,任何任务都可以用OOP风格来解决,包括分配接口、建立继承层次、声明虚拟函数,也可以用纯程序风格来解决--我们甚至可以把所有东西都放到一个巨大的函数里。

问题在于支持的便利和效率。

2.在MT--最适合OOP的地方是订单系统。就个人而言,我有虚拟接口 "位置 "和 "位置组件"。"头寸 "在MT4中是一组订单,在MT5中是一组头寸。"头寸组成部分 "是指单个订单或单个MT5头寸(套期保值或净值化)。

3.这是实际的界面文件(Retag Konow,你可以欣赏到与代码量相比,注释的数量,当我遇到我不记得一些细微之处,我定期在那里添加注释。例如,我经常忘记哪些真实物体构成了 "位置组件"。我只是不需要记住它--专家顾问根据界面与组件一起工作,现实中界面后面是什么并不重要。但是,我必须在修改过程中回到它 - 这就是为什么我经常需要这个文件中的第一个注释)。

贸易组件接口的文件如下(我已经在上面给出了,但我要重复一下。

根据这些接口--我同时实现了MT4和MT5的订单系统,用于真实和历史订单。

请求建仓的专家顾问收到这个界面,不必考虑MT4和MT5订单之间的差异。而如果增加了新的订单类型,或者改变了与它们的工作顺序--对专家顾问来说,什么都不会改变,只是增加了一个新的订单类型,它也将支持这个界面。

该系统被证明是非常合理的,当时引入了对冲账户。专家们在这一点上没有任何改变。

4.Reg Konow,你是如何处理MT4和MT5中订单类型的差异的?

如果引入一个新的账户类型(除了套期保值和净额结算外)--需要做哪些改变,而且是在同一个地方?

我认为,如果你对你的所有代码都记得一清二楚,而且你可以很容易地说出一年前为什么要在你的代码中写这一行或那一行--那么所有这些OOP增强器都只是不必要的姿态。

恰恰是当你在修改代码时不记得所有的东西时,OOP是必要的--OOP允许你将块相互隔离,以限制在任何特定时刻可用的实体集在程序中的特定位置。

1.1.我完全同意。唯一的区别在于以这种或那种方式解决任务的有效性。

2.我没有真正使用过订单系统,也看不出它的结构有什么技术问题。也许有,但我们需要一个具体的任务,然后就会清楚我在没有OOP的情况下能如何有效地解决它。

3.在我看来,从可读性的角度来看,给出的代码样本简直是糟糕透顶。难怪需要这么多评论,也难怪你会忘记它的内容。对不起,但这是我主观的第一印象。这只是令人毛骨悚然。

下面是我的代码可读性的一个例子--定义控件项颜色的函数。

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

正如你所看到的,评论在这里几乎是不必要的。我所有的代码都是用这种风格写的。所以我对它非常了解,不管它是什么尺寸,我都能记住它。


在我看来,你的问题解决系统中存在一些缺陷。问题本身应该是非常清晰和准确的,因此它的解决方案也是如此。如果解决方案是云里雾里的,并由 "事实证明系统是非常合理的 "这句话来定义(在270Kb的代码中怎么可能是合理的呢!),这意味着作者对他的系统如何工作有一个粗略的理解。而解决方案中可怕的语法构思和多余的实体,使他无法理解到最后。

为了使解决方案有效,必须切断不必要的实体,而且必须完全看清问题。