Bmw-rumyancevo.ru

БМВ Мастер — Автожурнал
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Наследование, композиция, агрегация

Наследование, композиция, агрегация

Нередко случается, что решив разобраться с какой-то новой темой, понятием, инструментом программирования, я читаю одну за другой статьи на различных сайтах в интернете. И, если тема сложная, то эти статьи могут не на шаг не приблизить меня к понимаю. И вдруг встречается статья, которая моментально дает озарение и все паззлы складываются воедино. Трудно определить, что отличает такую статью от других. Правильно подобранные слова, оптимальная логика изложения или же просто более релевантный пример. Я не претендую на то, что моя статься окажется новым словом в C# или же лучшей обучающей статьей. Но, возможно для кого-то она станет именно той, которая позволит разобраться, запомнить и начать правильно применять те понятия, о которых пойдет речь.

В объектно-ориентированных языках программирования существует три способа организации взаимодействия между классами. Наследование — это когда класс-наследник имеет все поля и методы родительского класса, и, как правило, добавляет какой-то новый функционал или/и поля. Наследование описывается словом «является». Легковой автомобиль является автомобилем. Вполне естественно, если он будет его наследником.

Ассоциация – это когда один класс включает в себя другой класс в качестве одного из полей. Ассоциация описывается словом «имеет». Автомобиль имеет двигатель. Вполне естественно, что он не будет являться наследником двигателя (хотя такая архитектура тоже возможна в некоторых ситуациях).

Выделяют два частных случая ассоциации: композицию и агрегацию.

Композиция – это когда двигатель не существует отдельно от автомобиля. Он создается при создании автомобиля и полностью управляется автомобилем. В типичном примере, экземпляр двигателя будет создаваться в конструкторе автомобиля.

Агрегация – это когда экземпляр двигателя создается где-то в другом месте кода, и передается в конструктор автомобиля в качестве параметра.

Хотя ведутся дискуссии о преимуществах того или иного способа организации взаимодействия между классами, какого-либо абстрактного правила не существует. Разработчик выбирает тот или иной путь основываясь на элементарной логике (“является” или “имеет”), но также принимает во внимание возможности и ограничения, которые дают и накладывают эти способы. Для того, чтобы увидеть эти возможности и ограничения, я попытался написать пример. Достаточно простой, чтобы код оставался компактным, но и достаточно развитый, чтобы в рамках одной программы можно было применить все три способа. И, главное, я попытался сделать этот пример как можно менее абстрактным – все объекты и экземпляры понятны и осязаемы.

Напишем простенькую игру – танковый бой. Играют два танка. Они поочередно стреляют и проигрывает тот, здоровье которого упало до нуля. В игре будут различные типы снарядов и брони. Для того, чтобы нанести урон необходимо во-первых, попасть по танку противника, во-вторых, пробить его броню. Если броня не пробита, урон не наносится. Логика игры построена на принципе «камень-ножницы-бумага»: то есть броня одного типа хорошо противостоит снарядам определенного типа, но плохо держит другие снаряды. Кроме того, снаряды, которые хорошо пробивают броню, наносят малый «заброневой» урон, и, напротив, наиболее «летальные» снаряды имеют меньше шансов пробить броню.

Создадим простенький класс для пушки. Он будет иметь два приватных поля: калибр и длину ствола. От калибра зависит урон, и, частично, способность к пробитию брони. От длины ствола – точность стрельбы.

Сделаем также конструктор для пушки:

Сделаем метод для получения калибра из других классов:

Помните, что для поражения цели должно произойти две вещи: попадание в цель и пробитие брони? Так вот, пушка будет отвечать за первую из них: попадание. Поэтому делаем булевый метод IsOnTarget, который принимает случайную величину (dice) и возвращает результат: попали или нет:

Целиком класс пушки выглядит следующим образом:

Теперь сделаем снаряды – это наиболее очевидный случай для применения наследования, но и агрегацию в нем тоже применим. Любой снаряд имеет свои особенности. Просто неких гипотетических снарядов не бывает. Поэтому класс делаем абстрактным. Делаем ему строковое поле «тип».

Снаряды делают для пушек. Для определенных пушек. Снаряд одного калибра не выстрелит из пушки другого калибра. Поэтому добавляем снаряду поле-ссылку на экземпляр пушки. Делаем конструктор.

