Помогите мне соединить наследование и реляционные понятия
Я говорил с моим приятелем-программистом о наследовании и его использовании при проектировании моделей. Он большой сторонник, а я немного прохладнее. Главным образом потому, что я склонен проектировать системы снизу вверх: База данных -> Приложение -> Презентация (честно говоря, я не очень интересный человек, поэтому часто оставляю презентацию целиком кому-то другому). Я считаю, что системы реляционных баз данных не поддерживают наследование без большого количества взаимно однозначных связей с другими таблицами.
Если я проектирую с концептуальной точки зрения, Администратор - это Пользователь, это Персона. Начиная с базы данных, администратор является пользователем с UserType = "Администратор". Согласование этих подходов мне кажется трудным, и поэтому я использую наследование только с непостоянными объектами.
Что не так с моим мышлением? Почему наследование является таким часто прославляемым аспектом ОО, если оно имеет эти врожденные несовместимости с традиционными реляционными структурами? Или я не правильно сопоставляю наследование с реляционными данными? Есть ли какое-то руководство, которое могло бы прояснить это для меня?
Извините за бессвязный вопрос и заранее спасибо за ваши ответы. Если вы включите код в свой ответ, C# - мой "родной язык".
11 ответов
Это обычно называют несоответствием объектно-реляционного импеданса:
Наследование схемы. Большинство реляционных баз данных не поддерживают наследование схемы. Хотя такую функцию теоретически можно добавить для уменьшения конфликта с ООП, сторонники реляционных отношений с меньшей вероятностью будут верить в полезность иерархических таксономий и подтипов, поскольку они склонны рассматривать таксономии или системы классификации на основе множеств как более мощные и гибкие. чем деревья. Сторонники ОО указывают, что модели наследования / подтипирования не обязательно должны быть ограничены деревьями (хотя это ограничение во многих популярных языках ОО, таких как Java), но не-древовидные ОО-решения рассматриваются как более трудные для формулировки, чем вариационные решения на основе множеств. методы управления по теме предпочтительнее реляционных. По крайней мере, они отличаются от методов, обычно используемых в реляционной алгебре.
Смотрите также: Agile Data, C2 Wiki
Я бы сказал, что модель наследования в этом вопросе имеет недостатки. Это слишком буквально или основано на реальном мире. Да, можно утверждать, что я являюсь администратором в реальном мире, и поэтому администратор - это человек. Тем не менее, объектный дизайн и наследование должны основываться больше на выраженном и общем поведении в пространстве кода. Я бы пошел больше по пути, по которому у пользователя есть роль. Администратор - это роль или экземпляр роли, для которой задано определенное состояние. Пользователь не является персоной (например, для вашей пакетной работы может потребоваться учетная запись пользователя).
Я рекомендую почитать объектное мышление Дэвида Уэста для хорошего знакомства с предметным дизайном. Однако он не охватывает несоответствие отношений объектов, но люди уже дали много ссылок на ресурсы по этой теме.
Разрыв между реляционной парадигмой и ОО-парадигмой часто обсуждается.
По сути, чтобы обеспечить отображение между СУБД и ОО, вы должны пожертвовать некоторыми возможностями обеих систем. Вы должны решить, с какой стороны ваш компромисс будет более взвешенным.
Обе парадигмы очень мощные и полезные. Но попытка плавно отобразить их - нерешенная проблема.
Вы должны прочитать Шаблоны Архитектуры Приложения Предприятия. Он покажет вам, как шаблоны наследования могут и должны быть выражены реляционными структурами.
Важно помнить, что наследование - это концептуальное моделирование. Реляционные структуры и ОО-код являются всего лишь материализацией этих концептуальных моделей, и их не следует рассматривать как все и заканчивать всей объектной ориентацией.
Здесь есть учебник по этому типу вещей.
Есть много способов выразить такие отношения в C#. Реляционные базы данных просто более ограничены (что может быть как преимуществом, так и недостатком). Когда вы разрабатываете иерархию объектов, которая будет сохраняться в базе данных, я обнаружил, что обычно сначала проще начать со схемы базы данных, поскольку практически любую схему базы данных можно легко сопоставить с отношениями объектов, тогда как обратное не обязательно дело.
В этом конкретном случае вы можете смоделировать администратора с композицией. Ваша таблица "Администраторы" будет содержать любое дополнительное состояние администратора плюс ключ соответствующего пользователя. Пользователи FK также будут вашими администраторами ПК.
Существуют различные виды наследования. Разработчики могут думать с точки зрения интерфейсов и поведения.
В вашем мире, что значит иметь "userType" администратора?
Семантика, на которую вы, вероятно, намекаете, заключается в том, что некоторый код где-то видит этот тип пользователя и разрешает действия для пользователей с этим типом. Так, может быть, администратор может создать других пользователей?
В этом случае разработчик может иметь класс User
class User() { viewData(){ ...} ; signReport() {...} }
и класс Adminstrator с дополнительной возможностью
class Administrator() extends User { createUser() {...}; approvePurchase() {...} }
Объект типа Администратор может использоваться везде, где может использовать Пользователь. Это полиморфное поведение может быть полезным при реализации. Теперь ваша база данных вполне правдоподобно поддерживает этот случай. Тем не менее, что вы будете делать, когда администраторам понадобятся немного дополнительных данных для выполнения их конкретной задачи? Например, параметр purchaseApproval() имеет ограничение до определенного предела, этот предел нам нужен как новое поле, но он применяется только к администраторам.
Я считаю, что поведенческие аспекты, подразумеваемые вашей "типовой" концепцией, нередко связаны с дополнительными данными.
Почему наследование является таким часто прославляемым аспектом ОО, если оно имеет эти врожденные несовместимости с традиционными реляционными структурами?
Это любопытная цитата - почему вы говорите, что реляционные структуры являются "традиционными"? По своей природе они являются нормой в СУБД, но я видел очень мало реляционных библиотек в контексте языка без БД.
Причина, по которой ОО пользуется популярностью, заключается в том, что она значительно улучшилась по сравнению с доминирующей процедурной моделью. Используя наследование, код можно сделать более надежным (с помощью проверки типов), более легко изменяемым (с помощью специализации методов) и более тестируемым (с помощью простого переопределения поведения). По сравнению с процедурной моделью ОО гораздо проще разрабатывать качественное программное обеспечение.
Конечно, существует сложность в сопоставлении ОО и реляционных моделей. Это называется "объектно-реляционное несоответствие" и было названо "Вьетнам компьютерных наук". Существуют различные стратегии хранения ОО-данных в реляционной базе данных, но ни одна из них не является идеальной - наиболее популярными в современном использовании являются платформы, основанные на шаблоне активной записи.
Да, наследование, вероятно, не тот инструмент, когда вы отображаете базу данных и из нее.
Наследование гораздо более полезно при создании каркасов, в которых у вас есть разные типы объектов, которые ведут себя по-разному, но при этом у них есть общие части.
Например, у вас могут быть разные "сообщения", передаваемые между одним сервером и другим. Каждое сообщение имеет свою собственную логику, поэтому вам нужны разные классы (чтобы избежать огромного оператора switch()), но есть общие части, такие как тот факт, что каждое сообщение должно знать, как сериализовать / десериализовать себя в поток (который является Метод все подклассы сообщения должны переопределить). Кроме того, наличие всех сообщений, унаследованных от Message, позволит вам получить список, а также переходить по одному и вызывать их метод Serialize, например.
Но если все, что вы делаете, - это типичная бизнес-логика / логика БД, то, скорее всего, вам помешает наследование.
Ваш конкретный пример того, как Admininstrator является пользователем с типом пользователя "Administrator", является ярким примером шаблона "Single Table Inheritance". Это реализовано в некоторых основных ORM. В частности "Rails ActiveRecord" и Hibernate.
Нормализованные схемы реляционных баз данных действительно не поддерживают полиморфизм, если вы не выходите за рамки того, что обычно считается "лучшими практиками" в мире администраторов баз данных. Это не новая проблема, и сама проблема была решена тысячу раз несколькими различными способами.
Настоящая проблема возникает, когда вы начинаете работать с данными - если вы работаете с наборами данных, у вас по-прежнему будут возникать проблемы, пытаясь реализовать какой-либо полиморфизм. Однако, если вы сопоставляете набор сущностей домена с вашей реляционной моделью, вы обнаружите, что существует множество инструментов, которые помогут вам преодолеть ограничения схемы реляционной базы данных.
Поскольку вы являетесь разработчиком на C#, вам, вероятно, стоит начать с изучения следующих 2 проектов, один из которых поставляется с последним пакетом обновления.NET.
ADO.NET Entity Framework:
http://msdn.microsoft.com/en-us/library/bb386876.aspx
NHibernate: