Форум » Консультации по программированию » Как грамотно инкапсулировать стркутуры? » Ответить

Как грамотно инкапсулировать стркутуры?

hoz: Есть несколько структур с хранениями некоторых данных, типа свойства символа, свойства позиции и тд. Логично, что эти данные должны использоваться в единственном экземпляре в различных классах, которые используют члены-элементы соответствующих структур. Например, вот структура свойств позиций: // =================================================_______ СВОЙСТВА ПОЗИЦИИ _______======================================================= struct Position_Properties { datetime gdt_Expiration; // Срок истечения отложенного ордера datetime gdt_OpenTime; // Время открытия выбранной позиции double gd_OpenPrice; // Цена открытия double gd_Lots; // Объём позиции на открытие double gd_CurSL; // Текущий Stop Loss выбранной позиции double gd_NewSL; // Новый Stop Loss выбранной позиции double gd_CurTP; // Текущий Take Profit выбранной позиции double gd_NewTP; // Новый Take Profit выбранной позиции int gi_CurTicket; // Тикет выбранного ордера int gi_Type; // Тип торговой операции int gi_Slippage; // Максимально допустимое отклонение цены для рыночных ордеров int gi_Magic; // Магический номер string gs_Comment; // Комментарий string gs_Symbol; // Наименование фин. инструмента, с которым производится операция ulong gu_Duration; // Длительность позиции в секундах }; Как реализовать проект так, чтоб классы данного проекта использовали единственный экземпляр данной структуры и работали только с ним, и, если модифицировали, то только этот экземпляр? Обязательно использовать синглтоны или можно обойтись без этого? В плане синглтонов я не особо понимаю как они работают, так что, думаю, что возможно иначе как-то...

Ответов - 19, стр: 1 2 All

Scriptong: hoz пишет: Обязательно использовать синглтоны или можно обойтись без этого? В данном случае singleton вообще не нужен. Просто используйте объявление переменной данного типа один раз. Singleton - это совершенно другое направление. PS. Избегайте названий переменных в стиле "gdt", "gd", "gs". Это стиль декомпилятора. Такой стиль - это "красная тряпка" для компилятора MQL4, который может посчитать Ваши исходные коды продуктом декомпиляции. В структурах вообще не используют префиксы для переменных. Префиксы используют для глобальных переменных ("g_" - global), настроечных параметров ("i_" - input) и членов класса ("m_" - member).

hoz: Scriptong пишет: В данном случае singleton вообще не нужен. Просто используйте объявление переменной данного типа один раз. Singleton - это совершенно другое направление. А для чего тогда он нужен? Я читал, что Singleton, как раз-таки и используется, для того, чтобы контролировать тот факт, что б некоторые переменные существовали в проекте в единственном экземпляре.

Scriptong: hoz пишет: А для чего тогда он нужен? К сожалению, простого ответа на этот вопрос нет, т. к. для обоснованного (а не надуманного) использования Singleton нужны такие специфические условия, которые вот так сходу не придумаешь. Кроме того речь идет о реально больших проектах, которые ни на MQL4, ни на MQL5 не создаются (нет таких удобств IDE, которые есть в Visual Studio, к примеру). Я веду к тому, что в MQL4 и MQL5 вполне возможно проконтролировать единственное использование переменной самому программисту. Не стоит усложнять программу там, где это совершенно не нужно. В данном случае объявите переменную типа Position_Properties как static и все. Если же Вам необходимо, чтобы ни одна другая переменная не имела тип Position_Properties (хотя сама такая необходимость вызывает удивление), то для этого достаточно воспользоваться поиском по файлам проекта и найти такие переменные, удалив их впоследствии.


hoz: Scriptong пишет: PS. Избегайте названий переменных в стиле "gdt", "gd", "gs". Это стиль декомпилятора. Такой стиль - это "красная тряпка" для компилятора MQL4, который может посчитать Ваши исходные коды продуктом декомпиляции. В структурах вообще не используют префиксы для переменных. Префиксы используют для глобальных переменных ("g_" - global), настроечных параметров ("i_" - input) и членов класса ("m_" - member). Игорь, Благодарю за совет. Дело в том, что я использую данные префиксы для того, чтоб видеть какой тип переменной или метода. Как-то уже и привык... gd - тип double, gs - тип string, gdt - тип datetime, gi - тип int. Отвыкать как-то снова лопать коды.. На данный момент компилятор не говорит, что у меня декомпил, так что обожду. Отложу этот момент на потом. Тем более глаз уже привык. Scriptong пишет: В данном случае объявите переменную типа Position_Properties как static и все. Если же Вам необходимо, чтобы ни одна другая переменная не имела тип Position_Properties (хотя сама такая необходимость вызывает удивление), то для этого достаточно воспользоваться поиском по файлам проекта и найти такие переменные, удалив их впоследствии. Вы имеете в виду объявить переменную типа Position_Properties как static или сам объект данной структуры? Я вот так на данный момент написал: struct Symbol_Properties { static datetime gdt_Quote; // Время поступления последней котировки static double gda_Price [2]; // Текущие рыночные цены (0 - Bid, 1- Ask) static double gd_Spread; // Размер спреда в пунктах static double gd_Swap; // Своп static double gd_Comission; // Комиссия static double gd_Pt; // Величина одного пункта static int gi_Digits; // Количество знаков в цене после запятой static int gi_StopLevel; // Минимально-допустимый уровень стоп-лосса/тейк-профита в пунктах static int gi_FreezLevel; // Уровень заморозки ордеров в пунктах }; int Symbol_Properties::gdt_Quote; int Symbol_Properties::gda_Price; int Symbol_Properties::gd_Spread; int Symbol_Properties::gd_Swap; int Symbol_Properties::gd_Comission; int Symbol_Properties::gd_Pt; int Symbol_Properties::gi_Digits; int Symbol_Properties::gi_StopLevel; int Symbol_Properties::gi_FreezLevel; Но получается что объект не создан. Что-то не верно у меня, так?

Scriptong: hoz пишет: Но получается что объект не создан. Что-то не верно у меня, так? 1. Структура - это не класс. Вы же пытаетесь обратиться к ней, как к классу. 2. SymbolProperties - это тип данных, а перед ним зачем-то указан еще один тип данных. Нужно так: SymbolProperties symbProp; // Переменная symbProp имеет тип SymbolProperties symbProp.gdt_Quote = StringToTime("2014.08.08 12:00:35"); symbProp.gda_Price[0] = 1.36579; symbProp.gda_Price[1] = 1.36589; symbProp.gd_Spread = symbProp.gda_Price[1] - symbProp.gda_Price[0]; symbProp.gd_Swap = 0.12; symbProp.gd_Commision = 0.0; symbProp.gd_Pt = 0.00001; symbProp.gi_Digits = 5; symbProp.gi_StopLevel = 3; symbProp.gi_FreezeLevel = 0;

hoz: В общем я сделал именно так: struct Symbol_Properties { static datetime gdt_Quote; // Время поступления последней котировки static double gda_Price [2]; // Текущие рыночные цены (0 - Bid, 1- Ask) static double gd_Spread; // Размер спреда в пунктах static double gd_Swap; // Своп static double gd_Comission; // Комиссия static double gd_Pt; // Величина одного пункта static int gi_Digits; // Количество знаков в цене после запятой static int gi_StopLevel; // Минимально-допустимый уровень стоп-лосса/тейк-профита в пунктах static int gi_FreezLevel; // Уровень заморозки ордеров в пунктах }; //---- Создадим объект структуре Symbol_Properties //Symbol_Properties SSym; datetime Symbol_Properties::gdt_Quote = 0; double Symbol_Properties::gda_Price [2] = {0.0, 0.0}; double Symbol_Properties::gd_Spread = 0; double Symbol_Properties::gd_Swap = 0; double Symbol_Properties::gd_Comission = 0; double Symbol_Properties::gd_Pt = 0; int Symbol_Properties::gi_Digits = 0; int Symbol_Properties::gi_StopLevel = 0; int Symbol_Properties::gi_FreezLevel = 0; Тока вот возникает мысль. Ведь удобнее обращаться к статическим переменным структуры не по такому длинному " имени " типа: double Symbol_Properties::gd_Pt = 0; А гораздо удобнее сразу передать данного значение соответствующей переменной типа: double Pt = Symbol_Properties::gd_Pt = 0; Но в таком случает компилятор ругается. Почему?

Scriptong: hoz пишет: В общем я сделал именно так: struct Symbol_Properties { static datetime gdt_Quote; // Время поступления последней котировки static double gda_Price [2]; // Текущие рыночные цены (0 - Bid, 1- Ask) static double gd_Spread; // Размер спреда в пунктах static double gd_Swap; // Своп static double gd_Comission; // Комиссия static double gd_Pt; // Величина одного пункта static int gi_Digits; // Количество знаков в цене после запятой static int gi_StopLevel; // Минимально-допустимый уровень стоп-лосса/тейк-профита в пунктах static int gi_FreezLevel; // Уровень заморозки ордеров в пунктах }; Описанное просто не имеет смысла. Об этом прямо говорит компилятор: struct has no members, size assigned to 1 byte - ни один из описанных членов структуры не воспринят, структура пустая Причина - указание членов структуры со спецификатором static. Это просто нонсенс, т. к. структура является типом данных, а не переменной. Статическими могут быть только переменные или члены класса, но не структур. hoz пишет: А гораздо удобнее сразу передать данного значение соответствующей переменной типа: double Pt = Symbol_Properties::gd_Pt = 0; Но в таком случает компилятор ругается. Почему? Замените на: double Pt = Symbol_Properties::gd_Pt; и все будет нормально с точки зрения синтаксиса. Хотя с точки зрения здравого смысла все очень плохо - зачем городить огород со структурами, если Вам проще использовать обычные локальные переменные?

hoz: Scriptong пишет: Причина - указание членов структуры со спецификатором static. Это просто нонсенс, т. к. структура является типом данных, а не переменной. Статическими могут быть только переменные или члены класса, но не структур. Это мне не понятно. Структура является типом данных ? Согласен. Но и класс тоже является типом данных. Так? Так! Получается, возникает вопрос, почему тогда у классах могут быть статические переменные, а у структур нет? Scriptong пишет: Хотя с точки зрения здравого смысла все очень плохо - зачем городить огород со структурами, если Вам проще использовать обычные локальные переменные? Если использовать просто переменные, то включая данный файл с переменными компилятор будет ругаться, что мол такие переменные "уже есть". Я это уже проходил. Т.е. при подгрузке каждого класса, например, с переменными: gdt_Expiration; gdt_OpenTime; gd_OpenPrice ; gd_Lots; gd_CurSL; gd_CurTP; gd_NewSL; gd_NewTP; gi_CurTicket; gi_Type; gi_Slippage; gi_Magic; gs_Comment; gs_Symbol; gu_Duration: Компилятор ругнётся, что каждый последующий раз когда будет подгружаться очередной класс( в который включён данный инклюдник к набором переменных ), что gdt_Expiration уже объявлен.. Раньше у меня такое было постоянно. Потому и пришлось прибегнуть к поиску другого варианта.

Scriptong: hoz пишет: Получается, возникает вопрос, почему тогда у классах могут быть статические переменные, а у структур нет? При всем сходстве структур и классов, у них есть множество различий. Одно из них - статические члены. hoz пишет: Компилятор ругнётся, что каждый последующий раз когда будет подгружаться очередной класс( в который включён данный инклюдник к набором переменных ), что gdt_Expiration уже объявлен.. Раньше у меня такое было постоянно. Потому и пришлось прибегнуть к поиску другого варианта. Тогда Вам нужно просто создать ОДИН-ЕДИНСТВЕННЫЙ включаемый файл, в котором описать необходимую структуру. И уже этот включаемый файл подключать ко всем своим проектам. Тогда и проблемы не будет. Вообще же создание единой "библиотеки" включаемых файлов - хорошая и удобная вещь. Посмотрите на мои проекты. Многие из них используют включаемые файлы: Common_Trade.mqh, Common_MathUtils.mqh, Common_GetSymbol.mqh. Эти файлы лежат в отдельной папке Common, которую я подключаю к новому проекту, если типы данных или функции, описанные в этих включаемых файлах, мне нужны.

hoz: Scriptong пишет: Тогда Вам нужно просто создать ОДИН-ЕДИНСТВЕННЫЙ включаемый файл, в котором описать необходимую структуру. И уже этот включаемый файл подключать ко всем своим проектам. Тогда и проблемы не будет. Я так и делаю. Но когда решил сделать члены статическими возникли проблемы. Scriptong пишет: Вообще же создание единой "библиотеки" включаемых файлов - хорошая и удобная вещь. Посмотрите на мои проекты. Многие из них используют включаемые файлы: Common_Trade.mqh, Common_MathUtils.mqh, Common_GetSymbol.mqh. Эти файлы лежат в отдельной папке Common, которую я подключаю к новому проекту, если типы данных или функции, описанные в этих включаемых файлах, мне нужны. Да, у Вас там серьёзный код. Нужно разбирать его. На это уйдёт некоторое время. Не так всё просто там.

Scriptong: hoz пишет: Но когда решил сделать члены статическими возникли проблемы. Предлагаю отталкиваться от простого факта - сделать статическими члены структуры не получится. Переделайте на класс, если уж так необходимо, хотя и не понимаю, зачем в данном случае это нужно.

hoz: Scriptong пишет: зачем в данном случае это нужно Почему? Как тогда нужно по Вашему? Scriptong пишет: Предлагаю отталкиваться от простого факта - сделать статическими члены структуры не получится. Как я понял, это всё недочёт мкл4. Вы и сами видели, что модератор на форуме метаквотов не смог ответить на вопрос. Да и в конце темы, которую я подымал там это всё-таки выяснилось. А что скажите по поводу статического объекта? class MyClass { }; static MyClass MyClassObj;

Scriptong: hoz пишет: А что скажите по поводу статического объекта? Ничего хорошего, т. к. в таком случае можно просто использовать обычные глобальные/локальные переменные в единственном экземпляре. Смысл использования статических типов данных в ООП заключается именно в том, чтобы иметь единое место хранения данных для всех объектов одного типа и при этом иметь гарантию невмешательства в эти данные со стороны других объектов. То есть речь идет именно о статических членах классов. Других практических примеров статических переменных я не вижу. Это больше подходит для академических изысков, к которым я, как практикующий программист, отношусь более чем прохладно.

hoz: Scriptong пишет: Это больше подходит для академических изысков Т.е. хотите сказать, что вариант предложенный модератором с форума метаквотов "не годным"? Имею ввиду для той задачи, которую я поставил. В плане инкапсуляции как я вижу это так. Но он по ходу этого так и не понял или просто мкл4 не позволяет это реализовать проще. Потому мало кто это умеет. То что у Вас это реализовано я видел. Но такой подход я осилю чутка позже Scriptong пишет: Это больше подходит для академических изысков, к которым я, как практикующий программист, отношусь более чем прохладно. Как же прохладно... У Вас же именно так и написан код... Весь инкапсулирован!

Scriptong: hoz пишет: Т.е. хотите сказать, что вариант предложенный модератором с форума метаквотов "не годным"? Какой именно вариант? Если Вы про объект, объявленный статически, то я по нему уже высказался. А насчет того, что кто-то там предложил такой вариант, нужно смотреть полный текст его предложения, чтобы ответить предметно. Ведь очень часто фразы попросту вырываются из контекста. hoz пишет: Имею ввиду для той задачи, которую я поставил. К сожалению, поставленные Вами цели для меня до сих пор остаются загадкой. Опишите свою задачу как можно подробнее, без абстракций, на конкретном примере. hoz пишет: Как же прохладно... У Вас же именно так и написан код... Весь инкапсулирован! Вот свежий пример вырывания фразы из контекста. Цитируемое Вами относится к рассуждениям о статическом объекте, а не о механизме инкапсуляции в целом.

hoz: Scriptong пишет: Какой именно вариант? Если Вы про объект, объявленный статически, то я по нему уже высказался. А насчет того, что кто-то там предложил такой вариант, нужно смотреть полный текст его предложения, чтобы ответить предметно. Ведь очень часто фразы попросту вырываются из контекста. Именно, про статический объект я и имел ввиду. Больше они ничего предложить не смогли. Scriptong пишет: Вот свежий пример вырывания фразы из контекста. Цитируемое Вами относится к рассуждениям о статическом объекте, а не о механизме инкапсуляции в целом. Нет. Речь как раз-таки идёт о механизме инкупсуляции, а не о статических объектах. Т.к. я опирался на Ваш совет, посмотреть как реализовано у Вас это. Например, проект VPMA. Так я чётко увидел как у Вас реализованы подобные задачи. Так что вопрос этот как появится энтузиазм - разберу. С первого взгляда с большего понятно, но не привычно. Scriptong пишет: К сожалению, поставленные Вами цели для меня до сих пор остаются загадкой. Опишите свою задачу как можно подробнее, без абстракций, на конкретном примере. Конкретно, есть, структура, элементы которой являются, на данный момент обычными переменными простого типа. struct Position_Properties { datetime gdt_Expiration; // Срок истечения отложенного ордера datetime gdt_OpenTime; // Время открытия выбранной позиции double gd_OpenPrice; // Цена открытия double gd_Lots; // Объём позиции на открытие double gd_CurSL; // Текущий Stop Loss выбранной позиции double gd_NewSL; // Новый Stop Loss выбранной позиции double gd_CurTP; // Текущий Take Profit выбранной позиции double gd_NewTP; // Новый Take Profit выбранной позиции int gi_CurTicket; // Тикет выбранного ордера int gi_Type; // Тип торговой операции int gi_Slippage; // Максимально допустимое отклонение цены для рыночных ордеров int gi_Magic; // Магический номер string gs_Comment; // Комментарий string gs_Symbol; // Наименование фин. инструмента, с которым производится операция ulong gu_Duration; // Длительность позиции в секундах } Необходимо, чтоб данные члены-элементы: 1. Не зависели от конкретного экземпляра структуры. 2. Данные члены-элементы были надёжно инкапсулированы. В сервисдеске мне ответили так: " К сожалению, сделать то, что Вам можно только через макросы: #define Swap Symbol_Properties::gd_Swap " Игорь, а Вы что об этом думаете? Дело в том, что по-моему это не вариант. Т.к. подобные дефайны применимы, разве что, в случае, когда члены-элементы структуры будут не массивами. А если иначе, то придётся создавать теоретически огромное количество дефайнов, что, в любом случает, не удобно.

Scriptong: hoz пишет: Конкретно, есть, структура, элементы которой являются, на данный момент обычными переменными простого типа. К сожалению, это не описание. Это попытка решения. Опишите саму задачу. То, что Вы в моих проектах называете инкапсуляцией, является простым разложением задачи на более мелкие задачи. Для каждой такой подзадачи и создается отдельный класс. Больше ни для чего такая инкапсуляция мне и не нужна. Хотя у нее есть несомненный плюс: в будущем, при усложнении задачи, я автоматически избавляюсь от возможных багов в программе, т. к. все подзадачи решаются максимально независимо друг от друга, пересекаясь лишь при помощи специальных интерфейсов между ними.

hoz: Игорь, я видимо сам запутался. Когда задавал вопрос думал иначе, а щяс вижу то, что спрашивал по-другому. Вопрос закрываю на данный момент. В соседнем топике задам новый... Уже конкретный.

Scriptong: hoz пишет: Игорь, я видимо сам запутался. Это часто бывает Так вот сидишь на какой-то задачей - непробиваемо. Затем отвлечешься, забудешь о ней на какое-то время, а потом, возвращаясь к ней, с удивлением обнаруживаешь, что двигался совершенно не в том направлении. Оказывается, решение лежало в другой плоскости.



полная версия страницы