Здесь мы применили агрегацию. Где-то будет создана пушка. Потом к этой пушке будут создаваться снаряды, которые имеют указатель на пушку.

Конкретные типы снарядов будут наследниками абстрактного снаряда. Наследники могут просто наследовать методы родителя, но могут и быть переопределены, то есть работать не так, как родительский метод. Но мы точно знаем, что любой снаряд должен иметь ряд методов. Любой снаряд должен наносить урон. Метод GetDamage просто возвращает калибр, умноженный на три. В общем случае, урон снаряда зависит от калибра. Но этот метод будет переопределяться в дочерних классах (помним, что снаряды, которые хорошо пробивают броню, как правило наносят меньший «заброневой» урон. Чтобы иметь возможность переопределить метод в дочернем классе, используем слово virtual.

Любой снаряд должен пробивать (или по крайней мере пытаться пробить) броню. В общем случае способность пробивать броню также зависит от калибра (ну, и еще от многого – начальной скорости, например, но мы не будем усложнять). Поэтому, метод возвращает калибр. То есть, грубо говоря, снаряд может пробить броню, равную по толщине своему калибру. Этот метод не будет переопределяться в дочерних классах.

Кроме того, для удобной отладки и организации консольного вывода, имеет смысл добавить метод ToString, который просто позволит нам увидеть, что это за снаряд и какого калибра:

Теперь сделаем разные типы снарядов, которые будут наследовать абстрактный снаряд: фугасный, кумулятивный, подкалиберный. Фугасный наносит самый большой урон, кумулятивный – меньше, подкалиберный – еще меньше. Дочерние классы не имеют полей и вызывают конструктор базового снаряда, передавая ему пушку, и строковый тип. В дочернем классе переопределяется метод GetDamage() – вносятся коэффициенты, которые увеличат или уменьшат урон по сравнению с дефолтным.

Фугасный (дефолтный урон):

Кумулятивный (дефолтный урон х 0.6):

Читать еще:  271 двигатель мерседеса технические характеристики

Подкалиберный (дефолтный урон х 0.3):

Обратите внимание, что в переопределенном методе GetDamage вызывается и метод базового класса. То есть, переопределив метод, мы также сохраняем возможность обратиться к дефолтному методу, использовав ключевое слово base).

Итак, для снарядов мы применили и агрегацию (пушка в базовом классе), и наследование.
Создадим теперь броню для танка. Здесь применим только наследование. Любая броня имеет толщину. Поэтому абстрактный класс брони будет иметь поле thickness, и строковое поле type, которое будет определятся при создании дочерних классов.

Броня будет в нашей игре определять пробита они или нет. Поэтому, у нее будет лишь один метод, который будет переопределяться в дочерних, в зависимости от типа брони.

А пробита они или нет – зависит от того, какой прилетел снаряд: в дефолтном случае какого калибра. Поэтому метод принимает экземпляр снаряда и возвращает булевый результат: пробита или нет. Создадим несколько типов брони – наследников абстрактной брони. Приведу код лишь одного типа – логика примерно такая же, как и в снарядах. Гомогенная броня хорошо держит фугасный снаряд, но плохо – подкалиберный. Поэтому, если прилетел подкалиберный снаряд, который имеет высокую бронепробиваемость, то в вычислениях наша броня как-бы становится тоньше. И так далее: каждый вид брони имеет свой набор коэфициентов устойчивости к тому или иному снаряду.

Здесь мы используем одно из чудес, которые дает полиморфизм. Метод принимает любой снаряд. В сигнатуре указан базовый класс, а не дочерние. Но внутри метода, мы можем увидеть, что за снаряд прилетел – какого типа. И в зависимости от этого, реализуем ту или иную логику. Если бы мы не применили наследование для снарядов, а сделали просто три уникальных класса типов снарядов, то проверку пробития брони пришлось бы организовывать иначе. Нам пришлось бы писать столько перегруженных методов, сколько типов снарядов у нас в игре, и вызывать один из них в зависимости от того, какой снаряд прилетел. Это тоже было бы довольно изящно, но не относится к теме данной статьи.

Теперь у нас все готово для создания танка. В танке не будет наследования, но будет композиция и агрегация. Разумеется, у танка будет название. У танка будет пушка (агрегация). Для нашей игры сделаем допущение, что танк может «переодевать» броню перед каждым ходом – выбрать тот или иной тип брони. Для этого, у танка будет список типов брони. У танка будет боеукладка – список снарядов, который будет наполнен снарядами, созданными в конструкторе танка (композиция!). У танка будет здоровье (уменьшается при попадании в него), и, у танка будет текущая выбранная броня и текущий выбранный снаряд.

