Наследование в бизнес-объектах: доступ и отображение атрибутов подкласса при запросе типа базового класса из уровня доступа к данным
(Пожалуйста, имейте в виду, что я относительно неопытный программист. Я знаю, что этот вопрос можно рассматривать как слишком открытый, потому что в ООП так много философий о наследовании. Этот вопрос больше направлен на мой мыслительный процесс, т.е. подхожу ли я к этому сценарию так, что опытный программист может показаться правильным? Что в моих идеях очевидно точных или неточных?)
Я разрабатываю систему инвентаризации, которая отслеживает информацию об ИТ-оборудовании, включая компьютеры, принтеры, коммутаторы, маршрутизаторы, мобильные телефоны, жесткие диски и другие устройства. У меня есть разработанная база данных, и я сейчас нахожусь в процессе планирования клиентского приложения. Я намерен, чтобы приложение использовало уровень доступа к данным, уровень бизнес-логики и бизнес-объекты. Я все еще на стадии концептуального планирования, и я понимаю, что на данном этапе мне не следует рассматривать детали реализации, но мой разум стремительно движется вперед. Функция поиска должна работать следующим образом: пользователь вводит критерии поиска и выполняет поиск. Список соответствующих устройств (или единственное соответствующее устройство) возвращается. Список устройств отображается в виде списка определенного типа, а детальное представление отображается для устройства, когда оно выбрано.
Мне было интересно, принесет ли использование наследования в моих возможных бизнес-объектах пользу моему приложению, или если это добавит ненужную сложность... или это просто неправильно. Моя первоначальная мысль - это установка, показанная на рисунке:
(Это не фактический дизайн, а просто упрощенная концепция для этого поста). В дополнение к каждому устройству, имеющему специфические для типа атрибуты, любое устройство в любой момент времени может находиться в одном из двух состояний, активном или заархивированном. Я вообще не знаю, как это смоделировать.
Я начал думать о том, как могут работать запросы при использовании этой настройки. Кажется достаточно простым запросить любой конкретный подкласс устройства из уровня доступа к данным, такой как
псевдокод:
Computer comp = getComputerBySerialNumber(sn);
List<Router> routers = getRouters();
// I can then write code to display a list of basic device information and
// additionally display all details of a computer or router when requested.
// Obviously display would be handled in a different layer.
Проблема, которая привела меня к написанию этого вопроса, заключается в том, как обрабатывать запросы, такие как "получить все устройства из определенного места".
// Returns a list of devices regardless of device type
// as long as they have the same location
List<Device> devsFromLocation = getDevicesByLocation(loc);
// List contains computers, routers, printers, etc.
Как бы я отобразил основные сведения об устройстве, а затем конкретные сведения об устройстве, если у меня есть ссылка на объект базового класса? (Попытка избежать сумасшедшего кастинга или использования отражения). Каждое из устройств из этого местоположения будет не иметь определенных атрибутов своих подтипов. Если бы я хотел отобразить все данные о конкретном устройстве, мне пришлось бы снова запросить базу данных, чтобы получить оставшиеся поля. Является ли необходимость выполнения другого запроса признаком плохого дизайна? Кроме того, как я могу определить правильный тип устройства? Возможно, большой оператор switch / case тестирует каждый Device.Type
атрибут, выполнить правильный запрос, вернуть полный подтип и отобразить детали для пользователя? Или... Лучше ли возвращать отдельные списки, содержащие объекты полных подтипов, а затем перебирать все списки для отображения общих атрибутов в представлении списка, а затем легко отображать детали подтипа в представлении сведений?
Это полезный случай наследования или я его неправильно использую? В настоящее время я страдаю от проблемы слишком большого количества информации. Я прочитал все возможное об ООД, и у меня в голове так много правил и указаний, что я никогда не знаю, правильно ли я что-то делаю. Я чувствую, что мой мозг пытается применить информацию, которую я поглощал, поэтому я представляю реализацию, которая является неправильной. Я продолжаю думать обо всем этом бизнесе о программировании абстракций для обеспечения гибкости кода, но в какой-то момент вам нужно иметь дело с конкретными классами, верно? С моей точки зрения, наследование связано с поведением, а не с атрибутами. Поскольку я на самом деле не моделирую какое-либо поведение (или я просто не вижу его?), А просто собираю данные об устройствах, мне трудно интерпретировать их отношения. Поскольку эти классы по сути являются глупыми наборами атрибутов, я чувствую, что все они должны быть отдельными классами. Опять же, у меня будут повторяющиеся поля во всех классах, но действительно ли это имеет значение в этом случае?
Я знаю, что есть тонны книг по ООД, наследованию, композиции и т. Д. Я читал некоторые из этих книг; В настоящее время я читаю еще немного, и я провел дни, исследуя онлайн. Каждый удобно использует очевидные примеры наследования. Мне снятся кошмары о фруктах, животных и формах.
Спасибо, что нашли время, чтобы прочитать мой вопрос, и спасибо за любую информацию или понимание, которое вы можете предоставить. Пожалуйста, не стесняйтесь предлагать любые другие советы, идеи, торговые секреты, карты для захороненных сокровищ, достойную море лодку и секстант, или что-нибудь еще, что, по вашему мнению, может помочь
1 ответ
Самый простой способ - добавить информационный метод в базовый класс, который возвращает информацию, и каждый производный тип переопределяет этот метод правильной информацией.
Это позволит вам сделать:
foreach (Base b in list)
Write(b.Information());
Если ваш вывод должен быть более динамичным, рассмотрите информационный объект устройства.
Просматривая только ваш пост (поэтому я мог пропустить некоторые детали, которые делают это плохой идеей), я бы также предложил вам сделать Active State
член Device
базовый класс, так как Device
'Имеет-A (N)' Active State
(а также Archive State
если то же самое верно).
Кроме этого, ваш дизайн приятен и прост и имеет смысл.
РЕДАКТИРОВАТЬ:
Таким образом, вы могли бы иметь Report
объект, на котором вы хотите, чтобы информация была записана, чтобы вы имели:
class Device{
write_information_to_report(Report report);
}
Это может быть переопределено производными классами, чтобы добавить производную конкретную информацию.
Вы могли бы абстрагировать Report
что-то вроде InformationOutputter
если ты действительно хотел.
Хороший пример такого рода вещей, глядя на рисование фигур:
class Graphics{
line(int, int, int, int) = 0;
curve(float, float, float, float) = 0;
class OpenGLDrawer : Graphics {
line(int, int, int, int) { // Use open gl to draw a line };
curve(int, int, int, int) { // Use open gl to draw a line };
}
class DirextXDrawer : Graphics {
line(int, int, int, int) { // Use directX to draw a line };
curve(int, int, int, int) { // Use directX to draw a line };
}
class Shape{
draw(Graphics g) = 0;
}
class Triangle : Shape{
draw(Graphics g) { g.line(... /* draw a triangle using line */ };
}
class Circle : Shape{
draw(Graphics g) { g.arc(... /* draw a circle using arc */};
}
Здесь вы можете видеть, что каждый объект может отвечать за свою собственную функцию, общие функции могут быть общими на уровне базового класса, и любой графический объект может рисовать любую форму.