Ответ 1
На вопрос просто ответят, узнав, что наследование моделирует отношение "IS-A", а членство моделирует отношение "HAS-A".
- Сотрудник IS Пользователь
- Сотрудник HAS A userinfo
Какой из них правильный? Это ваш ответ.
Какой дизайн класса лучше и почему?
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;
}
На вопрос просто ответят, узнав, что наследование моделирует отношение "IS-A", а членство моделирует отношение "HAS-A".
Какой из них правильный? Это ваш ответ.
Мне не нравится ни один. Что происходит, когда кто-то является членом и сотрудником?
Задайте себе следующее:
В целом старайтесь моделировать реальность, которую ваша программа имитирует, с ограничениями сложности кода и требуемой эффективности.
Я не думаю, что композиция всегда лучше, чем наследование (как правило, обычно). Если Employee и Member действительно являются Пользователями, и они являются взаимоисключающими, то первый дизайн лучше. Рассмотрим сценарий, в котором вам нужно получить доступ к UserName сотрудника. Используя вторую конструкцию, вы должны:
myEmployee.UserInfo.UserName
что плохо (закон Деметры), поэтому вы бы реорганизовали:
myEmployee.UserName
который требует небольшого метода для Employee делегировать объект User. Все это избегается первой конструкцией.
Хороший вопрос, хотя во избежание отвлекаться по поводу правильного и неправильного я бы подумал о том, чтобы просить плюсы и минусы каждого подхода - я думаю, что вы имели в виду, что лучше или хуже, и почему. Во всяком случае....
Плюсы:
Минусы:
Плюсы:
Минусы:
Списки, подобные этим + упомянутые вопросы Jon Limjap, помогут вам принять решения и начать работу - тогда вы можете найти ответы на правильные ответы;-)
Вы также можете думать о Employee как о роли пользователя (человека). Роль пользователя может измениться во времени (пользователь может стать безработным), или Пользователь может иметь несколько ролей одновременно.
Наследование намного лучше, если существует реальное "отношение, например Apple - Fruit. Но будьте очень осторожны: Circle - Ellipse не является реальным" является "отношением, потому что cirlce имеет меньше" свободы ", чем эллипс (круг является состоянием эллипса) - см.: Проблема эллипса круга.
Реальные вопросы:
Это могут быть три совершенно несвязанных объекта или нет, и это определит, будет ли работать ваш первый или второй дизайн, или если другой совершенно другой дизайн в порядке.
Ни один из них не является хорошим. Слишком много изменчивого состояния. Вы не сможете создать экземпляр класса, который находится в недопустимом или частично инициализированном состоянии.
Тем не менее, второй лучше, потому что он способствует составу над наследованием.
Утверждение вашего требования/спецификации может помочь прийти к "лучшему дизайну".
На данный момент ваш вопрос слишком "интерпретируется для читателя".
Вот сценарий, о котором вы должны подумать:
Композиция (второй пример) предпочтительнее, если один и тот же Пользователь может быть как Сотрудником, так и Участником. Зачем? Потому что для двух экземпляров (Employee и Member), которые представляют одного и того же пользователя, если данные пользователя изменяются, вам не нужно обновлять их в двух местах. Только экземпляр пользователя содержит всю информацию о пользователе, и только он должен быть обновлен. Поскольку классы Employee и Member содержат один и тот же экземпляр пользователя, они автоматически содержат обновленную информацию.
Еще три варианта:
Если класс User
содержит дополнительную информацию как для сотрудников, так и для членов, причем неиспользованные поля пусты (ID
конкретного User
будет указывать, был ли пользователь сотрудником, членом, или что-то еще).
Есть класс User
, который содержит ссылку на ISupplementalInfo
, где ISupplementalInfo
наследуется ISupplementalEmployeeInfo
, ISupplementalMemberInfo
и т.д. Код, применимый ко всем пользователям, может работать с User
объекты класса и код, который имел ссылку User
, могли получить доступ к дополнительной информации пользователя, но этот подход не позволит изменить User
, если в будущем потребуются различные комбинации дополнительной информации.
Как указано выше, но класс User
содержит некоторую коллекцию ISupplementalInfo
. Преимущество такого подхода состояло в том, чтобы облегчить добавление свойств пользователю во время выполнения (например, поскольку a Member
получил наем). При использовании предыдущего подхода нужно было бы определить разные классы для разных комбинаций свойств; превращение "члена" в "участника + клиента" потребует от другого кода превращения "служащего" в "сотрудника + клиента". Недостатком последнего подхода является то, что он будет затруднять защиту от избыточных или несогласованных атрибутов (использование чего-то типа Dictionary<Type, ISupplementalInfo>
для хранения дополнительной информации могло бы работать, но казалось бы немного "громоздким" ).
Я бы склонялся к второму подходу, поскольку он позволял будущему расширению лучше, чем прямое наследование. Работа с набором объектов, а не с одним объектом может быть немного обременительной, но этот подход может быть лучше, чем другие, для обработки изменяющихся требований.