Какой класс дизайна лучше?

Какой дизайн класса лучше и почему?

public class User
{
    public String UserName;
    public String Password;
    public String FirstName;
    public String LastName;
}

public class Employee : User
{
    public String EmployeeId;
    public String EmployeeCode;
    public String DepartmentId;
}

public class Member : User
{
    public String MemberId;
    public String JoinDate;
    public String ExpiryDate;
}

ИЛИ

public class User
{
    public String UserId;
    public String UserName;
    public String Password;
    public String FirstName;
    public String LastName;
}

public class Employee
{
    public User UserInfo;
    public String EmployeeId;
    public String EmployeeCode;
    public String DepartmentId;
}

public class Member
{
    public User UserInfo;
    public String MemberId;
    public String JoinDate;
    public String ExpiryDate;
}

Ответ 1

На вопрос просто ответят, узнав, что наследование моделирует отношение "IS-A", а членство моделирует отношение "HAS-A".

  • Сотрудник IS Пользователь
  • Сотрудник HAS A userinfo

Какой из них правильный? Это ваш ответ.

Ответ 2

Мне не нравится ни один. Что происходит, когда кто-то является членом и сотрудником?

Ответ 3

Задайте себе следующее:

  • Вы хотите смоделировать Employee IS User? Если это так, выберите наследование.
  • Вы хотите, чтобы модель Employee имела информацию о пользователе? Если да, используйте композицию.
  • Существуют ли виртуальные функции между Пользователем (info) и Работником? Если это так, используйте наследование.
  • Может ли сотрудник иметь несколько экземпляров User (info)? Если да, используйте композицию.
  • Имеет ли смысл назначать объект Employee объекту User (info)? Если это так, используйте наследование.

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

Ответ 4

Я не думаю, что композиция всегда лучше, чем наследование (как правило, обычно). Если Employee и Member действительно являются Пользователями, и они являются взаимоисключающими, то первый дизайн лучше. Рассмотрим сценарий, в котором вам нужно получить доступ к UserName сотрудника. Используя вторую конструкцию, вы должны:

myEmployee.UserInfo.UserName

что плохо (закон Деметры), поэтому вы бы реорганизовали:

myEmployee.UserName

который требует небольшого метода для Employee делегировать объект User. Все это избегается первой конструкцией.

Ответ 5

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

Первый подход aka Наследование

Плюсы:

  • Разрешает полиморфное поведение.
  • Изначально простой и удобный.

Минусы:

  • Может стать сложным или неуклюжим с течением времени, если добавлено больше поведения и отношений.

Второй подход aka Состав

Плюсы:

  • Хорошо подходит для не-oop-сценариев, таких как реляционные таблицы, структурированное программирование и т.д.
  • Является простым (если не обязательно удобным) постепенным расширением отношений и поведения.

Минусы:

  • Нет полиморфизма, поэтому менее удобно использовать связанную информацию и поведение.

Списки, подобные этим + упомянутые вопросы Jon Limjap, помогут вам принять решения и начать работу - тогда вы можете найти ответы на правильные ответы;-)

Ответ 6

Вы также можете думать о Employee как о роли пользователя (человека). Роль пользователя может измениться во времени (пользователь может стать безработным), или Пользователь может иметь несколько ролей одновременно.

Наследование намного лучше, если существует реальное "отношение, например Apple - Fruit. Но будьте очень осторожны: Circle - Ellipse не является реальным" является "отношением, потому что cirlce имеет меньше" свободы ", чем эллипс (круг является состоянием эллипса) - см.: Проблема эллипса круга.

Ответ 7

Реальные вопросы:

  • Каковы бизнес-правила и пользовательские истории за пользователем?
  • Каковы бизнес-правила и пользовательские истории за сотрудником?
  • Каковы бизнес-правила и пользовательские истории за членом?

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

Ответ 8

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

Тем не менее, второй лучше, потому что он способствует составу над наследованием.

Ответ 9

Утверждение вашего требования/спецификации может помочь прийти к "лучшему дизайну".
На данный момент ваш вопрос слишком "интерпретируется для читателя".

Ответ 10

Вот сценарий, о котором вы должны подумать:

Композиция (второй пример) предпочтительнее, если один и тот же Пользователь может быть как Сотрудником, так и Участником. Зачем? Потому что для двух экземпляров (Employee и Member), которые представляют одного и того же пользователя, если данные пользователя изменяются, вам не нужно обновлять их в двух местах. Только экземпляр пользователя содержит всю информацию о пользователе, и только он должен быть обновлен. Поскольку классы Employee и Member содержат один и тот же экземпляр пользователя, они автоматически содержат обновленную информацию.

Ответ 11

Еще три варианта:

  • Если класс User содержит дополнительную информацию как для сотрудников, так и для членов, причем неиспользованные поля пусты (ID конкретного User будет указывать, был ли пользователь сотрудником, членом, или что-то еще).

  • Есть класс User, который содержит ссылку на ISupplementalInfo, где ISupplementalInfo наследуется ISupplementalEmployeeInfo, ISupplementalMemberInfo и т.д. Код, применимый ко всем пользователям, может работать с User объекты класса и код, который имел ссылку User, могли получить доступ к дополнительной информации пользователя, но этот подход не позволит изменить User, если в будущем потребуются различные комбинации дополнительной информации.

  • Как указано выше, но класс User содержит некоторую коллекцию ISupplementalInfo. Преимущество такого подхода состояло в том, чтобы облегчить добавление свойств пользователю во время выполнения (например, поскольку a Member получил наем). При использовании предыдущего подхода нужно было бы определить разные классы для разных комбинаций свойств; превращение "члена" в "участника + клиента" потребует от другого кода превращения "служащего" в "сотрудника + клиента". Недостатком последнего подхода является то, что он будет затруднять защиту от избыточных или несогласованных атрибутов (использование чего-то типа Dictionary<Type, ISupplementalInfo> для хранения дополнительной информации могло бы работать, но казалось бы немного "громоздким" ).

Я бы склонялся к второму подходу, поскольку он позволял будущему расширению лучше, чем прямое наследование. Работа с набором объектов, а не с одним объектом может быть немного обременительной, но этот подход может быть лучше, чем другие, для обработки изменяющихся требований.