Це "запах шаблону", щоб у вашу модель включити геттери типу "FullName" або "FormattedPhoneNumber"?


13

Я працюю над програмою ASP.NET MVC, і мені стало звично розміщувати те, що здається корисним та зручним для роботи в моїх класах / моделях.

Наприклад:

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    public string FormattedPhoneNumber
    {
        get { return "(" + PhoneNumber.Substring(0, 3) + ") " + PhoneNumber.Substring(3, 3) + "-" + PhoneNumber.Substring(6); }
    }
}

Мені цікаво, що люди замислюються про FullNameта про них FormattedPhoneNumber.

Вони дуже просто створюють стандартизовані формати даних у всьому додатку, і вони, схоже, економлять багато повторних кодів, але, безумовно, можна стверджувати, що формат даних - це те, що слід обробляти при зіставленні від моделі до моделі перегляду.

Насправді я спочатку застосовував ці формати даних у своєму сервісному шарі, де я робив своє картографування, але це стало тягарем постійно писати формати, а потім застосовувати їх у багатьох різних місцях. Наприклад, я використовую "Повне ім'я" в більшості видах перегляду, і введення чогось подібного в model.FullName = MappingUtilities.GetFullName(entity.FirstName, entity.LastName);усьому світі видалося набагато менш елегантним, ніж просто вводити текст model.FullName = entity.FullName(або, якщо ви використовуєте щось на зразок AutoMapper, потенційно взагалі нічого не вводити).

Отже, де ви проводите лінію, коли справа стосується форматування даних. Чи "добре" робити форматування даних у вашій моделі чи це "запах візерунка"?

Примітка. У моїй моделі, безумовно, немає жодного html. Я використовую html-помічники для цього. Я строго кажу про форматування або комбінування даних (і особливо даних, які часто використовуються).


1
Робити це може бути зручно. Але сподівайтеся і моліться, що вам ніколи не доведеться інтернаціоналізувати цей код.
btilly

@btilly, хороший момент, але я приблизно 99,99% впевнений, що не хочу.
devuxer

Характерно для FullName та PhoneNumber, безумовно. Питання стосується саме тих, оскільки вони мають непослідовні формати в різних культурах, чи @DanM просто підібрав приклади, які не є інтернаціоналізованими для більш загального питання?
Грег Джексон

@Greg Джексон, безумовно, сходи. Як вказував ammoQ, PhoneNumberнапевно, належить до власного класу (який я зараз реалізував). Але FullNameнасправді це мене мотивувало написати питання. Але мені цікаво дізнатися, чи взагалі має сенс розміщувати в моделі форматування / розчісування даних тощо для речей, які застосовуватимуться в додатку. З наведених нижче відповідей здається, що це не є антидіаграмою, але рішення слід приймати обережно.
devuxer

Майте на увазі, що це специфічне форматування повного імені також може не бути інтернаціоналізованим. Наприклад, у Східній Азії порядок імен є зворотним, як це є у західному світі. Вам справді потрібно це чітко впоратися? Можливо, ні, але майте на увазі, що існує багато складних речей, з якими ви зіткнетесь під час форматування даних.
Грег Джексон

Відповіді:


9

У вашому прикладі мені подобається FullNamegetter (з усіх наведених вами причин), але мені не подобається Getter FormattedPhoneNumber. Причина полягає в тому, що це, мабуть, не так просто (коли у вас є міжнародні телефонні номери тощо), і якщо ви розмістите логіку формування формату телефонних номерів методом Member, швидше за все, вам знадобиться зробити рефакторинг (або скопіювати вставку обережно ), як тільки ви потрібен відформатований номер телефону Institution, і Vendorт.п. теж.

EDIT: IMO, краще було б мати PhoneNumberклас з Formattedгеттером.


+1 і спасибі Але що робити, якщо я фактично ставлю код форматування свого номера телефону методом розширення? Тоді будь-яка модель могла б використовувати її, і не було б рефакторингу чи копіювання / вставлення. Це рішення все ще буде набагато менш повторюваним, ніж застосування форматера до кожного номера телефону, який відображається в кожному огляді.
devuxer

3
Використання методу розширення для цього було б швидким шляхом до антифункціонування "функціонального розкладання". Використовуючи метод розширення (для Stringкласу, я припускаю), ви "навчаєте" Stringклас форматувати телефонні номери. Чи справді обов'язок Stringкласу знати про телефонні номери? Я не думаю, що так. Використовувані так, методи розширення - це синтаксичний цукор, щоб вийшло те, що явно не орієнтоване на об’єкт, виглядало так, як було.
користувач281377

1
Гаразд, забудь, я сказав метод розширення. Притворіться, що я сказав, що утилітний метод або клас форматування. Я просто кажу, що рефакторинг / копіювання вставляти не потрібно, незалежно від того, чи є у мене модель моделювання чи форматування десь в іншому місці.
devuxer

1
І мені подобається ідея PhoneNumberкласу. Я все одно планував це робити, тому що також маю PhoneTypeвласність.
devuxer

Мені не подобається ідея мати PhoneNumberклас екземпляра, оскільки дані є вихідними string. Швидше, це повинен бути статичний клас з такими методами public static string Format(string phoneNumber, PhoneNumberStyle style).
Містер Андерсон

5

Те, що потрібно враховувати при написанні коду: чи правильно? Чи читається? Це ефективно? Це можна ремонтувати? Я б заперечив, як @btilly зазначав, що це неможливо здійснити завдяки специфічному для культури форматуванню, але питання, здається, є більш загальним, що це.

Використання таких аксесуарів робить ваш код більш читабельним і, залежно від способу його використання, може зробити інші частини вашого коду більш чистими. На мою думку, це зовсім не пахне. Він би почав пахнути, якби у вас були аксесуари для форматування для будь-якого виду рядка, який ви хочете надрукувати ( public string FirstLastName; public string FullName; public string FullNameWithMiddleInitial; public string PhoneNumberWithAreaCode; public string PhoneNumberWithoutAreaCode; public string PhoneNumberWithCountryCode;тощо)

Або, кажучи іншим способом, використання шаблону не означає, що ваш код має "запах візерунка". Вам потрібно зловживати ним, якщо ви хочете заробити цей атрибут.


Спасибі, Грег. +1. Я погоджуюсь з вами щодо розміщення кожної комбінації. Я справді просто намагаюся придумати найчистіший спосіб стандартизувати перегляд даних.
devuxer

3

Порушує принцип єдиної відповідальності. Чому б не зробити клас номера телефону тощо ...?


Гаразд, я фактично згоден з цим (див. Дискусію під відповіддю ammoQ), але чи варто також робити FullNameклас?
devuxer

Так, слід, але слід виправити написання з "FullName" на "FoolName". А може бути, "PersonalName", оскільки це ім'я людини, а не повне.
Кевін Клайн

1
Дійсно? Якщо не очікується, що даний клас зросте, тільки що саме з ним не так? Навіть якщо вона все-таки зростає, наскільки важко було б переоцінити її?
Робота

@DanM: Тоді це те, що ви просите, тобто попросіть їх ввести своє повне юридичне ім’я. Якщо ви сортуєте за першим іменем, ви дійсно сортуєте за першою літерою (потім другою тощо) першого імені (потім наступною, то так далі), тож імена будуть сортувати однакові незалежно.
Метт Еллен


1

Для вашого прикладу, я не вважаю це занадто великою угодою для використання конкретних форматів. Це одна-дві, і всі частини програми використовують однаковий формат.

Там, де це рішення почало б руйнуватися, це коли у вас є одні і ті ж дані, що збираються в декілька різних місць, де потрібні різні формати .

Якби це сталося, я б спокусився Memberповернути клас до:

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }  
}

А потім зробіть різні адаптери для кожної цілі. Наприклад, припустимо, що інформація була потрібна у форматі CSV:

public static class CSVMemberAdapter
{
    public static string ToCSV(this Member mbr)
    {
         return mbr.Id + "," + mbr.LastName + "," + mbr.FirstName, "," mbr.PhoneNumber;
    }
}

Завжди припускайте, що ви санітували дані, щоб у рядках не було коми тощо.

Адаптер не повинен бути методом розширення, але в цьому випадку, мабуть, він підходить.


Минув час, коли я написав C #, але, безумовно, існують класи серіалізації, які можуть впоратися з цим, а не втомливо писати такі методи, як toCSV знову і знову і знову і знову і знову і знову і знову і знову і знову і знову і знову і знову і знову і знову і знову ...
Кевін Клайн

@kevin cline: Це залежить від того, що потрібно для кожної раковини. Якщо все, що їм потрібно, це серіалізований XML, добре. Багато систем цього не роблять. Якщо це доводиться робити overстільки разів, то з дизайном щось не так.
Пітер К.

як правило, було б багато класів для серіалізації. Слід створити єдиний CSV або інший серіалізатор, який міг би обробляти більшість класів за допомогою відображення, а не кодувати їх вручну, як ваш приклад.
Кевін Клайн

@kevin cline: Погоджуйся! Я просто писав щось дуже конкретне для поставленого питання. Конкретні, прості приклади, як правило, пояснюють речі краще.
Пітер К.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.