Шаблон «декоратор»: суперсила классов-обёрток

Адаптивный фон, фиксированный контент

В своей книге о секретах CSS Лия Веру предложила интересную технику, которая может быть использована для секций с адаптивным фоном (фон, занимающий всю ширину окна просмотра), внутри которых есть контейнер. Давайте рассмотрим распространенный способ, позволяющий сделать это:

HTML

<section>
  <div class="wrapper"></div>
</section>

CSS

section {
  background-color: #ccc;
}

.wrapper {
  max-width: 1170px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 16px;
  padding-right: 16px;
}

Принцип работы margin-left: auto и margin-right: auto заключается в вычислении половины ширины окна просмотра и вычитании из неё ширины контента. То же самое можно сделать, используя padding.

CSS

section {
  padding: 1rem calc(50% - 585px);
}

Мы ещё не закончили. На мобильных устройствах контент будет соприкасаться с границами экрана. Решить это можно следующим способом:

CSS

section {
  padding: 1rem;
}

@media (min-width: 1170px) {
  section {
    padding: 1rem calc(50% - 585px);
  }
}

В качестве альтернативного решения можно использовать новую функцию CSS max(). Мы просто устанавливаем минимальный padding размером в 1rem, а вычисление 50% — 585px будет использовано в качестве другого значения.

CSS

section {
  padding: 1rem max(1rem, (50% - 585px));
}

Вспоминаем основные понятия

  • Есть программа. В императивном программировании программа представляет собой последовательность заданий, которые мы даём компьютеру. Делай одно, потом второе, потом третье. Есть ещё функциональное программирование, но это немного другое. 
  • Сами задания простые, но из простых заданий можно сделать более сложные. Если такое более сложное задание как-то назвать, можно сказать, что это функция — мини-программа внутри программы.
  • В функцию можно упаковать любые последовательности действий, которые вам часто нужны в программе: например сохранить файл особым образом, вывести что-то на особый экран или отправить электронное письмо на особый адрес. 
  • Внутри одних функций можно вызывать другие. Например, в таск-менеджере может быть функция «Закрыть задачу», внутри которой сначала сохраняется файл, потом отправляется письмо, потом всё выводится на особый экран. 
  • Проблема: когда много функций вызываются друг из друга, они переплетаются и создают много зависимостей. Если изменить работу одной из функций, могут посыпаться другие. 
  • Решение: стандартизировать подходы к работе функций. В частности, для этого придумали объектно-ориентированное программирование.
  • В объектно-ориентированном программировании главная не функция, а объект. Объект можно представить как коробку с данными и функциями.

Слишком длинная строка на больших экранах

Будет очень сложно читать текст абзаца на больших экранах, так как строка слишком длинная. Сайт «Элементы типографического стиля, используемые в сети» рекомендует, чтобы в строке было 45-75 символов. Чем дальше от этого диапазона, тем сложнее будет читать текст, представленный на веб-странице.

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

HTML

<section class="hero">
  <div class="hero__wrapper">
    <h2>How to make bread at home</h2>
    <p>...</p>
    <p><a href="/sign-up">Sign up</a></p>
  </div>
</section>

Я использовал класс hero__wrapper, так как этот контейнер может принадлежать только первой секции (Hero Section), поэтому его ширина может быть меньше ширины других контейнеров.

CSS

.hero__wrapper {
  max-width: 720px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 16px;
  padding-right: 16px;
}

Для центрирования содержимого вы можете применить любой метод, который хотите, в зависимости от варианта использования. В этом примере будет достаточно применить text-align: center, чтобы расположить контент в центре.

Модификаторы доступа private и public

Модификаторы доступа служат для определения полномочий доступа к членам класса извне. Если перед полем или методом стоит ключевое слово private, то обращаться к данному члену можно только внутри класса. Член с модификатором public доступен за пределами класса: то есть другие классы могут напрямую получить или модифицировать значение поля (категорически не рекомендуется поле делать public, для безопасного получения и установки значения нужно использовать геттеры и сеттеры), либо вызвать публичный метод.

С помощью модификаторов доступа реализуется ключевой принцип ООП – инкапсуляция данных (их сокрытие).

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

  • private в C#;
  • public в Java.

