#c_sharp #net #ооп #классы #проектирование
Предположим есть следующий класс: public class User { public string FirstName {get;set;} public string LastName {get;set;} } Мне необходимо получить полное имя, я знаю следующие способы как это сделать: 1.Создадим необходимое свойство в классе: public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } } 2.Переопределим ToString() для данного класса: public override string ToString() { return string.Format("{0} {1}", FirstName, LastName); } 3.Создадим метод расширения: public static UserHelpers { public static string FullName(this User obj) { return string.Format("{0} {1}", obj.FirstName, obj.LastName); } } 4.Создадим функцию public string GetFullName() { return string.Format("{0} {1}", FirstName, LastName); } Я понимаю что первые два способа могут быть использованы только при возможности изменять исходный класс. Объясните пожалуйста когда какой способ предпочтительней использовать, плюсы/минусы того или иного способа для дальнейшего сопровождения кода.
Ответы
Ответ 1
Полное имя - свойство пользователя, а то что оно вычислимое, а не вводится вручную - всего лишь удобство\неудобство в использовании. Так что, в плане класса - это его свойство. Если свойство всегда должно быть только вычислимым (с учетом наследования, ага), то можно сделать из свойства метод. ToString для сложных объектов не сильно полезен, хоть в данном случае и похоже на что-то полезное. Экстеншены - только для чужих классов. Иначе за ними потом становится слишком тяжело следить и поддерживать. UPD: для вычислимых свойств можно делать как свойства, так и методы. Я тут больше опираюсь на то, как оно себя ведет в абстрактном случае - может быть вообще в теории установка вручную или это всегда вычисление из свойств сущности. Стоит учитывать, что в свойства обычно больше пары строчек никто не пишет, т.е. как только у вас способ построения увеличивается до 5 строк - это уже явный кандитат на метод. Ну и, стоит учитывать, что свойство должно считаться быстро, иначе это тоже явный метод. Никаких запросов на сервер за информацией свойство явно делать не должно.Ответ 2
С моей точки зрения вычислимое поле, за редким исключением, это внешняя, по отношению к классу, сущность. Поэтому, нахождение такого поля в классе считаю в общем случае не верным. Поясню на примере: Пусть у нас есть класс из вопроса: public class User { public string FirstName {get;set;} public string LastName {get;set;} } Мы добавляем свойство(или метод — не важно): public string FullName => LastName + FirstName; Всё, хорошо, мы молодцы. Выпускаем продукт и забываем об этом. Приходит в проект Иван Петров, и дают ему задание написать некую фичу, где требуется вывод полного имени пользователя. Только в его случае, ему нужно вывести только имя и первую часть фамилию. Он идёт в класс User, смотрит как там сделано, и решает повторить существующее решение(он в чём-то прав,— последовательность очень важна в коде). Поэтому он добавляет ещё одно свойство: public string FullNameWithShortSecond => FirstName + LastName[0]; Думаете на этом проблемы наши исчерпались? О нет, они только начались, ведь продажники продавили продажи нашего чудесного софта в США. Теперь-то деньги польются рекой! Вот только одна незадача — в США порядок First-Second[Name] обратен принятому в РФ. Поэтому мы создаём ещё одно поле, теперь для США: public string FullNameUsa => FirstName + LastName; Стоит ли упоминать, что обычно в классах не 2 свойства, и вариаций их сопоставлений можгут быть десятки и даже сотни. Всё будем свойствами прописывать? Конечно же нет. Мы оставим минимально необходимый интерфейс класса, а вот вычисляемые поля пусть вычисляют те, кому они нужны. Как они будут реализовывать вычисляемые поля? Это не важно, в C#, как мне кажется, самый удобный способ это использование extension methods. В C++ это будут свободные функции. Ну или можно будет создавать декоратор, который будет добавлять вычисляемые свойства. Но это сложнее и не так часто необходимо. Так что, никогда не добавлять вычисляемых полей в изначальный класс? Нет, к этому я не призываю. Я призываю лишь к тому, чтобы сначала рассмотреть насколько это свойство необходимо данному классу, и если у Вас нет чёткого понимания, что это поле должно быть именно здесь, то и не стоит его сюда пихать. Интерфейс класса нужно содержать в чистоте и порядке и не давать ему разрастаться, просто потому, что кажется, что тут поле будет воткнуть проще.Ответ 3
Я бы предложил четвёртый вариант: Создадим метод GetFullName в классе: public string GetFullName() { return string.Format("{0} {1}", FirstName, LastName); } Первый вариант (создать необходимое свойство FullName в классе) не плохой вариант, хотя не так очевидно пользователям вашего класса, что FullName изменяется когда другие свойства изменяются. Как правило, если надо что-то вычислить, лучше сделать метод. Второй вариант (переопределить ToString()) подходит если вы хотите сделать метод, который показывает важную информацию человека, вроде Console.Write("Кто я? Я " + me); Но если хотите создать способ получить именно имя и фамилию, это не подходит: string fullName = person.ToString(); Откуда знаем, что ToString() возвращает то, что хотим, то есть, "Иван Прокофьев", а не "Иван, 28 лет", или "Прокофьев Иван Григоревич, человек №541"? Следующий вариант более выразителен: string fullName = person.GetFullName(); Лучше использовать третий вариант только при необходимости. Если возможно изменять исходный класс, будет проще для всех положить методы в одном классе.
Комментариев нет:
Отправить комментарий