Для того, чтобы конструктор танка остался более-менее компактным, сделаем два вспомогательных приватных метода, которые добавляют три типа брони соответствующей толщины, и наполняют боеукладку 10 снарядами каждого из трех типов:

Теперь конструктор танка выглядит вот таким образом:

Обратите внимание, что здесь мы снова используем возможности полиморфизма. Наша боекладка вмещает снаряды любого типа, так как список имеет тип данных Ammo – родительский снаряд. Если бы мы не наследовались, а создавали уникальные типы снарядов, пришлось бы делать отдельный список под каждый тип снаряда.

Пользовательский интерфейс танка состоит из трех методов: выбрать броню, зарядить пушку, выстрелить.

Как я упомянул в начале, в этом примере я старался максимально уйти от абстрактных понятий, которые нужно все время держать в голове. Поэтому каждый экземпляр снаряда у нас равен физическому снаряду, который положили в боеукладку перед боем. Следовательно, снаряды могут закончится в самый неподходящий момент!

Здесь – поподробнее. Во-первых, есть проверка заряжена ли пушка. Во-вторых, снаряд, который вылетел из ствола, уже не существует для данного танка, его уже нет ни в пушке, ни в боеукладке. Но физически он еще существует – летит по направлению к цели. И если попадет, будет участвовать в вычислении пробития брони и урона цели. Поэтому, мы сохраняем этот снаряд в новой переменной: Ammo firedAmmo. Поскольку на следующей же строке данный снаряд перестанет существовать для данного танка, придется использовать интерфейс IClonable для базового класса снаряда:

Этот интерфейс требует реализации метода Clone(). Вот она:

Теперь все супер реалистично: при выстреле генерируется dice, пушка рассчитывает попадание своим методом IsOnTarget, и, если попадание есть, то метод Shoot вернет экземпляр снаряда, а если промах – то вернет null.

Последний метод танка – его поведение при попадании вражеского снаряда:

Снова полиморфизм во всей красе. К нам прилетает снаряд. Любой. Исходя из выбранной брони и типа снаряда, вычисляется пробита броня или нет. Если пробита, то вызывается метод конкретного типа снаряда GetDamage().

Все готово. Остается только написать консольный (или неконсольный) вывод, в котором будет обеспечен пользовательский интерфейс и в цикле реализованы поочередные ходы игроков.

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

  • собственно, скопировать один из существующих типов, заменив название и строковое поле, передаваемое в конструктор;
  • добавить еще один if в дочерние классы брони;
  • добавить дополнительный пункт в меню выбора снаряда в пользовательском интерфейсе.

Аналогично, чтобы добавить еще одну разновидность брони, требуется лишь описать эту разновидность и добавить пункт в пользовательский интерфейс. Модифицировать другие классы или методы не требуется.

Читать еще:  Двигатель f16d3 какое масло лить

Ниже – приведена диаграмма наших классов.

В финальном коде игры все «магические числа», которые использовались в тексте, вынесены в отдельный статический класс Config. К публичным полям статического класса мы можем обратиться из любого фрагмента нашего кода и его экземпляр не нужно (и невозможно) создавать. Вот так он выглядит:

И благодаря этому классу мы можем производить дальнейшую настройку, меняя параметры лишь здесь, без дальнейшего углубления в классы и методы. Если, например, мы пришли к выводу, что подкалиберный снаряд получился слишком сильным, то мы меняем одну циферку в Config.
Весь код игры можно увидеть вот здесь.

Что такое композиция двигателя

NanoFull : для двигателей внутреннего сгорания

Это состав, который показывает результаты уже через 30 минут и максимум эффекта через 3-5 т. км:

  • ПРИ ЗАКАЗЕ ВТОРАЯ В ПОДАРОК.
  • 1. Устраняет шумы в двигателе.
  • 2. Возрастает «приёмистость».
  • 3. Повышает и выравнивает компрессию.
  • 4. Восстанавливает частично узлы и механизмы.
  • 5. Восстанавливает эластичность сальников.
  • 6. Снижает расход топлива и масла.
  • 7. Снижает температуру в узлах трения.
  • 8. Полная защита при экстремальных нагрузках. (многочасовые пробки, протечки, жара и мороз).

Подробности обработки в меню «Инструкция применения» пункт №2

NanoFull : для механических коробок переключения передач.

Это состав, который может восстанавливать изношенные узлы и механизмы в механических коробках передач, мостах, раздатках.

  • ПРИ ЗАКАЗЕ ВТОРАЯ В ПОДАРОК.
  • 1. Устраняет шумы и вибрацию.
  • 2. Мягкость включение скоростей.
  • 3. Уменьшает трение и расход топлива.
  • 4. Увеличивает срок службы масла.

NanoFull : для автоматических коробок переключения передач.

Это состав, который может восстанавливать изношенные узлы и механизмы в автоматических коробках передач и гидравлическом усилители руля(ГУР). Устраняет шумы, вибрацию и (пенки). Для ГУРа: устраняет шумы, возникает легкость вращения руля.

  • ПРИ ЗАКАЗЕ ВТОРАЯ В ПОДАРОК.
  • 1. Мягкость работы механизмов.
  • 2. Уменьшает трение и расход топлива.
  • 3. Увеличивает срок службы масла.

NanoFull : для топливных насосов высокого давления дизельных двигателей.

Состав, который может восстановить изношенные механизмы ТНВД и форсунок:

  • БЕСПЛАТНАЯ ДОСТАВКА!
  • 1. Восстановить давление ТНВД и форсунок.
  • 2. Увеличивает приемистость двигателя.
  • 3. Уменьшает шумы и громкость работы топливной аппаратуры.
  • 4. Уменьшает выбросы черного дыма из выхлопной трубы.
  • 5. Уменьшает расход топлива.

Подробности обработки в меню «Инструкция применения» пункт №4

Инструкция по применению

Если композиция заливается через маслозаливную горловину, состав заливается, когда двигатель выключен.

  • 3 — Затем необходимо дать поработать двигателю в холостом режиме в течение 10-15 мин.
  • После эксплуатировать в штатном режиме, избегая критических (максимальных) нагрузок первые 100 км эксплуатации. Если двигатель имеет внутренние масляные загрязнения, то рекомендуется после использования состава заменить масляный фильтр через 500 км. пробега после первой обработки.

  • 2.3. Такой же порядок обработки использовать в новых двигателях, и в двигателях после капитального ремонт (расточка, шлифовка, замена изношенных механизмов).
  • 2.4. Если необходима вторая обработка двигателя, можно заливать композицию в старое масло через 1 -1.5 тыс. км после первой обработки. После этого эксплуатировать двигатель не менее 1 – 1.5 тыс. км. В некоторых случаях может потребоваться третья обработка. Она производится непосредственно после замены старого масла.
  • 2.5. Во время штатной замены масла любыми промывочными средствами для двигателя пользоваться необязательно.
  • 2.6. В зависимости от износа механизмов, возможно потребуется повторить циклы обработки двигателя. Для более точного определения состояния механизмов, желательно использовать измерительные приборы ( компрессометр, АГЦ – 2), как перед первой обработкой, так и при последующих обработках.
    • 3. Обработка механических коробок передач, редукторов, раздаточных коробок.
      • 3.1. Для обработки вышеуказанных узлов применяется композиция НАНОФУЛЛ-ТРАНСМИССИЯ.
      • 3.2. Композиция вносится через заливное отверстие или через отверстие для щупа из расчета 25-30 мл на 1л масла.
      • 3.3. При сильных износах узлов, когда шум, вибрация не полностью прекращаются необходимо повторить обработку после 1-1.5 тыс. км пробега (добавить новую порцию композиции в то же масло).
    • 4. Обработка топливных насосов высокого давления (ТНВД) и форсунок.
      • 4.1. Для обработки ТНВД и форсунок, кроме систем Common Rail, используется композиция НАНОФУЛЛ-ТОПЛИВНЫЙ НАСОС.

        Примечание: НАНОФУЛЛ обладает высоким чистящим эффектом, поэтому загрязнения и наслоения, которые в результате чистки придут в движение, могут попасть в регулятор давления системы Common Rail и тем нарушить её функциональность. Если двигатель, оснащенный системой Common Rail, работает не удовлетворительно по вине регулятора давления, то вследствие описанного процесса, его работа может еще ухудшиться.

      • 4.2. Наиболее эффективное восстановления ТНВД и форсунок происходит на стенде , на котором обрабатывается ТНВД и форсунки. При этом ТНВД, приводимый в действие электродвигателем, прокачивает дизельное топливо, в 1л которого содержится 40-50 мл состава НАНОФУЛЛ.
      • 4.3. При отсутствии стенда, возможно восстановление или профилактику ТНВД и форсунок за счёт работы автомобиля без нагрузки. При этом дизельное топливо сжигается с добавлением композиции. Для легковых машин используется 200 мл композиции и 5-6л дизтоплива (смесь композиции и дизтоплива), а для грузовых 1л композиции и 20л дизтоплива. Для восстановления всей рабочей поверхности плунжера, двигатель должен работать с переменной скоростью вращения коленчатого вала, т.е. плунжер должен совершать угловые перемещения для подачи разного количества топлива. Скорость вращения коленвала должна составлять от 800 до 1200об/мин для большегрузных автомобилей и 800-2500 для легковых автомобилей (микроавтобусов, малых грузовиков). Обработку ТНВД легковых автомобилей можно производить и при движение автомобиля, но тогда количество смеси нужно вырабатывать в 1,5-2 раза больше.
      • 4.4. В большегрузных автомобилях смесь вырабатывается из отдельной емкости, куда подсоединяются трубопроводы прямой и обратной подач этого топлива. При этом во избежание выпадения минеральной составляющей композиции, производится периодическое перемешивание вырабатываемой смеси. Обязательное условие: вырабатываемая смесь должна подаваться в ТНВД через штатный топливный фильтр.
      • 4.5. В легковых автомобилях смесь вырабатывается из штатного бака. При заливке приготовленной смеси бак должен быть практически пустым. Кроме того, чтобы смесь не успевала выпадать минеральная составляющая в осадок, размешанную смесь необходимо добавлять порциями по 0,5-1л. Естественно, смесь попадает в ТНВД через штатный фильтр.
    Читать еще:  Горит epc троит двигатель

    ВНИМАНИЕ: При обработке форсунки увеличивается гидроплотность запорной иглы, что улучшает распыление топлива. Однако, если форсунки «льют», то необходимо заменить распылители.

    Урок №148. Агрегация

    Обновл. 19 Фев 2021 |

    На уроке о композиции мы говорили, что композиция объекта — это процесс создания сложных объектов из более простых. Мы также говорили о подтипе композиции объектов — композиции. В отношениях внутри композиции целое (класс) несет ответственность за существование частей (членов).

    На этом уроке мы рассмотрим второй подтип композиции объекта — агрегацию.

    1. Агрегация
    2. Реализация агрегации
    3. Выбирайте правильные отношения
    4. Композиция и агрегация
    5. Тест

    Агрегация

    Для реализации агрегации целое и его части должны соответствовать следующим отношениям:

    Часть (член) является частью целого (класса).

    Часть (член) может принадлежать более чем одному целому (классу) в моменте.

    Часть (член) существует, не управляемая целым (классом).

    Часть (член) не знает о существовании целого (класса).

    Как и в случае с подтипом композиция, отношения в агрегации также являются отношениями части-целого и однонаправленные. Однако, в отличие от композиции, части могут принадлежать более чем одному целому в моменте, и целое не управляет существованием и продолжительностью жизни частей. При создании/уничтожении агрегации, целое не несет ответственности за создание/уничтожение своих частей.

    Например, рассмотрим отношения между человеком и его домашним адресом. У каждого человека есть свой адрес. Однако этот адрес может принадлежать более чем одному человеку в моменте, например, вам и вашему соседу по комнате или родственникам, которые живут вместе с вами. К тому же этот адрес не управляется человеком — адрес существовал до того, как человек заселился и будет существовать после того, как человек выселится. Кроме того, человек знает, по какому адресу он живет, но адрес, в свою очередь, не знает, что это за человек и вообще, сколько их там находится. Такие отношения и являются агрегацией.

    В качестве альтернативы рассмотрим автомобиль и двигатель. Двигатель является частью автомобиля. И хотя двигатель принадлежит автомобилю, он может принадлежать и другим объектам, например, человеку, которому принадлежит автомобиль. Автомобиль не несет ответственности за создание или уничтожение двигателя. И в то же время автомобиль знает, что у него есть двигатель (ведь благодаря ему он двигается), но сам двигатель не знает, что он является частью автомобиля.

    Когда дело доходит до моделирования физических объектов, использование термина «уничтожение» может быть немного расплывчатым. Возникает вопрос: «Если бы метеорит упал с неба и раздавил машину, то можно ли считать, что и все части машины также были бы уничтожены?». Да, конечно. Но это вина метеорита, а не автомобиля. Важным моментом является то, что автомобиль не несет ответственности за уничтожение своих частей (но есть и внешняя сила, которая может этому поспособствовать).

    Мы можем сказать, что типом отношений в агрегации является «имеет» (отдел «имеет» работников, автомобиль «имеет» двигатель).

    Подобно композиции, части агрегации могут быть сингулярными или мультипликативными.

    Реализация агрегации

    Поскольку агрегация подобна композиции, так как обе состоят из отношений части-целого, то они реализуются почти одинаково, а разница между ними в основном семантическая. В композиции мы добавляем части к целому, используя обычные переменные-члены (или указатели, когда в классе происходит динамическое выделение/освобождение памяти).

    В агрегации мы также добавляем части к целому, используя переменные-члены. Однако этими переменными-членами обычно являются либо ссылки, либо указатели, которые указывают на объекты, созданные за пределами класса. Следовательно, агрегация принимает части, на которые она будет указывать, в качестве параметров конструктора или, если параметров нет, части добавляются позже через функции доступа или через перегруженные операторы.

    Поскольку эти части существуют вне области видимости класса, то при уничтожении класса, переменные-члены в виде ссылок или указателей также уничтожаются (но не удаляются значения, на которые они указывают). Следовательно, сами части продолжают существовать дальше.

    Рассмотрим пример Работника и Отдела детально. Чтобы было проще, в Отделе работает только один Работник и он не знает, Работником какого именно Отдела он является:

    Композиция для двигателя АКТИВ ПЛЮС 90мл

    Артикул: 122899

    Москва, Рябиновая ул.2 шт.
    Москва, Хабаровская ул.4 шт.
    Сабурово4 шт.
    Москва, Кетчерская ул.49 шт.

    Данные обновлены: 28.08.2021 в 19:33

    Москва, Рябиновая ул.2 шт.
    Москва, Хабаровская ул.4 шт.
    Сабурово4 шт.
    Москва, Кетчерская ул.49 шт.

    Данные обновлены: 28.08.2021 в 19:33

    • Параметры и характеристики
    • Наличие (59)
    • Описание
    • Категории товара

    Характеристики

    Код для заказа672156
    АртикулыСУПРОТЕК 122899/ 121144
    Ширина, м0.05
    Высота, м0.05
    Длина, м0.11
    Вес, кг0.109

    Параметры

    Бренд (ТМ)СУПРОТЕК
    ПроизводительСУПРОТЕК

    Территория отгрузки

    Другие склады и магазины партнера

    +7 (495) 660-51-64
    [email protected]
    Отгрузки только для юридических лиц по предварительному заказу
    Пн-Пт: с 9:00 до 18:00, Сб, Вс: выходной

    +7 (495) 664-23-36
    [email protected]
    Пн-Пт: с 9:00 до 20:00, Сб: с 9:00 до 18:00, Вс: с 9:00 до 16:00

    +7 (343) 384-56-25
    [email protected]
    ОПТ: Пн-Пт: с 9:00 до 18:00, Сб-Вс: выходной.
    Розница: Пн-Пт: с 8:30 до 17:30, Сб: с 10:00 до 16:00, Вс: выходной

    +7 (383) 322-70-45
    [email protected]
    Пн: с 8:30 до 18:00, Вт-Чт: с 9:00 до 18:00, Пт: с 9:00 до 17:30, Сб-Вс: выходной

    С этим товаром покупают

    На складах : 29 шт.

    На складах : 14 шт.

    На складах : 24 шт.

    На складах : 488 шт.

    На складах : 45 шт.

    На складах : 43 шт.

    На складах : 25 шт.

    На складах : 30 шт.

    На складах : 58 шт.

    В настройках личного кабинета Вы можете указать территорию отгрузки по умолчанию, чтобы быстро получать список актуальных остатков.

    Мы открыты к сотрудничеству, принимаем заказы на любой объем продукции.

    Полное или частичное использование любых материалов или их копирование разрешено только с письменного согласия администрации сайта.

    Ссылка на основную публикацию
    Adblock
    detector