Не больше двух переменных экземпляра (instance variable) на класс

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

Примечание переводчика

Переменная экземпляра (instance variable, атрибут) — переменная, которая хранит свойство объекта — экземпляра класса. Этим она отличается от статической переменной (относится к классу, а не к его экземпляру) и от локальной переменной, которая объявляется в членах класса — например, в методах.

Кажется, это требование очень сложно выполнить. Уверен, вы видели классы с десятками параметров в конструкторе, так ведь?

Отлично! Почему бы не сгруппировать их в один объект? Или ещё раз хорошенько подумать о том, точно ли у этого класса идеальная архитектура и не делает ли он слишком много лишнего.

Какие бывают профили

Под «профилем» подразумевается более глубокое изучение определённых предметов. На них выделяют больше часов, а количество уроков по «непрофильным» предметам сокращают до минимума, необходимого для освоения программы.

В  федеральном государственном образовательном стандарте 2020 года указаны 4 основных профиля:

  • естественные и математические науки;
  • гуманитарные науки;
  • технологии;
  • социально-экономические науки.

Пятый профиль – общеобразовательный – предназначен для детей, которые не выбрали ни одио из узких направлений.

ФГОС предусматривает, что в программе каждого профиля обязательно должны быть русский язык и литература, математика, иностранные языки, общественные и естественные науки, а также физкультура и ОБЖ. Но в каком объёме и какие именно предметы включить в учебный план профильного класса – решает школа. На основе перечня ФГОС школа формирует более узкие профильные классы. Самые распространённые варианты:

Профиль Предметы
Физико-математический Физика, математика
Информационно-технологический Информатика, математика, физика
Химико-биологический Биология, химия
Лингвистический Русский язык, литература, иностранный язык
Филологический  Русский язык, литература
Гуманитарный Русский язык, литература, история, обществознание
Социально-экономический Обществознание, география

Бывают и другие профили: инженерные, культурологические, педагогические, юридические, художественно-эстетические и даже театральные.

В чем разница между классом оболочки и примитивным типом в Java?

Класс Wrapper предоставляет механизм для преобразования примитивного типа в объект и объекта в примитивный тип. Примитивный тип — это предопределенный тип данных, предоставляемый Java.
Связанный класс
Класс Wrapper используется для создания объекта; следовательно, он имеет соответствующий класс. Примитивный тип не является объектом, поэтому он не принадлежит классу.
Нулевые значения
Объекты класса оболочки допускают нулевые значения. Примитивный тип данных не допускает значений NULL.
Требуется память
Требуемая память больше, чем у примитивных типов. Кластерный индекс не требует дополнительного места. Требуемая память ниже по сравнению с классами-оболочками.
Коллекции
Класс Wrapper можно использовать с коллекцией, такой как ArrayList и т. Д. Примитивный тип не используется с коллекциями.

Центрирование контейнера

Чтобы разместить контейнер в центре, вы должны присвоить свойству margin значение auto с левой и правой стороны. Смотрите пример, приведенный ниже:

CSS

.wrapper {
  max-width: 1170px;
  margin: 0 auto;
}

Согласно спецификации CSS, auto margin работает следующим образом:

Если свойствам margin-left и margin-right присвоено значение auto, то размер отступа с обеих сторон будет одинаковым. Это горизонтально центрирует объект, относительно краёв содержащего блока.

Я использовал параметр «margin: 0 auto», который сбрасывает значение margin сверху и снизу до нуля, а справа и слева устанавливает значение auto. Пользуясь этим способом, можно ожидать некоторых последствий, о которых я расскажу в этой статье чуть позже.

Пока что рекомендую установить значения margin вручную.

CSS

.wrapper {
  max-width: 1170px;
  margin-left: auto;
  margin-right: auto;
}

Автобокс и распаковка

В предыдущем разделе мы показали, как вручную преобразовать примитивное значение в объект.

После Java 5 это преобразование может быть выполнено автоматически с помощью функций, называемых автобоксом и распаковкой.

“Бокс” относится к преобразованию примитивного значения в соответствующий объект-оболочку. Поскольку это может произойти автоматически, это называется автобоксом.

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

На практике это означает, что мы можем передать примитивное значение методу, который ожидает объект-оболочку , или назначить примитив переменной, которая ожидает объект:

List list = new ArrayList<>();
list.add(1); // autoboxing

Integer val = 2; // autoboxing

В этом примере Java автоматически преобразует значение примитива int в оболочку.

Внутренне он использует метод valueOf() для облегчения преобразования. Например, следующие строки эквивалентны:

Integer value = 3;

Integer value = Integer.valueOf(3);

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

Подобно автобоксу, распаковка выполняется автоматически при передаче объекта методу, ожидающему примитив, или при назначении его переменной примитива:

Integer object = new Integer(1); 
int val1 = getSquareValue(object); //unboxing
int val2 = object; //unboxing

public static int getSquareValue(int i) {
    return i*i;
}

В принципе, если мы напишем метод, который принимает примитивное значение или объект-оболочку, мы все равно сможем передать им оба значения. Java позаботится о передаче правильного типа, например, примитива или оболочки, в зависимости от контекста.

Постановка задачи

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

В нашем маленьком мирке будут два типа героев: зелёные и красные. Каждый из них может обладать одной или несколькими сверхспособностями: суперсила, суперловкость и суперинтеллект.

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

  • суперсила — на 4;
  • суперловкость — на 3;
  • суперинтеллект — на 7.

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

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

Класс для зелёного супергероя:

И для красного, более живучего:

Используем переменные CSS для вариаций контейнеров

Редко случается так, что вам нужен контейнер только одного размера. Ширина контейнера может быть большой или маленькой, в зависимости от содержимого и варианта использования. Применяя переменные CSS, мы можем по-новому взглянуть на wrapper и сделать его максимально пластичным

Обратите внимание на следующее:

HTML

<div class="wrapper"></div>

CSS

.wrapper {
  max-width: var(--wrapper-width, 1170px);
  margin-left: auto;
  margin-right: auto;
  padding-left: 16px;
  padding-right: 16px;
}

Возможно, вы заметили, что у функции var есть два значения: первое – —wrapper-width, и второе – 1170px. Вторая переменная является резервной, то есть используется, если значение переменной —wrapper-width не установлено.

Что это значит? Это значит, что вы можете создать вариацию контейнера, установив свойство —wrapper-width, как показано ниже.

HTML

<div class="wrapper" style="--wrapper-width: 720px"></div>

Таким образом, я создал вариацию контейнера:

  • Без добавления новых классов;
  • Не копируя и не вставляя стили;
  • Более надежную и легко редактируемую с помощью DevTools.

Если вам не нравится использовать встроенные стили для изменения переменной CSS, вы можете вместо этого добавить новый класс. Смотрите пример, приведенный ниже:

HTML

<div class="wrapper wrapper--small"></div>

CSS

.wrapper--small {
  --wrapper-width: 720px;
  /* это изменит ширину контейнера, установленную по умолчанию */
}

Логический и символьный типы данных

Чтобы работать с логическими значениями, используют тип данных boolean — это его единственное применение. У такой переменной может быть только два значения: false (ложь) и true (истина).

В Java boolean — отдельная переменная. Это не аналог 1 или , как, например, в JavaScript и PHP.

Тип данных char используют, чтобы хранить в переменных любые 16-разрядные символы Unicode. Но их нужно записывать строго в одинарные кавычки ‘ ‘, и только по одному.

Не стоит путать символьные и строковые переменные — ‘ж’ не равно «ж», потому что в двойных кавычках хранится тип данных String. А это уже не примитив.

Оборачивайте примитивные типы

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

А ещё такой код легче воспринимать, ведь по сигнатуре объекта-обёртки сразу ясно, что передавать методу в качестве параметров.

Примечание переводчика

В оригинальной книге правило звучит так: «оборачивайте примитивы и строки».

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

Как используют целочисленные переменные

Целочисленные типы данных различаются только диапазонами значений. Их основная задача — хранить информацию для вычислений.

Тип byte. Эти переменные используют, чтобы работать с потоком данных, который получили из файла или по сети.

Тип short. По сравнению с byte у него увеличенный, но всё же ограниченный диапазон значений. Применяют short редко — например, когда нужно экономить память.

Тип int. В языке Java int — самый популярный тип целочисленных данных. При вычислениях в виртуальной машине остальные целочисленные типы (byte, short) занимают столько же памяти, сколько int.

Множество классов в Java обладают значениями типа int — например, длина массива внутри класса String выражается целочисленным значением int:

Если переменная хранит количество элементов в коллекциях List, Set и Map, она тоже относится к типу int:

Тип возвращаемого значения подсказывает, сколько элементов можно хранить в списке или множестве. Максимум для int — 2 147 483 647.

Тип long применяют, когда нужно работать с большими целочисленными значениями.

Создадим много классов-индивидуальностей

Можем поступить как в Marvel и каждому возможному варианту героя дать своё имя — создать отдельный класс. Например, зелёный супергерой с суперсилой и суперинтеллектом будет Халком, а красного — с суперинтеллектом и суперловкостью — назовём Человеком-пауком.

Всего получится 16 классов: восемь комбинаций из трёх суперспособностей для красных и восемь — для зелёных:

Суперсила Суперловкость Суперинтеллект
1
2 +
3 +
4 +
5 + +
6 + +
7 + +
8 + + +

Например, так будет выглядеть класс Халка:

Что здесь плохо

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

Если же мы захотим добавить не суперспособность, а тип — например, жёлтых супергероев, — то классов станет больше на 2n, где n — варианты суперспособностей.

Как это посчитать

Для каждого типа героя (красного или зелёного) суперсила либо есть, либо нет — ровно два варианта.

Независимо от этого, у каждого такого варианта суперловкость либо есть, либо нет. Итого: для каждого из 2 вариантов ещё по 2 варианта = 4 варианта.

У каждого из этих 4 вариантов суперинтеллект либо есть, либо нет:

4 ∗ 2 = 8 вариантов.

Таким образом, каждая суперспособность увеличивает число вариантов супергероев каждого цвета вдвое, то есть при n суперспособностей их число равно 2n.

Классы обертки

“Какова цель класса обертки?”. Это один из самых распространенных вопросов для интервью на Java .

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

Например, фреймворк коллекции Java работает исключительно с объектами. Давным-давно (до Java 5, почти 15 лет назад) не было автобоксов, и мы, например, не могли просто вызвать add(5) для набора целых чисел.

В то время эти примитивные значения должны были быть вручную преобразованы в соответствующие классы-оболочки и сохранены в коллекциях.

Сегодня, с помощью autoboxing, мы можем легко сделать ArrayList.add(101) но внутренне Java преобразует примитивное значение в Целое число перед сохранением его в ArrayList с помощью метода valueOf () .

Преобразование примитива в класс-оболочку

Теперь большой вопрос: как мы преобразуем примитивное значение в соответствующий класс-оболочку, например, int в Целое число или char в Символ?

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

Однако начиная с Java 9 конструкторы для многих коробочных примитивов, таких как | или Long

Поэтому настоятельно рекомендуется использовать только заводские методы в новом коде .

Давайте рассмотрим пример преобразования значения int в объект Integer в Java:

Integer object = new Integer(1);

Integer anotherObject = Integer.valueOf(1);

Метод valueOf() возвращает экземпляр, представляющий указанное значение int .

Он возвращает кэшированные значения, что делает его эффективным. Он всегда кэширует значения от -128 до 127, но также может кэшировать другие значения за пределами этого диапазона.

Аналогично, мы также можем преобразовать boolean в Boolean, byte в Byte, char в Символ, long в Long, float в Float, и double to Double. Хотя, если нам нужно преобразовать строку в целое число , нам нужно использовать метод parseInt () , потому что String не является классом-оболочкой.

С другой стороны, для преобразования объекта-оболочки в примитивное значение мы можем использовать соответствующий метод, такой как intValue(), doubleValue () |/и т. Д:

int val = object.intValue();

Исчерпывающую справку можно найти здесь .

Где применять классы и ООП, а где — функции

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

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

Текст

Миша Полянин

Редактировал и рисовал

Максим Ильяхов

Корректор

Ира Михеева

Иллюстратор

Даня Берковский

Вёрстка

Маша Дронова

Доставка

Олег Вешкурцев

Boxing и unboxing — как превратить примитив в объект

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

