Получить Работу (Серия Из 6 Частей)
Поэтому на прошлой неделе я сделал кое-что ужасающее: я дал техническое интервью на камеру. 🙈 Люсинэ с планеты-кандидата задала мне вопрос об объектно-ориентированном дизайне, и мы нашли решение. Посмотрите видео здесь! ✨ В этом посте будет рассмотрен тот же вопрос, что и в видео, но более подробно, а также будет включено кодовое решение на Java.
Так почему же я согласился сниматься, делая то, о чем мне снятся кошмары? Ну, я подумал о том, каковы были мои цели в этой серии блогов. Я начал это после быстрого, интенсивного поиска работы, где мне пришлось быстро учиться на своих ошибках. Я много работал, но я также должен признать, что у меня есть огромные привилегии. Я вырос в белой семье из высшего среднего класса, отец которой был инженером-электриком. Я начал писать код, когда мне было 9 лет и я поступил в 10 лучших университетов по информатике. Колода была сложена в мою пользу. Но не должно быть так сложно попасть в технологическую индустрию. Существует так много искусственных барьеров для входа, которые исключают кого-либо из среды, не совсем похожей на мою. И это чушь собачья. Это чушь про альфа-самцов. И я устал от этого. Поэтому мне нужно сделать свой контент максимально доступным – отсюда и видео. Я готов попробовать другие форматы, если люди тоже захотят их увидеть. Это означает, что на горизонте может появиться больше видео – дайте мне знать, что вы хотели бы видеть в комментариях 👀
Теперь давайте углубимся в тему: вопросы объектно-ориентированного проектирования!
Вопрос объектно-ориентированного проектирования (ООД) сосредоточен вокруг написания программы для моделирования реальной системы. Например, один ХОРОШИЙ вопрос, который мне задали, касался дизайна ресторана. Решение будет включать в себя определение важных классов и методов управления рестораном. Примерами функций, которые следует включить, могут быть способы управления меню, кухонным инвентарем, расстановкой мест и бронированием. Вы также хотели бы смоделировать действующих лиц в системе, что в данном случае будет означать персонал ресторана и гостей.
Одна сложная вещь, на которую следует обратить внимание, заключается в том, что ХОРОШИЕ вопросы для интервью часто звучат аналогично вопросам проектирования системы. Разница заключается в области применения – с вопросом о проектировании системы вас просят разработать систему от начала до конца, что означает внешний интерфейс, серверную часть и инфраструктуру. С ХОРОШИМ вопросом вас просят увеличить один фрагмент. Если вы не уверены, вы всегда можете попросить своего интервьюера уточнить.
Прежде чем вы отправитесь на СТАРОЕ собеседование, у вас должен быть опыт проектирования и реализации классов, а также практические знания четырех принципов объектно-ориентированного проектирования. Чтобы дать вам освежить память, они:
Инкапсуляция
Инкапсуляция означает ограничение доступа к данным с помощью общедоступных и частных классов и методов. Это часто выглядит как использование геттеров и сеттеров для доступа к частным переменным внутри общедоступного класса:
public class Chair {
private int numLegs;
public int getNumLegs() {
return numLegs;
}
public void setNumLegs(int newNumLegs);
numLegs = newNumLegs;
}
Абстракция
Абстракция означает наличие информации, привязанной к модели чего-либо, а не к его экземпляру. На практике это может выглядеть как интерфейс класса, реализуемый подклассами:
public interface Furniture {
public void useFurniture();
}
public class Chair implements Furniture {
private boolean occupied;
public void useFurniture() {
sit();
}
private void sit() {
occupied = true;
}
}
Полиморфизм
Полиморфизм означает, что объект может принимать множество форм. Предметом мебели может быть стул, стол или кровать. Любой код, написанный для родителя, также будет работать для детей.
public class Furniture {
private boolean isInUse;
public void useFurniture() {
isInUse = true;
}
}
public class Chair extends Furniture {
public void sit() {
useFurniture();
}
}
public class Bed extends Furniture {
public void sleep() {
useFurniture();
}
}
Наследование
Наследование означает, что объект имеет отношение “есть” с другим объектом. Например, кресло “есть” стул. Это может выглядеть как подкласс, повторно использующий код из своего родительского класса:
public class Chair {
private int numLegs;
public Chair() {
numLegs = 4;
}
}
public class ArmChair extends Chair {
private int numArms;
public ArmChair() {
super(); //this calls Chair's constructor and sets numLegs to 4
numArms = 2;
}
}
Более старшие кандидаты также должны быть знакомы с общими шаблонами проектирования. К ним относятся:
Шаблоны конструкторов
Некоторые распространенные шаблоны конструкторов – это фабрики, строители и синглеты. Конструкторы могут быть полезны в интервью, потому что они делают конструкторы с длинными списками аргументов более удобочитаемыми.
Структурные Закономерности
Структурные закономерности определяют состав классов. Две основные структурные модели – это фасады и обертки. Лично я не видел, чтобы интервьюеры слишком глубоко копались в этой области. ХОРОШИЕ вопросы обычно имеют простое решение, поэтому структуры классов, как правило, довольно просты.
Поведенческие Паттерны
Поведенческие паттерны определяют, как классы общаются. Важной концепцией здесь является цепочка ответственности – запросы должны обрабатываться путем прохождения последовательной цепочки обработчиков, чтобы вы гарантированно всегда проходили через все обработчики и обрабатывали запрос в одном и том же порядке. Еще один поведенческий паттерн, который следует знать, – это паттерн наблюдателя, когда объект прислушивается к изменениям, исходящим от другого объекта.
Дополнительные ресурсы об этих шаблонах приведены ниже 👇
Мы собираемся проработать вопрос, который одна крупная технологическая компания задала мне в телефонном интервью. Вопрос в том, “Разработайте программу для решения головоломки”.
В своем интервью с Люсьеном я нарисовал решение на доске. В этом посте есть кодовое решение, но вы можете заметить, что это не функциональный код. Это потому, что многое из этого написано с сокращенным синтаксисом, что является вольностью, которую вы можете позволить себе в этой форме интервью. Никто не собирается компилировать ваш код, так что не стесняйтесь сокращать.
Уточняющие Вопросы
Первое, что вы всегда должны делать, – это задавать вопросы, чтобы прояснить проблему. Как выглядит кусочек головоломки? В этом случае все детали будут иметь четыре стороны, которые могут иметь либо углубление, выдавливание, либо плоский край:
Еще несколько вещей, которые следует уточнить: как выглядит доска? Мы скажем, что наша доска представляет собой прямоугольник. Откуда мы знаем, что две части подходят друг другу? Кривизна углубления на одной детали будет соответствовать кривизне выдавливания на другой. И, наконец, может ли одна деталь сочетаться с несколькими частями? Нет, совпадения будут уникальными – одна деталь будет сочетаться только с одной другой деталью.
Проектирование части головоломки с голыми костями
Затем начните думать о том, как организовать свои занятия. Многие вопросы по дизайну настольных игр следуют аналогичной схеме: есть игровые фигуры, доска и игрок или решатель. Таким образом, имея это в виду, эту проблему можно разбить на три класса: части головоломки, доска и решатель.
Мы могли бы либо сначала спроектировать самый маленький компонент и продвигаться дальше, либо сначала спроектировать общую картину, а затем заполнить ее деталями. Я решил начать с кусочка головоломки и наращивать, потому что правильное понимание абстракции кусочка головоломки имеет решающее значение для решения головоломки.
Для начала мы знаем, что у каждого кусочка головоломки есть 4 стороны. Это заставляет меня думать, что Сторона должна быть подклассом части, а часть должна содержать 4 боковых объекта:
public class Piece {
private Side side1, side2, side3, side4;
public class Side {
}
}
Одно из решений, которое необходимо принять здесь, заключается в том, следует ли поместить Стороны в структуру данных или оставить в виде четырех отдельных переменных. Я решил оставить их в качестве отдельных переменных, потому что мы мало что выиграем от их включения в структуру данных; это не сделает код быстрее или более читабельным.
Сторона
Каждая сторона имеет два свойства: 1) она может выступать, входить или быть плоской и 2) кривизна углубления/выдавливания. Мы скажем, что стороны двух частей подходят друг к другу, когда одна находится ВНУТРИ , другая – СНАРУЖИ , и обе они имеют одинаковую кривизну. Не вдаваясь пока в подробности, мы можем начать заполнять внутреннюю:
public class Side {
private enum Edge {IN, OUT, FLAT}
private Edge edge;
private Curvature curve;
}
Возможно, вы думаете, что это Кривизна ? В условиях собеседования вам нужно установить границы того, насколько конкретным будет ваш дизайн. Не увязайте в попытках определить каждый последний компонент; более важно сначала получить общую картину. По этой причине я бы ушел Кривизна на данный момент не определена на доске, но я бы сказал своему интервьюеру, как я себе это представлял, т. Е. Она содержит некоторое свойство, которое я могу использовать, чтобы сопоставить две части, например, угол дуги выдавливания.
Правление
Теперь у нас есть класс функциональных кусочков головоломки, так что давайте уменьшим масштаб и начнем думать о том, как мы собираемся их всех разместить. Нам нужен способ отслеживать два компонента состояния игры: сыгранные фигуры и неиспользованные.
Поскольку мы знаем, что доска представляет собой прямоугольник, мы можем представить доску в виде 2D-массива. Что касается неиспользуемых фрагментов, у нас есть несколько вариантов их представления – мы могли бы поместить их в список, очередь или график, чтобы назвать несколько. Допустим, мы будем перебирать кусочки один за другим, чтобы решить головоломку. В этом случае мы можем использовать очередь, чтобы быстро захватить следующий кусок или вернуть его в конец, если мы не смогли найти для него совпадение.
Доска выглядит так:
public class PuzzleBoard {
private Piece[][] board; get;
private Queue unusedPieces; get;
public void placePiece(Piece p, int row, int column) {
board[row][column] = p;
}
public Piece getNextPiece() {
return unusedPieces.pop();
}
public void returnPiece(Piece p) {
unusedPieces.push(p);
}
}
Решатель
Класс решателя должен будет принять нерешенную доску и вернуть решенную доску:
public class Solver {
public PuzzleBoard solve(PuzzleBoard puzzle) {
//solve puzzle
}
}
Давайте подумаем о том, как решить эту головоломку. Нам не нужно изобретать велосипед; мы можем использовать стандартную эвристику, состоящую в том, чтобы сначала найти угловые части, затем края, а затем заполнить средние части.
Прежде чем мы перейдем к этому, нам нужно будет добавить метод сопоставления, а также некоторые вспомогательные методы в классы частей и сторон, чтобы мы могли легко идентифицировать края и углы:
public class Piece {
private Side side1, side2, side3, side4; get;
public boolean matches(Piece other) {
if ((side1.curve == other.side3.curve)
&& ((side1.edge == Edge.IN && side3.edge == Edge.OUT)
|| (side1.edge == Edge.OUT && side3.edge == Edge.IN) ... ) //etc- check all opposite sides
}
public boolean isCornerPiece() {
if ((side1.isEdge() && side2.isEdge()) || side2.isEdge()
&& side3.isEdge() || ...) //etc - check all adjacent sides {
return true;
}
return false;
}
public boolean isEdgePiece() {
if (isCornerPiece()) {
return false;
}
if (side1.isEdge() || side2.isEdge() || .. //etc - check all sides) {
return true;
}
public class Side {
private enum Edge {IN, OUT, FLAT}
private Edge edge;
private Curvature curve;
public boolean isEdge() {
return edge == Edge.FLAT;
}
}
}
Теперь мы можем закончить Решатель:
public class Solver {
public PuzzleBoard solve(PuzzleBoard puzzle) {
while (puzzle.getUnusedPieces().getNextPiece()) {
//find corner pieces
//find edge pieces
//finish the puzzle
}
}
}
Я предпочитаю оставить алгоритм в виде расплывчатых инструкций в качестве метода управления временем. В моем собственном интервью на данный момент у меня почти не было времени, и, учитывая, что основное внимание в этом интервью уделяется не оценке моих навыков разработки алгоритмов, не важно полностью конкретизировать алгоритм.
Попались
Это тот момент в интервью, когда интервьюер начинает задавать вопросы, чтобы попытаться проверить, насколько хорош ваш дизайн. Мой интервьюер добавил дополнительное требование, чтобы мы могли вращать фигуры.
Чтобы справиться с этим, нам нужно будет внести несколько изменений. Во-первых, нам нужно было бы добавить метод rotate() в класс Piece:
public class Piece {
private Side side1, side2, side3, side4;
public void rotate() {
Side extraSide = side1;
side1 = side2;
side2 = side3;
side3 = side4;
side4 = extraSide;
}
public boolean isCornerPiece() {
if ((side1.isEdge() && side2.isEdge() || (side2.isEdge() && side3.isEdge() || ... ) //etc - check all adjacent sides) {
return true;
}
return false;
}
public boolean isEdgePiece() {
if (isCornerPiece()) {
return false;
}
if (side1.isEdge() || side2.isEdge() || .. //etc - check all sides) {
return true;
}
public class Side {
private enum Edge {IN, OUT, FLAT}
private Edge edge;
private Curvature curve;
public boolean isEdge() {
return edge == Edge.FLAT;
}
}
}
В решателе нам нужно было бы добавить логику, чтобы попытаться повернуть деталь, если она изначально не подходит. Возможность поворачивать фигуры также вносит некоторую неопределенность в решатель – мы больше не уверены, что, когда мы кладем угловую фигуру, мы ставим ее в нужное место. Поэтому нам также нужно было бы добавить в наш алгоритм обратный отсчет, чтобы учесть это.
Ресурсы
Вот несколько ресурсов, которые помогли мне понять принципы ООД:
- Шаблоны проектирования от Гуру рефакторинга
- Шаблоны проектирования программного обеспечения в Википедии
- Шаблоны проектирования: Элементы многоразового объектно-ориентированного программного обеспечения от Эриха Гаммы
- 4 Основных принципа объектно-ориентированного программирования Раймонда Леваллена
- Как объяснить концепции объектно-ориентированного программирования 6-летнему ребенку, Александр Петков
- СОЛИДНО в Википедии
Заключительные мысли
Объектно-ориентированный дизайн – это широкая тема. Сначала вам нужно освоить основы, такие как концепции абстракции, инкапсуляции, наследования и полиморфизма, прежде чем переходить к более сложным темам, таким как шаблоны проектирования и принципы SOLID. Самое главное, вам нужно практиковаться, чтобы учиться. Поэтому я оставлю вам несколько вопросов, чтобы вы могли разработать свои собственные решения для:
- Разработайте систему управления запасами книжного магазина.
- Спроектируйте парковку.
- Создайте игру в монополию.
И, пожалуйста, дайте мне знать, понравилось ли вам видео!
Получить Работу (Серия Из 6 Частей)
Оригинал: “https://dev.to/techdebtor/get-hired-handling-object-oriented-design-questions-4i70”