Програмування до інтерфейсів, орієнтованих на дані


9

Є частина нашої кодової бази, написана у такому стилі:

// IScheduledTask.cs
public interface IScheduledTask
{
    string TaskName { get; set; }
    int TaskPriority { get; set; }
    List<IScheduledTask> Subtasks { get; set; }
    // ... several more properties in this vein
}

// ScheduledTaskImpl.cs
public class ScheduledTaskImpl : IScheduledTask
{
    public string TaskName { get; set; }
    public int TaskPriority { get; set; }
    public List<IScheduledTask> Subtasks { get; set; }
    // ... several more properties in this vein, 
    // perhaps a constructor or two for convenience.
}

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


1
Однією з причин, що я це зробив, є сумісність із COM, але це, мабуть, не є вашою причиною.
Майк

@Mike Цікаво, що я ніколи не використовував COM, і він тут не використовується. Я запитаю автора цього розділу коду, чи планував він використовувати COM або що-небудь.
проходити

Я гадаю, що він очікує, що принаймні одне з цих властивостей не буде автоматичним у відносно недалекому майбутньому, і виписувати цю котельну плиту на початку - це звичка, до якої він потрапив, щоб заощадити трохи пізніше, хоча я не хлопець C #, тому це все, що я можу сказати.
Іксрек

6
IMHO - це надмірна одержимість та неправильне застосування коду до інтерфейсів, які не реалізуються . Ключовою інформацією є єдине виконання . Суть інтерфейсів - це поліморфізм, але лише клас властивостей є поліморфним у певному сенсі, просто маючи різні значення. Навіть з поведінкою - методами - немає сенсу їй давати єдину реалізацію. Ця дурниця є всією нашою кодовою базою і в кращому випадку заважає обслуговуванню. Я витрачаю занадто багато часу на запитання, чому, що і де. Чому вони це зробили, якого дизайну я не бачу і де інші реалізації?
radarbob

2
Більшість попередніх коментарів стосуються єдиного втілення "кодового запаху" передчасної абстракції; однак тут також є анемічна модель домену "кодовий запах", дивіться: martinfowler.com/bliki/AnemicDomainModel.html
Ерік Еддт

Відповіді:


5

Ось два мої центи:

  • Ми не впевнені, що у DTO ніколи не буде принаймні трохи поведінки. Тож для мене є предмети, які можуть чи не можуть мати поведінку в майбутньому.
  • Однією з можливих причин того, так багато класів єдиною реалізації є відсутністю дизайну , наприклад , НЕ бачити , що ScheduledTask, ScheduledJob, ScheduledEvent, ScheduledInspectionі т.д., має бути тільки один відокремлені Schedulableінтерфейс робить будь-який реалізатор запланованим.
  • Створення інтерфейсів спочатку - дуже хороша практика, вона дає вам уявлення про те, що вам потрібно. Багато інтерфейсів починаються з того, що вони взагалі не мають реалізації. Потім хтось пише одну реалізацію, і у неї є така. Стан єдиної реалізації є тимчасовим, якщо ви уникаєте того, що я згадую у другому пункті. Як ви заздалегідь знаєте, що якийсь інтерфейс ніколи не матиме секунди третьої реалізації?
  • Ім'я, яке ми обираємо для продуманого інтерфейсу, має тенденцію не змінюватись у майбутньому, тому залежність від цього інтерфейсу не вплине. З іншого боку, конкретний клас схильний перейменовуватися, коли щось важливе в способі його реалізації змінюється, наприклад, конкретний клас, названий TaxSheetможе змінитися, SessionAwareTaxSheetоскільки був зроблений значний капітальний ремонт, але інтерфейс ITaxSheet, ймовірно, не буде перейменований так легко.

Нижня лінія:

  • Гарні дизайнерські практики застосовуються також до DTO.
  • DTO може бути додано трохи поведінки в дорозі.
  • Кожен інтерфейс починається лише з однієї реалізації.
  • З іншого боку, якщо у вас занадто багато комбінацій одного інтерфейсу та одного класу, може бути брак дизайну, на який слід звернути увагу. Ваша зайнятість може бути виправданою .

4
Я підтримав вашу відповідь, але ваша друга куля передбачає, що всі класи повинні автоматично мати відповідний інтерфейс, положення, з яким я ніколи не погоджувався. Запис інтерфейсів з випадковістю, що у вас може бути друга реалізація, просто спричиняє поширення інтерфейсу та YAGNI.
Роберт Харві

1

Особлива проблема, яку я бачив із DTO, які використовують інтерфейси, полягає в тому, що це дозволяє:

public interface ISomeDTO { string SomeProperty { get; set; }}

public class SomeDTO : ISomeDTO
{
    public string SomeProperty { get; set; }
    string ISomeDTO.SomeProperty { get { /* different behavior */ } set { SomeProperty = value; } }
}

Я бачив, що ця модель застосовується як швидкий, брудний злом для реалізації критичної поведінки. Це призводить до коду, який може мати дуже заплутану поведінку:

SomeDTO a = GetSomeDTO();
ISomeDTO ia = a;
Assert.IsTrue(a.SomeProperty == ia.SomeProperty); // assert fails!

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

DTO не є доменними моделями. Ми не повинні бути стурбовані, якщо ДТО є анемічними. Щоб процитувати обговорення Мартіна Фаулера про анемічну модель домену :

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.