Поэтому у каждого примитива есть соответствующий ему ссылочный тип — его называют классом-обёрткой. В таких классах хранятся методы для преобразования типов данных, а также другие константы и методы, которые применяются при работе с примитивами.

Тип данных Класс-обёртка
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean

Ссылочные типы данных (обёртки) пишут с прописной буквы, потому что это полноценные классы. А в Java названия всех классов должны начинаться с большой буквы — язык чувствителен к регистру.

Чтобы создать ссылку на примитивный тип данных, нужно использовать соответствующую обёртку:

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

Классы-обёртки полезны, когда нужно одновременно работать и с числами, и с объектами — например, в коллекциях.

В этой статье мы рассмотрели примитивные типы данных (byte, short, int, long, float, double, char и boolean), ссылочные типы данных (String и остальные). Вы узнали, чем они отличаются друг от друга и какие значения принимают по умолчанию.

В следующей статье мы расскажем, что можно делать с этими переменными с помощью арифметических и логических операторов языка Java.

Ключевое отличие — оболочка Класс против примитивного типа в Java

Java — популярный язык программирования, который используется для разработки различных приложений. Одним из преимуществ Java является то, что она поддерживает объектно-ориентированное программирование (ООП). Используя ООП, программу или программное обеспечение можно моделировать с помощью объектов. Класс используется как образец для создания объекта. В программировании необходимо хранить данные. Зарезервированные области памяти для хранения данных известны как переменные. Каждая переменная имеет определенный тип данных. В языке Java предусмотрено восемь примитивных типов. Они короткие, байтовые, int, float, double, char, логическое значение. Иногда требуется преобразовать примитивный тип в объект, а объект — обратно в примитивный тип. Для этого преобразования используются классы-оболочки. В этой статье обсуждается разница между классом-оболочкой и примитивным типом в Java. В ключевое отличие между классом-оболочкой и примитивным типом в Java заключается в том, что Класс-оболочка используется для преобразования примитивного типа в объект и объекта обратно в примитивный тип, в то время как примитивный тип — это предопределенный тип данных, предоставляемый языком программирования Java.

1. Обзор и основные отличия 2. Что такое класс-оболочка в Java 3. Что такое примитивный тип в Java 4. Сходства между классом-оболочкой и примитивным типом в Java 5. Параллельное сравнение — класс оболочки и примитивный тип в Java в табличной форме 6. Резюме

Что такое класс Wrapper в Java?

Класс Wrapper в Java используется для преобразования примитивного типа данных в объект и объекта в примитивный тип. Даже примитивные типы данных используются для хранения первичных типов данных, структур данных, таких как списки массивов и объекты хранилища векторов. Следовательно, для преобразования необходимо использовать классы-оболочки. Соответствующие классы-оболочки для примитивных типов char, byte, short и int — это Character, Byte, Short и Integer. Соответствующие классы-оболочки для long, float, double и boolean — Long, Float, Double и Boolean.

Согласно приведенной выше программе intobj является объектом класса-оболочки Integer. Floatobj — это объект класса-оболочки Float. Doubleobj — это объект класса двойной оболочки. Объект Integer преобразуется в примитивный тип int с помощью intValue (). Точно так же объект Float преобразуется в примитивный float с помощью floatValue (). Объект Double преобразуется в примитивный тип double с помощью doubleValue (). Если программист записывает оператор как int i = intobj; компилятор внутренне записывает в bj.Value (). Процесс автоматического преобразования объекта класса-оболочки в соответствующий ему примитивный тип известен как распаковка. Коллекции, такие как ArrayLists, используют класс Wrapper, потому что они хранят объекты.

Что такое класс?

В объектно-ориентированном программировании (ООП) – класс это основной элемент, в рамках которого осуществляется конструирование программ. Класс содержит в себе данные и код, который управляет этими данными.

Класс зачастую описывает объект реального мира. Как и реальный объект, класс содержит свой набор параметров и характеристик. Каждый такой параметр называется поле класса (очень похоже на обычные переменные). Также класс способен манипулировать своими характеристиками (полями) с помощью методов класса (похожи на функции в процедурных языках). Рассмотрим такой объект, как автомобиль.

Оговоримся, что данная статья исключительно для начинающих. В ней не рассматривается наследование, абстрактные классы и т.д.

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: